Revision 2cdaf225

b/Makefile.am
1358 1358
	$(PEP8) --ignore='$(PEP8_IGNORE)' --exclude='$(PEP8_EXCLUDE)' \
1359 1359
		--repeat $(pep8_python_code)
1360 1360

  
1361
# FIXME: remove ignore "Use void" when GHC 6.x is deprecated
1361 1362
.PHONY: hlint
1362 1363
hlint: $(HS_BUILT_SRCS) htools/lint-hints.hs
1363 1364
	@test -n "$(HLINT)" || { echo 'hlint' not found during configure; exit 1; }
......
1367 1368
	  --ignore "Use comparing" \
1368 1369
	  --ignore "Use on" \
1369 1370
	  --ignore "Reduce duplication" \
1371
	  --ignore "Use &&&" \
1372
	  --ignore "Use void" \
1370 1373
	  --hint htools/lint-hints \
1371 1374
	  $(filter-out htools/Ganeti/THH.hs,$(HS_LIB_SRCS))
1372 1375

  
b/htools/Ganeti/Confd.hs
89 89
-- converts them to strings anyway, as they're used as dict-keys.
90 90

  
91 91
$(buildObject "ConfdReqQ" "confdReqQ"
92
  [ renameField "Ip" $
92
  [ renameField "Ip" .
93 93
                optionalField $ simpleField C.confdReqqIp [t| String   |]
94
  , renameField "IpList" $
94
  , renameField "IpList" .
95 95
                defaultField [| [] |] $
96 96
                simpleField C.confdReqqIplist [t| [String] |]
97
  , renameField "Link" $ optionalField $
97
  , renameField "Link" . optionalField $
98 98
                simpleField C.confdReqqLink [t| String   |]
99
  , renameField "Fields" $ defaultField [| [] |] $
99
  , renameField "Fields" . defaultField [| [] |] $
100 100
                simpleField C.confdReqqFields [t| [ConfdReqField] |]
101 101
  ])
102 102

  
b/htools/Ganeti/Confd/Server.hs
31 31

  
32 32
import Control.Concurrent
33 33
import Control.Exception
34
import Control.Monad (forever, liftM)
34
import Control.Monad (forever, liftM, when)
35 35
import qualified Data.ByteString as B
36 36
import Data.IORef
37 37
import Data.List
38 38
import qualified Data.Map as M
39
import Data.Maybe (fromMaybe)
39 40
import qualified Network.Socket as S
40 41
import Prelude hiding (catch)
41 42
import System.Posix.Files
......
217 218
buildResponse cdata (ConfdRequest { confdRqType = ReqNodePipByInstPip
218 219
                                  , confdRqQuery = DictQuery query}) =
219 220
  let (cfg, linkipmap) = cdata
220
      link = maybe (getDefaultNicLink cfg) id (confdReqQLink query)
221
      link = fromMaybe (getDefaultNicLink cfg) (confdReqQLink query)
221 222
  in case confdReqQIp query of
222 223
       Just ip -> return $ getNodePipByInstanceIp cfg linkipmap link ip
223 224
       Nothing -> return (ReplyStatusOk,
......
333 334
-- | Wrapper over 'buildFileStatus'. This reads the data from the
334 335
-- filesystem and then builds our cache structure.
335 336
getFStat :: FilePath -> IO FStat
336
getFStat p = getFileStatus p >>= (return . buildFileStatus)
337
getFStat p = liftM buildFileStatus (getFileStatus p)
337 338

  
338 339
-- | Check if the file needs reloading
339 340
needsReload :: FStat -> FilePath -> IO (Maybe FStat)
......
389 390
onReloadTimer :: IO Bool -> FilePath -> CRef -> MVar ServerState -> IO ()
390 391
onReloadTimer inotiaction path cref state = do
391 392
  continue <- modifyMVar state (onReloadInner inotiaction path cref)
392
  if continue
393
    then do
394
      threadDelay configReloadRatelimit
395
      onReloadTimer inotiaction path cref state
396
    else -- the inotify watch has been re-established, we can exit
397
      return ()
393
  when continue $
394
    do threadDelay configReloadRatelimit
395
       onReloadTimer inotiaction path cref state
396
  -- the inotify watch has been re-established, we can exit
398 397

  
399 398
-- | Inner onReload handler.
400 399
--
......
425 424
                   _            -> True
426 425
  return (state' { reloadModel = newmode }, continue)
427 426

  
427
-- the following hint is because hlint doesn't understand our const
428
-- (return False) is so that we can give a signature to 'e'
429
{-# ANN addNotifier "HLint: ignore Evaluate" #-}
428 430
-- | Setup inotify watcher.
429 431
--
430 432
-- This tries to setup the watch descriptor; in case of any IO errors,
b/htools/Ganeti/Config.hs
37 37
    , instNodes
38 38
    ) where
39 39

  
40
import Control.Monad (liftM)
40 41
import Data.List (foldl')
41 42
import qualified Data.Map as M
42 43
import qualified Data.Set as S
......
134 135
-- | Looks up an instance's primary node.
135 136
getInstPrimaryNode :: ConfigData -> String -> Result Node
136 137
getInstPrimaryNode cfg name =
137
  getInstance cfg name >>= return . instPrimaryNode >>= getNode cfg
138
  liftM instPrimaryNode (getInstance cfg name) >>= getNode cfg
138 139

  
139 140
-- | Filters DRBD minors for a given node.
140 141
getDrbdMinorsForNode :: String -> Disk -> [(Int, String)]
b/htools/Ganeti/Daemon.hs
314 314

  
315 315
  when (optShowHelp opts) $ do
316 316
    putStr $ usageHelp progname options
317
    exitWith ExitSuccess
317
    exitSuccess
318 318
  when (optShowVer opts) $ do
319 319
    printf "%s %s\ncompiled with %s %s\nrunning on %s %s\n"
320 320
           progname Version.version
321 321
           compilerName (Data.Version.showVersion compilerVersion)
322 322
           os arch :: IO ()
323
    exitWith ExitSuccess
323
    exitSuccess
324 324

  
325 325
  exitUnless (null args) "This program doesn't take any arguments"
326 326

  
b/htools/Ganeti/HTools/Cluster.hs
931 931
    let no_nodes = Left "no nodes available"
932 932
        node_pairs = [(p,s) | p <- avail_nodes, s <- avail_nodes, p /= s]
933 933
    (nl', il', ops, _) <-
934
        annotateResult "Can't find any good nodes for relocation" $
934
        annotateResult "Can't find any good nodes for relocation" .
935 935
        eitherToResult $
936 936
        foldl'
937 937
        (\accu nodes -> case evacDrbdAllInner nl il inst gdx nodes of
......
974 974
             MirrorNone -> Bad "Can't relocate/evacuate non-mirrored instances"
975 975
             MirrorInternal -> Ok ReplaceSecondary
976 976
             MirrorExternal -> Ok FailoverToAny
977
  (nl', inst', _, ndx) <- annotateResult "Can't find any good node" $
977
  (nl', inst', _, ndx) <- annotateResult "Can't find any good node" .
978 978
                          eitherToResult $
979 979
                          foldl' (evacOneNodeInner nl inst gdx op_fn)
980 980
                          (Left "no nodes available") avail_nodes
......
1046 1046
    if Node.offline primary
1047 1047
      then do
1048 1048
        (nl', inst', _, _) <-
1049
          annotateResult "Failing over to the secondary" $
1049
          annotateResult "Failing over to the secondary" .
1050 1050
          opToResult $ applyMove nl inst Failover
1051 1051
        return (nl', inst', [Failover])
1052 1052
      else return (nl, inst, [])
......
1056 1056
  -- we now need to execute a replace secondary to the future
1057 1057
  -- primary node
1058 1058
  (nl2, inst2, _, _) <-
1059
    annotateResult "Changing secondary to new primary" $
1059
    annotateResult "Changing secondary to new primary" .
1060 1060
    opToResult $
1061 1061
    applyMove nl1 inst1 o1
1062 1062
  let ops2 = o1:ops1
1063 1063
  -- we now execute another failover, the primary stays fixed now
1064
  (nl3, inst3, _, _) <- annotateResult "Failing over to new primary" $
1064
  (nl3, inst3, _, _) <- annotateResult "Failing over to new primary" .
1065 1065
                        opToResult $ applyMove nl2 inst2 o2
1066 1066
  let ops3 = o2:ops2
1067 1067
  -- and finally another replace secondary, to the final secondary
1068 1068
  (nl4, inst4, _, _) <-
1069
    annotateResult "Changing secondary to final secondary" $
1069
    annotateResult "Changing secondary to final secondary" .
1070 1070
    opToResult $
1071 1071
    applyMove nl3 inst3 o3
1072 1072
  let ops4 = o3:ops3
b/htools/Ganeti/HTools/ExtLoader.hs
55 55

  
56 56
-- | Error beautifier.
57 57
wrapIO :: IO (Result a) -> IO (Result a)
58
wrapIO = flip catch (\e -> return . Bad . show $ (e::IOException))
58
wrapIO = handle (\e -> return . Bad . show $ (e::IOException))
59 59

  
60 60
-- | Parses a user-supplied utilisation string.
61 61
parseUtilisation :: String -> Result (String, DynUtil)
......
102 102
  input_data <-
103 103
    case () of
104 104
      _ | setRapi -> wrapIO $ Rapi.loadData mhost
105
        | setLuxi -> wrapIO $ Luxi.loadData $ fromJust lsock
105
        | setLuxi -> wrapIO . Luxi.loadData $ fromJust lsock
106 106
        | setSim -> Simu.loadData simdata
107
        | setFile -> wrapIO $ Text.loadData $ fromJust tfile
108
        | setIAllocSrc -> wrapIO $ IAlloc.loadData $ fromJust iallocsrc
107
        | setFile -> wrapIO . Text.loadData $ fromJust tfile
108
        | setIAllocSrc -> wrapIO . IAlloc.loadData $ fromJust iallocsrc
109 109
        | otherwise -> return $ Bad "No backend selected! Exiting."
110 110

  
111 111
  let ldresult = input_data >>= mergeData util_data exTags selInsts exInsts
b/htools/Ganeti/HTools/IAlloc.hs
276 276
      MirrorNone -> fail "Can't relocate non-mirrored instances"
277 277
      MirrorInternal -> return (sorig, "secondary", ChangeSecondary)
278 278
      MirrorExternal -> return (porig, "primary", ChangePrimary)
279
  when (exndx /= [exp_node]) $
279
  when (exndx /= [exp_node]) .
280 280
       -- FIXME: we can't use the excluded nodes here; the logic is
281 281
       -- already _but only partially_ implemented in tryNodeEvac...
282 282
       fail $ "Unsupported request: excluded nodes not equal to\
b/htools/Ganeti/HTools/Program/Hail.hs
75 75

  
76 76
  let Request rq cdata = request
77 77

  
78
  when (verbose > 1) $
78
  when (verbose > 1) .
79 79
       hPutStrLn stderr $ "Received request: " ++ show rq
80 80

  
81
  when (verbose > 2) $
81
  when (verbose > 2) .
82 82
       hPutStrLn stderr $ "Received cluster data: " ++ show cdata
83 83

  
84 84
  maybePrintNodes shownodes "Initial cluster"
b/htools/Ganeti/HTools/Program/Hbal.hs
297 297
  -- nothing to do on an empty cluster
298 298
  when (Container.null il) $ do
299 299
         printf "Cluster is empty, exiting.\n"::IO ()
300
         exitWith ExitSuccess
300
         exitSuccess
301 301

  
302 302
  -- hbal doesn't currently handle split clusters
303 303
  let split_insts = Cluster.findSplitInstances nl il
......
328 328
             "Initial check done: %d bad nodes, %d bad instances.\n"
329 329
             (length bad_nodes) (length bad_instances)
330 330

  
331
  when (not (null bad_nodes)) $
331
  unless (null bad_nodes) $
332 332
         putStrLn "Cluster is not N+1 happy, continuing but no guarantee \
333 333
                  \that the cluster will end N+1 happy."
334 334

  
......
340 340
         printf "Cluster is already well balanced (initial score %.6g,\n\
341 341
                \minimum score %.6g).\nNothing to do, exiting\n"
342 342
                ini_cv min_cv:: IO ()
343
         exitWith ExitSuccess
343
         exitSuccess
344 344

  
345 345
-- | Main function.
346 346
main :: Options -> [String] -> IO ()
......
411 411

  
412 412
  let cmd_jobs = Cluster.splitJobs cmd_strs
413 413

  
414
  when (isJust $ optShowCmds opts) $
414
  when (isJust $ optShowCmds opts) .
415 415
       saveBalanceCommands opts $ Cluster.formatCmds cmd_jobs
416 416

  
417 417
  maybeSaveData (optSaveCluster opts) "balanced" "after balancing"
b/htools/Ganeti/HTools/Program/Hcheck.hs
188 188
  unless (verbose == 0) $ do
189 189
    putStrLn ""
190 190
    putStr prefix
191
    mapM_ (\(a,b) -> printf "    %s: %s\n" a b) (zip descr values)
191
    mapM_ (uncurry (printf "    %s: %s\n")) (zip descr values)
192 192

  
193 193
-- | Extract name or idx from group.
194 194
extractGroupData :: Bool -> Group.Group -> String
......
230 230
perGroupChecks gl (gidx, (nl, il)) =
231 231
  let grp = Container.find gidx gl
232 232
      offnl = filter Node.offline (Container.elems nl)
233
      n1violated = length $ fst $ Cluster.computeBadItems nl il
233
      n1violated = length . fst $ Cluster.computeBadItems nl il
234 234
      conflicttags = length $ filter (>0)
235 235
                     (map Node.conflictingPrimaries (Container.elems nl))
236 236
      offline_pri = sum . map length $ map Node.pList offnl
......
335 335

  
336 336
  printFinalHTC machineread
337 337

  
338
  unless exitOK $ exitWith $ ExitFailure 1
338
  unless exitOK . exitWith $ ExitFailure 1
b/htools/Ganeti/HTools/Program/Hscan.hs
118 118
      oname = odir </> fixSlash name
119 119
  putStrLn $ printCluster nl il
120 120
  hFlush stdout
121
  when (isJust shownodes) $
121
  when (isJust shownodes) .
122 122
       putStr $ Cluster.printNodes nl (fromJust shownodes)
123 123
  writeFile (oname <.> "data") (serializeCluster cdata)
124 124
  return True
......
142 142
         let name = local
143 143
         input_data <- Luxi.loadData lsock
144 144
         result <- writeData nlen name opts input_data
145
         unless result $ exitWith $ ExitFailure 2
145
         unless result . exitWith $ ExitFailure 2
146 146

  
147 147
  results <- mapM (\name -> Rapi.loadData name >>= writeData nlen name opts)
148 148
             clusters
b/htools/Ganeti/HTools/QC.hs
1426 1426
  case genClusterAlloc count node inst of
1427 1427
    Types.Bad msg -> failTest msg
1428 1428
    Types.Ok (nl, il, inst') ->
1429
      conjoin $ map (\mode -> check_EvacMode defGroup inst' $
1429
      conjoin . map (\mode -> check_EvacMode defGroup inst' $
1430 1430
                              Cluster.tryNodeEvac defGroupList nl il mode
1431 1431
                                [Instance.idx inst']) .
1432 1432
                              evacModeOptions .
......
1894 1894
  -- ready
1895 1895
  server <- run $ Luxi.getServer fpath
1896 1896
  -- fork the server responder
1897
  _ <- run $ forkIO $
1897
  _ <- run . forkIO $
1898 1898
    bracket
1899 1899
      (Luxi.acceptClient server)
1900 1900
      (\c -> Luxi.closeClient c >> removeFile fpath)
b/htools/Ganeti/HTools/Rapi.hs
85 85
-- | Helper to convert I/O errors in 'Bad' values.
86 86
ioErrToResult :: IO a -> IO (Result a)
87 87
ioErrToResult ioaction =
88
  catch (ioaction >>= return . Ok)
88
  catch (liftM Ok ioaction)
89 89
        (\e -> return . Bad . show $ (e::IOException))
90 90

  
91 91
-- | Append the default port if not passed in.
......
203 203
readDataFile:: String -- ^ Path to the directory containing the files
204 204
             -> IO (Result String, Result String, Result String, Result String)
205 205
readDataFile path = do
206
  group_body <- ioErrToResult $ readFile $ path </> "groups.json"
207
  node_body <- ioErrToResult $ readFile $ path </> "nodes.json"
208
  inst_body <- ioErrToResult $ readFile $ path </> "instances.json"
209
  info_body <- ioErrToResult $ readFile $ path </> "info.json"
206
  group_body <- ioErrToResult . readFile $ path </> "groups.json"
207
  node_body <- ioErrToResult . readFile $ path </> "nodes.json"
208
  inst_body <- ioErrToResult . readFile $ path </> "instances.json"
209
  info_body <- ioErrToResult . readFile $ path </> "info.json"
210 210
  return (group_body, node_body, inst_body, info_body)
211 211

  
212 212
-- | Loads data via either 'readDataFile' or 'readDataHttp'.
b/htools/Ganeti/HTools/Simu.hs
30 30
  , parseData
31 31
  ) where
32 32

  
33
import Control.Monad (mplus)
33
import Control.Monad (mplus, zipWithM)
34 34
import Text.Printf (printf)
35 35

  
36 36
import Ganeti.HTools.Utils
......
90 90
parseData :: [String] -- ^ Cluster description in text format
91 91
          -> Result ClusterData
92 92
parseData ndata = do
93
  grpNodeData <- mapM (uncurry createGroup) $ zip [1..] ndata
93
  grpNodeData <- zipWithM createGroup [1..] ndata
94 94
  let (groups, nodes) = unzip grpNodeData
95 95
      nodes' = concat nodes
96 96
  let ktn = map (\(idx, n) -> (idx, Node.setIdx n idx))
b/htools/Ganeti/HTools/Text.hs
182 182
loadNode ktg [name, tm, nm, fm, td, fd, tc, fo, gu, spindles] = do
183 183
  gdx <- lookupGroup ktg name gu
184 184
  new_node <-
185
      if any (== "?") [tm,nm,fm,td,fd,tc] || fo == "Y" then
185
      if "?" `elem` [tm,nm,fm,td,fd,tc] || fo == "Y" then
186 186
          return $ Node.create name 0 0 0 0 0 0 True 0 gdx
187 187
      else do
188 188
        vtm <- tryRead name tm
......
224 224
  disk_template <- annotateResult ("Instance " ++ name)
225 225
                   (diskTemplateFromRaw dt)
226 226
  spindle_use <- tryRead name su
227
  when (sidx == pidx) $ fail $ "Instance " ++ name ++
227
  when (sidx == pidx) . fail $ "Instance " ++ name ++
228 228
           " has same primary and secondary node - " ++ pnode
229 229
  let vtags = commaSplit tags
230 230
      newinst = Instance.create name vmem vdsk vvcpus vstatus vtags
b/htools/Ganeti/HTools/Utils.hs
168 168
-- | Constructs a printable table from given header and rows
169 169
printTable :: String -> [String] -> [[String]] -> [Bool] -> String
170 170
printTable lp header rows isnum =
171
  unlines . map ((++) lp) . map ((:) ' ' . unwords) $
171
  unlines . map ((++) lp . (:) ' ' . unwords) $
172 172
  formatTable (header:rows) isnum
173 173

  
174 174
-- | Converts a unit (e.g. m or GB) into a scaling factor.
b/htools/Ganeti/Hash.hs
47 47

  
48 48
-- | Converts a list of bytes to a string.
49 49
word8ToString :: HashKey -> String
50
word8ToString = concat . map (printf "%02x")
50
word8ToString = concatMap (printf "%02x")
51 51

  
52 52
-- | Computes the HMAC for a given key/test and salt.
53 53
computeMac :: HashKey -> Maybe String -> String -> String
b/htools/Ganeti/Logging.hs
112 112
                     Just path -> openFormattedHandler file_logging fmt $
113 113
                                  fileHandler path level
114 114

  
115
  let handlers = concat [file_handlers, stderr_handlers]
115
  let handlers = file_handlers ++ stderr_handlers
116 116
  updateGlobalLogger rootLoggerName $ setHandlers handlers
117 117
  -- syslog handler is special (another type, still instance of the
118 118
  -- typeclass, and has a built-in formatter), so we can't pass it in
b/htools/Ganeti/Luxi.hs
310 310
buildCall :: LuxiOp  -- ^ The method
311 311
          -> String  -- ^ The serialized form
312 312
buildCall lo =
313
  let ja = [ (strOfKey Method, JSString $ toJSString $ strOfOp lo::JSValue)
314
           , (strOfKey Args, opToArgs lo::JSValue)
313
  let ja = [ (strOfKey Method, J.showJSON $ strOfOp lo)
314
           , (strOfKey Args, opToArgs lo)
315 315
           ]
316 316
      jo = toJSObject ja
317 317
  in encodeStrict jo
b/htools/Ganeti/Rpc.hs
102 102
    "Node " ++ nodeName node ++ " is marked as offline"
103 103

  
104 104
rpcErrorJsonReport :: (Monad m) => J.Result a -> m (Either RpcError a)
105
rpcErrorJsonReport (J.Error x) = return $ Left $ JsonDecodeError x
105
rpcErrorJsonReport (J.Error x) = return . Left $ JsonDecodeError x
106 106
rpcErrorJsonReport (J.Ok x) = return $ Right x
107 107

  
108 108
-- | Basic timeouts for RPC calls.
......
162 162
      url = requestUrl request
163 163
  -- FIXME: This is very similar to getUrl in Htools/Rapi.hs
164 164
  (code, !body) <- curlGetString url $ curlOpts ++ reqOpts
165
  case code of
166
    CurlOK -> return $ Right body
167
    _ -> return $ Left $ CurlLayerError node (show code)
165
  return $ case code of
166
             CurlOK -> Right body
167
             _ -> Left $ CurlLayerError node (show code)
168 168
#endif
169 169

  
170 170
-- | Prepare url for the HTTP request.
b/htools/Ganeti/Ssconf.hs
128 128
getPrimaryIPFamily :: Maybe FilePath -> IO (Result Socket.Family)
129 129
getPrimaryIPFamily optpath = do
130 130
  result <- readSSConfFile optpath (Just (show C.ip4Family)) SSPrimaryIpFamily
131
  return (result >>= return . rstripSpace >>=
131
  return (liftM rstripSpace result >>=
132 132
          tryRead "Parsing af_family" >>= parseIPFamily)
b/htools/lint-hints.hs
1
{- Custom hint lints for Ganeti.
2

  
3
Since passing --hint to hlint will override, not extend the built-in hints, we need to import the existing hints so that we get full coverage.
4

  
5
-}
6

  
7
import "hint" HLint.Default
8
import "hint" HLint.Dollar
9

  
1 10
-- The following two hints warn to simplify e.g. "map (\v -> (v,
2 11
-- True)) lst" to "zip lst (repeat True)", which is more abstract
3 12
warn = map (\v -> (v, x)) y ==> zip y (repeat x)

Also available in: Unified diff