Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / HTools / CLI.hs @ 313fdabc

History | View | Annotate | Download (21.7 kB)

1 209b3711 Iustin Pop
{-| Implementation of command-line functions.
2 209b3711 Iustin Pop
3 525bfb36 Iustin Pop
This module holds the common command-line related functions for the
4 26d62e4c Iustin Pop
binaries, separated into this module since "Ganeti.Utils" is
5 525bfb36 Iustin Pop
used in many other places and this is more IO oriented.
6 209b3711 Iustin Pop
7 209b3711 Iustin Pop
-}
8 209b3711 Iustin Pop
9 e2fa2baf Iustin Pop
{-
10 e2fa2baf Iustin Pop
11 e247747c Iustin Pop
Copyright (C) 2009, 2010, 2011, 2012, 2013 Google Inc.
12 e2fa2baf Iustin Pop
13 e2fa2baf Iustin Pop
This program is free software; you can redistribute it and/or modify
14 e2fa2baf Iustin Pop
it under the terms of the GNU General Public License as published by
15 e2fa2baf Iustin Pop
the Free Software Foundation; either version 2 of the License, or
16 e2fa2baf Iustin Pop
(at your option) any later version.
17 e2fa2baf Iustin Pop
18 e2fa2baf Iustin Pop
This program is distributed in the hope that it will be useful, but
19 e2fa2baf Iustin Pop
WITHOUT ANY WARRANTY; without even the implied warranty of
20 e2fa2baf Iustin Pop
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 e2fa2baf Iustin Pop
General Public License for more details.
22 e2fa2baf Iustin Pop
23 e2fa2baf Iustin Pop
You should have received a copy of the GNU General Public License
24 e2fa2baf Iustin Pop
along with this program; if not, write to the Free Software
25 e2fa2baf Iustin Pop
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 e2fa2baf Iustin Pop
02110-1301, USA.
27 e2fa2baf Iustin Pop
28 e2fa2baf Iustin Pop
-}
29 e2fa2baf Iustin Pop
30 209b3711 Iustin Pop
module Ganeti.HTools.CLI
31 cd08cfa4 Iustin Pop
  ( Options(..)
32 cd08cfa4 Iustin Pop
  , OptType
33 51000365 Iustin Pop
  , defaultOptions
34 51000365 Iustin Pop
  , Ganeti.HTools.CLI.parseOpts
35 51c3d88f Iustin Pop
  , parseOptsInner
36 a7ea861a Iustin Pop
  , parseYesNo
37 8b5a517a Iustin Pop
  , parseISpecString
38 cd08cfa4 Iustin Pop
  , shTemplate
39 cd08cfa4 Iustin Pop
  , maybePrintNodes
40 cd08cfa4 Iustin Pop
  , maybePrintInsts
41 cd08cfa4 Iustin Pop
  , maybeShowWarnings
42 79eef90b Agata Murawska
  , printKeys
43 79eef90b Agata Murawska
  , printFinal
44 cd08cfa4 Iustin Pop
  , setNodeStatus
45 cd08cfa4 Iustin Pop
  -- * The options
46 cd08cfa4 Iustin Pop
  , oDataFile
47 cd08cfa4 Iustin Pop
  , oDiskMoves
48 cd08cfa4 Iustin Pop
  , oDiskTemplate
49 f0753837 René Nussbaumer
  , oSpindleUse
50 cd08cfa4 Iustin Pop
  , oDynuFile
51 cd08cfa4 Iustin Pop
  , oEvacMode
52 cd08cfa4 Iustin Pop
  , oExInst
53 cd08cfa4 Iustin Pop
  , oExTags
54 cd08cfa4 Iustin Pop
  , oExecJobs
55 7dbe4c72 Klaus Aehlig
  , oForce
56 cd08cfa4 Iustin Pop
  , oGroup
57 9899796b René Nussbaumer
  , oIAllocSrc
58 cd08cfa4 Iustin Pop
  , oInstMoves
59 8af72964 Dato Simó
  , oJobDelay
60 29a30533 Iustin Pop
  , genOLuxiSocket
61 cd08cfa4 Iustin Pop
  , oLuxiSocket
62 cd08cfa4 Iustin Pop
  , oMachineReadable
63 cd08cfa4 Iustin Pop
  , oMaxCpu
64 cd08cfa4 Iustin Pop
  , oMaxSolLength
65 cd08cfa4 Iustin Pop
  , oMinDisk
66 cd08cfa4 Iustin Pop
  , oMinGain
67 cd08cfa4 Iustin Pop
  , oMinGainLim
68 cd08cfa4 Iustin Pop
  , oMinScore
69 cd08cfa4 Iustin Pop
  , oNoHeaders
70 22e513e7 Agata Murawska
  , oNoSimulation
71 cd08cfa4 Iustin Pop
  , oNodeSim
72 313fdabc Klaus Aehlig
  , oNodeTags
73 cd08cfa4 Iustin Pop
  , oOfflineNode
74 cd08cfa4 Iustin Pop
  , oOutputDir
75 cd08cfa4 Iustin Pop
  , oPrintCommands
76 cd08cfa4 Iustin Pop
  , oPrintInsts
77 cd08cfa4 Iustin Pop
  , oPrintNodes
78 cd08cfa4 Iustin Pop
  , oQuiet
79 cd08cfa4 Iustin Pop
  , oRapiMaster
80 cd08cfa4 Iustin Pop
  , oSaveCluster
81 cd08cfa4 Iustin Pop
  , oSelInst
82 cd08cfa4 Iustin Pop
  , oShowHelp
83 cd08cfa4 Iustin Pop
  , oShowVer
84 097ad7ee Iustin Pop
  , oShowComp
85 294bb337 Iustin Pop
  , oStdSpec
86 cd08cfa4 Iustin Pop
  , oTieredSpec
87 cd08cfa4 Iustin Pop
  , oVerbose
88 e247747c Iustin Pop
  , oPriority
89 42834645 Iustin Pop
  , genericOpts
90 cd08cfa4 Iustin Pop
  ) where
91 209b3711 Iustin Pop
92 cc532bdd Iustin Pop
import Control.Monad
93 79eef90b Agata Murawska
import Data.Char (toUpper)
94 e8f89bb6 Iustin Pop
import Data.Maybe (fromMaybe)
95 209b3711 Iustin Pop
import System.Console.GetOpt
96 209b3711 Iustin Pop
import System.IO
97 88a10df5 Iustin Pop
import Text.Printf (printf)
98 209b3711 Iustin Pop
99 5296ee23 Iustin Pop
import qualified Ganeti.HTools.Container as Container
100 5296ee23 Iustin Pop
import qualified Ganeti.HTools.Node as Node
101 9eeb0aa5 Michael Hanselmann
import qualified Ganeti.Path as Path
102 92e32d76 Iustin Pop
import Ganeti.HTools.Types
103 2fc5653f Iustin Pop
import Ganeti.BasicTypes
104 51000365 Iustin Pop
import Ganeti.Common as Common
105 e247747c Iustin Pop
import Ganeti.Types
106 26d62e4c Iustin Pop
import Ganeti.Utils
107 fae371cc Iustin Pop
108 525bfb36 Iustin Pop
-- * Data types
109 525bfb36 Iustin Pop
110 0427285d Iustin Pop
-- | Command line options structure.
111 0427285d Iustin Pop
data Options = Options
112 cd08cfa4 Iustin Pop
  { optDataFile    :: Maybe FilePath -- ^ Path to the cluster data file
113 cd08cfa4 Iustin Pop
  , optDiskMoves   :: Bool           -- ^ Allow disk moves
114 cd08cfa4 Iustin Pop
  , optInstMoves   :: Bool           -- ^ Allow instance moves
115 9fdd3d0f Iustin Pop
  , optDiskTemplate :: Maybe DiskTemplate  -- ^ Override for the disk template
116 f0753837 René Nussbaumer
  , optSpindleUse  :: Maybe Int      -- ^ Override for the spindle usage
117 cd08cfa4 Iustin Pop
  , optDynuFile    :: Maybe FilePath -- ^ Optional file with dynamic use data
118 cd08cfa4 Iustin Pop
  , optEvacMode    :: Bool           -- ^ Enable evacuation mode
119 cd08cfa4 Iustin Pop
  , optExInst      :: [String]       -- ^ Instances to be excluded
120 cd08cfa4 Iustin Pop
  , optExTags      :: Maybe [String] -- ^ Tags to use for exclusion
121 cd08cfa4 Iustin Pop
  , optExecJobs    :: Bool           -- ^ Execute the commands via Luxi
122 7dbe4c72 Klaus Aehlig
  , optForce       :: Bool           -- ^ Force the execution
123 cd08cfa4 Iustin Pop
  , optGroup       :: Maybe GroupID  -- ^ The UUID of the group to process
124 9899796b René Nussbaumer
  , optIAllocSrc   :: Maybe FilePath -- ^ The iallocation spec
125 cd08cfa4 Iustin Pop
  , optSelInst     :: [String]       -- ^ Instances to be excluded
126 cd08cfa4 Iustin Pop
  , optLuxi        :: Maybe FilePath -- ^ Collect data from Luxi
127 8af72964 Dato Simó
  , optJobDelay    :: Double         -- ^ Delay before executing first job
128 cd08cfa4 Iustin Pop
  , optMachineReadable :: Bool       -- ^ Output machine-readable format
129 cd08cfa4 Iustin Pop
  , optMaster      :: String         -- ^ Collect data from RAPI
130 cd08cfa4 Iustin Pop
  , optMaxLength   :: Int            -- ^ Stop after this many steps
131 284e9822 Iustin Pop
  , optMcpu        :: Maybe Double   -- ^ Override max cpu ratio for nodes
132 cd08cfa4 Iustin Pop
  , optMdsk        :: Double         -- ^ Max disk usage ratio for nodes
133 cd08cfa4 Iustin Pop
  , optMinGain     :: Score          -- ^ Min gain we aim for in a step
134 cd08cfa4 Iustin Pop
  , optMinGainLim  :: Score          -- ^ Limit below which we apply mingain
135 cd08cfa4 Iustin Pop
  , optMinScore    :: Score          -- ^ The minimum score we aim for
136 cd08cfa4 Iustin Pop
  , optNoHeaders   :: Bool           -- ^ Do not show a header line
137 22e513e7 Agata Murawska
  , optNoSimulation :: Bool          -- ^ Skip the rebalancing dry-run
138 cd08cfa4 Iustin Pop
  , optNodeSim     :: [String]       -- ^ Cluster simulation mode
139 313fdabc Klaus Aehlig
  , optNodeTags    :: Maybe [String] -- ^ List of node tags to restrict to 
140 cd08cfa4 Iustin Pop
  , optOffline     :: [String]       -- ^ Names of offline nodes
141 cd08cfa4 Iustin Pop
  , optOutPath     :: FilePath       -- ^ Path to the output directory
142 cd08cfa4 Iustin Pop
  , optSaveCluster :: Maybe FilePath -- ^ Save cluster state to this file
143 cd08cfa4 Iustin Pop
  , optShowCmds    :: Maybe FilePath -- ^ Whether to show the command list
144 cd08cfa4 Iustin Pop
  , optShowHelp    :: Bool           -- ^ Just show the help
145 097ad7ee Iustin Pop
  , optShowComp    :: Bool           -- ^ Just show the completion info
146 cd08cfa4 Iustin Pop
  , optShowInsts   :: Bool           -- ^ Whether to show the instance map
147 cd08cfa4 Iustin Pop
  , optShowNodes   :: Maybe [String] -- ^ Whether to show node status
148 cd08cfa4 Iustin Pop
  , optShowVer     :: Bool           -- ^ Just show the program version
149 be468da0 Iustin Pop
  , optStdSpec     :: Maybe RSpec    -- ^ Requested standard specs
150 ee4ffc8a Iustin Pop
  , optTestCount   :: Maybe Int      -- ^ Optional test count override
151 cd08cfa4 Iustin Pop
  , optTieredSpec  :: Maybe RSpec    -- ^ Requested specs for tiered mode
152 cd08cfa4 Iustin Pop
  , optReplay      :: Maybe String   -- ^ Unittests: RNG state
153 cd08cfa4 Iustin Pop
  , optVerbose     :: Int            -- ^ Verbosity level
154 e247747c Iustin Pop
  , optPriority    :: Maybe OpSubmitPriority -- ^ OpCode submit priority
155 cd08cfa4 Iustin Pop
  } deriving Show
156 0427285d Iustin Pop
157 0427285d Iustin Pop
-- | Default values for the command line options.
158 0427285d Iustin Pop
defaultOptions :: Options
159 0427285d Iustin Pop
defaultOptions  = Options
160 cd08cfa4 Iustin Pop
  { optDataFile    = Nothing
161 cd08cfa4 Iustin Pop
  , optDiskMoves   = True
162 cd08cfa4 Iustin Pop
  , optInstMoves   = True
163 9fdd3d0f Iustin Pop
  , optDiskTemplate = Nothing
164 f0753837 René Nussbaumer
  , optSpindleUse  = Nothing
165 cd08cfa4 Iustin Pop
  , optDynuFile    = Nothing
166 cd08cfa4 Iustin Pop
  , optEvacMode    = False
167 cd08cfa4 Iustin Pop
  , optExInst      = []
168 cd08cfa4 Iustin Pop
  , optExTags      = Nothing
169 cd08cfa4 Iustin Pop
  , optExecJobs    = False
170 7dbe4c72 Klaus Aehlig
  , optForce       = False
171 cd08cfa4 Iustin Pop
  , optGroup       = Nothing
172 9899796b René Nussbaumer
  , optIAllocSrc   = Nothing
173 cd08cfa4 Iustin Pop
  , optSelInst     = []
174 cd08cfa4 Iustin Pop
  , optLuxi        = Nothing
175 8af72964 Dato Simó
  , optJobDelay    = 10
176 cd08cfa4 Iustin Pop
  , optMachineReadable = False
177 cd08cfa4 Iustin Pop
  , optMaster      = ""
178 cd08cfa4 Iustin Pop
  , optMaxLength   = -1
179 284e9822 Iustin Pop
  , optMcpu        = Nothing
180 cd08cfa4 Iustin Pop
  , optMdsk        = defReservedDiskRatio
181 cd08cfa4 Iustin Pop
  , optMinGain     = 1e-2
182 cd08cfa4 Iustin Pop
  , optMinGainLim  = 1e-1
183 cd08cfa4 Iustin Pop
  , optMinScore    = 1e-9
184 cd08cfa4 Iustin Pop
  , optNoHeaders   = False
185 22e513e7 Agata Murawska
  , optNoSimulation = False
186 cd08cfa4 Iustin Pop
  , optNodeSim     = []
187 313fdabc Klaus Aehlig
  , optNodeTags    = Nothing
188 cd08cfa4 Iustin Pop
  , optOffline     = []
189 cd08cfa4 Iustin Pop
  , optOutPath     = "."
190 cd08cfa4 Iustin Pop
  , optSaveCluster = Nothing
191 cd08cfa4 Iustin Pop
  , optShowCmds    = Nothing
192 cd08cfa4 Iustin Pop
  , optShowHelp    = False
193 097ad7ee Iustin Pop
  , optShowComp    = False
194 cd08cfa4 Iustin Pop
  , optShowInsts   = False
195 cd08cfa4 Iustin Pop
  , optShowNodes   = Nothing
196 cd08cfa4 Iustin Pop
  , optShowVer     = False
197 be468da0 Iustin Pop
  , optStdSpec     = Nothing
198 ee4ffc8a Iustin Pop
  , optTestCount   = Nothing
199 cd08cfa4 Iustin Pop
  , optTieredSpec  = Nothing
200 cd08cfa4 Iustin Pop
  , optReplay      = Nothing
201 cd08cfa4 Iustin Pop
  , optVerbose     = 1
202 e247747c Iustin Pop
  , optPriority    = Nothing
203 cd08cfa4 Iustin Pop
  }
204 0427285d Iustin Pop
205 55abd2c7 Iustin Pop
-- | Abbreviation for the option type.
206 51000365 Iustin Pop
type OptType = GenericOptType Options
207 51000365 Iustin Pop
208 51000365 Iustin Pop
instance StandardOptions Options where
209 51000365 Iustin Pop
  helpRequested = optShowHelp
210 51000365 Iustin Pop
  verRequested  = optShowVer
211 097ad7ee Iustin Pop
  compRequested = optShowComp
212 5b11f8db Iustin Pop
  requestHelp o = o { optShowHelp = True }
213 5b11f8db Iustin Pop
  requestVer  o = o { optShowVer  = True }
214 097ad7ee Iustin Pop
  requestComp o = o { optShowComp = True }
215 0427285d Iustin Pop
216 7da760ca Iustin Pop
-- * Helper functions
217 7da760ca Iustin Pop
218 7da760ca Iustin Pop
parseISpecString :: String -> String -> Result RSpec
219 7da760ca Iustin Pop
parseISpecString descr inp = do
220 7da760ca Iustin Pop
  let sp = sepSplit ',' inp
221 8b5a517a Iustin Pop
      err = Bad ("Invalid " ++ descr ++ " specification: '" ++ inp ++
222 8b5a517a Iustin Pop
                 "', expected disk,ram,cpu")
223 8b5a517a Iustin Pop
  when (length sp /= 3) err
224 7da760ca Iustin Pop
  prs <- mapM (\(fn, val) -> fn val) $
225 8b5a517a Iustin Pop
         zip [ annotateResult (descr ++ " specs disk") . parseUnit
226 8b5a517a Iustin Pop
             , annotateResult (descr ++ " specs memory") . parseUnit
227 7da760ca Iustin Pop
             , tryRead (descr ++ " specs cpus")
228 7da760ca Iustin Pop
             ] sp
229 7da760ca Iustin Pop
  case prs of
230 7da760ca Iustin Pop
    [dsk, ram, cpu] -> return $ RSpec cpu ram dsk
231 8b5a517a Iustin Pop
    _ -> err
232 7da760ca Iustin Pop
233 ce207617 Iustin Pop
-- | Disk template choices.
234 ce207617 Iustin Pop
optComplDiskTemplate :: OptCompletion
235 ce207617 Iustin Pop
optComplDiskTemplate = OptComplChoices $
236 ce207617 Iustin Pop
                       map diskTemplateToRaw [minBound..maxBound]
237 ce207617 Iustin Pop
238 525bfb36 Iustin Pop
-- * Command line options
239 525bfb36 Iustin Pop
240 16c2369c Iustin Pop
oDataFile :: OptType
241 ce207617 Iustin Pop
oDataFile =
242 ce207617 Iustin Pop
  (Option "t" ["text-data"]
243 ce207617 Iustin Pop
   (ReqArg (\ f o -> Ok o { optDataFile = Just f }) "FILE")
244 ce207617 Iustin Pop
   "the cluster data FILE",
245 ce207617 Iustin Pop
   OptComplFile)
246 0427285d Iustin Pop
247 df18fdfe Iustin Pop
oDiskMoves :: OptType
248 ce207617 Iustin Pop
oDiskMoves =
249 ce207617 Iustin Pop
  (Option "" ["no-disk-moves"]
250 ce207617 Iustin Pop
   (NoArg (\ opts -> Ok opts { optDiskMoves = False}))
251 ce207617 Iustin Pop
   "disallow disk moves from the list of allowed instance changes,\
252 ce207617 Iustin Pop
   \ thus allowing only the 'cheap' failover/migrate operations",
253 ce207617 Iustin Pop
   OptComplNone)
254 b2278348 Iustin Pop
255 c4bb977b Iustin Pop
oDiskTemplate :: OptType
256 ce207617 Iustin Pop
oDiskTemplate =
257 ce207617 Iustin Pop
  (Option "" ["disk-template"]
258 ce207617 Iustin Pop
   (reqWithConversion diskTemplateFromRaw
259 ce207617 Iustin Pop
    (\dt opts -> Ok opts { optDiskTemplate = Just dt })
260 ce207617 Iustin Pop
    "TEMPLATE") "select the desired disk template",
261 ce207617 Iustin Pop
   optComplDiskTemplate)
262 c4bb977b Iustin Pop
263 f0753837 René Nussbaumer
oSpindleUse :: OptType
264 ce207617 Iustin Pop
oSpindleUse =
265 ce207617 Iustin Pop
  (Option "" ["spindle-use"]
266 ce207617 Iustin Pop
   (reqWithConversion (tryRead "parsing spindle-use")
267 ce207617 Iustin Pop
    (\su opts -> do
268 ce207617 Iustin Pop
       when (su < 0) $
269 ce207617 Iustin Pop
            fail "Invalid value of the spindle-use (expected >= 0)"
270 ce207617 Iustin Pop
       return $ opts { optSpindleUse = Just su })
271 ce207617 Iustin Pop
    "SPINDLES") "select how many virtual spindle instances use\
272 ce207617 Iustin Pop
                \ [default read from cluster]",
273 ecebe9f6 Iustin Pop
   OptComplFloat)
274 f0753837 René Nussbaumer
275 ddef0585 Guido Trotter
oSelInst :: OptType
276 ce207617 Iustin Pop
oSelInst =
277 ce207617 Iustin Pop
  (Option "" ["select-instances"]
278 ce207617 Iustin Pop
   (ReqArg (\ f opts -> Ok opts { optSelInst = sepSplit ',' f }) "INSTS")
279 ce207617 Iustin Pop
   "only select given instances for any moves",
280 ce207617 Iustin Pop
   OptComplManyInstances)
281 ddef0585 Guido Trotter
282 8fcfb767 Guido Trotter
oInstMoves :: OptType
283 ce207617 Iustin Pop
oInstMoves =
284 ce207617 Iustin Pop
  (Option "" ["no-instance-moves"]
285 ce207617 Iustin Pop
   (NoArg (\ opts -> Ok opts { optInstMoves = False}))
286 ce207617 Iustin Pop
   "disallow instance (primary node) moves from the list of allowed,\
287 ce207617 Iustin Pop
   \ instance changes, thus allowing only slower, but sometimes\
288 ce207617 Iustin Pop
   \ safer, drbd secondary changes",
289 ce207617 Iustin Pop
   OptComplNone)
290 8fcfb767 Guido Trotter
291 df18fdfe Iustin Pop
oDynuFile :: OptType
292 ce207617 Iustin Pop
oDynuFile =
293 ce207617 Iustin Pop
  (Option "U" ["dynu-file"]
294 ce207617 Iustin Pop
   (ReqArg (\ f opts -> Ok opts { optDynuFile = Just f }) "FILE")
295 ce207617 Iustin Pop
   "Import dynamic utilisation data from the given FILE",
296 ce207617 Iustin Pop
   OptComplFile)
297 0427285d Iustin Pop
298 f0f21ec4 Iustin Pop
oEvacMode :: OptType
299 ce207617 Iustin Pop
oEvacMode =
300 ce207617 Iustin Pop
  (Option "E" ["evac-mode"]
301 ce207617 Iustin Pop
   (NoArg (\opts -> Ok opts { optEvacMode = True }))
302 516c52f2 Dato Simó
   "enable evacuation mode, where the algorithm only moves\
303 ce207617 Iustin Pop
   \ instances away from offline and drained nodes",
304 ce207617 Iustin Pop
   OptComplNone)
305 f0f21ec4 Iustin Pop
306 10f396e1 Iustin Pop
oExInst :: OptType
307 ce207617 Iustin Pop
oExInst =
308 ce207617 Iustin Pop
  (Option "" ["exclude-instances"]
309 ce207617 Iustin Pop
   (ReqArg (\ f opts -> Ok opts { optExInst = sepSplit ',' f }) "INSTS")
310 ce207617 Iustin Pop
   "exclude given instances from any moves",
311 ce207617 Iustin Pop
   OptComplManyInstances)
312 10f396e1 Iustin Pop
313 df18fdfe Iustin Pop
oExTags :: OptType
314 ce207617 Iustin Pop
oExTags =
315 ce207617 Iustin Pop
  (Option "" ["exclusion-tags"]
316 ce207617 Iustin Pop
   (ReqArg (\ f opts -> Ok opts { optExTags = Just $ sepSplit ',' f })
317 ce207617 Iustin Pop
    "TAG,...") "Enable instance exclusion based on given tag prefix",
318 ce207617 Iustin Pop
   OptComplString)
319 0427285d Iustin Pop
320 0df5a1b4 Iustin Pop
oExecJobs :: OptType
321 ce207617 Iustin Pop
oExecJobs =
322 ce207617 Iustin Pop
  (Option "X" ["exec"]
323 ce207617 Iustin Pop
   (NoArg (\ opts -> Ok opts { optExecJobs = True}))
324 ce207617 Iustin Pop
   "execute the suggested moves via Luxi (only available when using\
325 ce207617 Iustin Pop
   \ it for data gathering)",
326 ce207617 Iustin Pop
   OptComplNone)
327 0df5a1b4 Iustin Pop
328 7dbe4c72 Klaus Aehlig
oForce :: OptType
329 7dbe4c72 Klaus Aehlig
oForce =
330 7dbe4c72 Klaus Aehlig
  (Option "f" ["force"]
331 7dbe4c72 Klaus Aehlig
   (NoArg (\ opts -> Ok opts {optForce = True}))
332 7dbe4c72 Klaus Aehlig
   "force the execution of this program, even if warnings would\
333 7dbe4c72 Klaus Aehlig
   \ otherwise prevent it",
334 7dbe4c72 Klaus Aehlig
   OptComplNone)
335 7dbe4c72 Klaus Aehlig
336 a423b510 Iustin Pop
oGroup :: OptType
337 ce207617 Iustin Pop
oGroup =
338 ce207617 Iustin Pop
  (Option "G" ["group"]
339 ce207617 Iustin Pop
   (ReqArg (\ f o -> Ok o { optGroup = Just f }) "ID")
340 0ff01075 Guido Trotter
   "the target node group (name or UUID)",
341 ce207617 Iustin Pop
   OptComplOneGroup)
342 a423b510 Iustin Pop
343 9899796b René Nussbaumer
oIAllocSrc :: OptType
344 ce207617 Iustin Pop
oIAllocSrc =
345 ce207617 Iustin Pop
  (Option "I" ["ialloc-src"]
346 ce207617 Iustin Pop
   (ReqArg (\ f opts -> Ok opts { optIAllocSrc = Just f }) "FILE")
347 ce207617 Iustin Pop
   "Specify an iallocator spec as the cluster data source",
348 ce207617 Iustin Pop
   OptComplFile)
349 9899796b René Nussbaumer
350 8af72964 Dato Simó
oJobDelay :: OptType
351 8af72964 Dato Simó
oJobDelay =
352 8af72964 Dato Simó
  (Option "" ["job-delay"]
353 8af72964 Dato Simó
   (reqWithConversion (tryRead "job delay")
354 8af72964 Dato Simó
    (\d opts -> Ok opts { optJobDelay = d }) "SECONDS")
355 8af72964 Dato Simó
   "insert this much delay before the execution of repair jobs\
356 8af72964 Dato Simó
   \ to allow the tool to continue processing instances",
357 8af72964 Dato Simó
   OptComplFloat)
358 8af72964 Dato Simó
359 29a30533 Iustin Pop
genOLuxiSocket :: String -> OptType
360 29a30533 Iustin Pop
genOLuxiSocket defSocket =
361 ce207617 Iustin Pop
  (Option "L" ["luxi"]
362 ce207617 Iustin Pop
   (OptArg ((\ f opts -> Ok opts { optLuxi = Just f }) .
363 29a30533 Iustin Pop
            fromMaybe defSocket) "SOCKET")
364 29a30533 Iustin Pop
   ("collect data via Luxi, optionally using the given SOCKET path [" ++
365 29a30533 Iustin Pop
    defSocket ++ "]"),
366 ce207617 Iustin Pop
   OptComplFile)
367 0427285d Iustin Pop
368 29a30533 Iustin Pop
oLuxiSocket :: IO OptType
369 67e4fcf4 Iustin Pop
oLuxiSocket = liftM genOLuxiSocket Path.defaultLuxiSocket
370 29a30533 Iustin Pop
371 519edd9f Iustin Pop
oMachineReadable :: OptType
372 ce207617 Iustin Pop
oMachineReadable =
373 ce207617 Iustin Pop
  (Option "" ["machine-readable"]
374 ce207617 Iustin Pop
   (OptArg (\ f opts -> do
375 ce207617 Iustin Pop
              flag <- parseYesNo True f
376 ce207617 Iustin Pop
              return $ opts { optMachineReadable = flag }) "CHOICE")
377 ce207617 Iustin Pop
   "enable machine readable output (pass either 'yes' or 'no' to\
378 ce207617 Iustin Pop
   \ explicitly control the flag, or without an argument defaults to\
379 ce207617 Iustin Pop
   \ yes",
380 ce207617 Iustin Pop
   optComplYesNo)
381 519edd9f Iustin Pop
382 0427285d Iustin Pop
oMaxCpu :: OptType
383 ce207617 Iustin Pop
oMaxCpu =
384 ce207617 Iustin Pop
  (Option "" ["max-cpu"]
385 ce207617 Iustin Pop
   (reqWithConversion (tryRead "parsing max-cpu")
386 ce207617 Iustin Pop
    (\mcpu opts -> do
387 ce207617 Iustin Pop
       when (mcpu <= 0) $
388 ce207617 Iustin Pop
            fail "Invalid value of the max-cpu ratio, expected >0"
389 ce207617 Iustin Pop
       return $ opts { optMcpu = Just mcpu }) "RATIO")
390 ce207617 Iustin Pop
   "maximum virtual-to-physical cpu ratio for nodes (from 0\
391 ce207617 Iustin Pop
   \ upwards) [default read from cluster]",
392 ecebe9f6 Iustin Pop
   OptComplFloat)
393 0427285d Iustin Pop
394 df18fdfe Iustin Pop
oMaxSolLength :: OptType
395 ce207617 Iustin Pop
oMaxSolLength =
396 ce207617 Iustin Pop
  (Option "l" ["max-length"]
397 ce207617 Iustin Pop
   (reqWithConversion (tryRead "max solution length")
398 ce207617 Iustin Pop
    (\i opts -> Ok opts { optMaxLength = i }) "N")
399 516c52f2 Dato Simó
   "cap the solution at this many balancing or allocation\
400 516c52f2 Dato Simó
   \ rounds (useful for very unbalanced clusters or empty\
401 ce207617 Iustin Pop
   \ clusters)",
402 ecebe9f6 Iustin Pop
   OptComplInteger)
403 df18fdfe Iustin Pop
404 0427285d Iustin Pop
oMinDisk :: OptType
405 ce207617 Iustin Pop
oMinDisk =
406 ce207617 Iustin Pop
  (Option "" ["min-disk"]
407 ce207617 Iustin Pop
   (reqWithConversion (tryRead "min free disk space")
408 ce207617 Iustin Pop
    (\n opts -> Ok opts { optMdsk = n }) "RATIO")
409 ce207617 Iustin Pop
   "minimum free disk space for nodes (between 0 and 1) [0]",
410 ecebe9f6 Iustin Pop
   OptComplFloat)
411 0427285d Iustin Pop
412 4f807a57 Iustin Pop
oMinGain :: OptType
413 ce207617 Iustin Pop
oMinGain =
414 ce207617 Iustin Pop
  (Option "g" ["min-gain"]
415 ce207617 Iustin Pop
   (reqWithConversion (tryRead "min gain")
416 ce207617 Iustin Pop
    (\g opts -> Ok opts { optMinGain = g }) "DELTA")
417 ce207617 Iustin Pop
   "minimum gain to aim for in a balancing step before giving up",
418 ecebe9f6 Iustin Pop
   OptComplFloat)
419 4f807a57 Iustin Pop
420 4f807a57 Iustin Pop
oMinGainLim :: OptType
421 ce207617 Iustin Pop
oMinGainLim =
422 ce207617 Iustin Pop
  (Option "" ["min-gain-limit"]
423 ce207617 Iustin Pop
   (reqWithConversion (tryRead "min gain limit")
424 ce207617 Iustin Pop
    (\g opts -> Ok opts { optMinGainLim = g }) "SCORE")
425 ce207617 Iustin Pop
   "minimum cluster score for which we start checking the min-gain",
426 ecebe9f6 Iustin Pop
   OptComplFloat)
427 4f807a57 Iustin Pop
428 df18fdfe Iustin Pop
oMinScore :: OptType
429 ce207617 Iustin Pop
oMinScore =
430 ce207617 Iustin Pop
  (Option "e" ["min-score"]
431 ce207617 Iustin Pop
   (reqWithConversion (tryRead "min score")
432 ce207617 Iustin Pop
    (\e opts -> Ok opts { optMinScore = e }) "EPSILON")
433 ce207617 Iustin Pop
   "mininum score to aim for",
434 ecebe9f6 Iustin Pop
   OptComplFloat)
435 c0501c69 Iustin Pop
436 df18fdfe Iustin Pop
oNoHeaders :: OptType
437 ce207617 Iustin Pop
oNoHeaders =
438 ce207617 Iustin Pop
  (Option "" ["no-headers"]
439 ce207617 Iustin Pop
   (NoArg (\ opts -> Ok opts { optNoHeaders = True }))
440 ce207617 Iustin Pop
   "do not show a header line",
441 ce207617 Iustin Pop
   OptComplNone)
442 4f83a560 Iustin Pop
443 22e513e7 Agata Murawska
oNoSimulation :: OptType
444 ce207617 Iustin Pop
oNoSimulation =
445 ce207617 Iustin Pop
  (Option "" ["no-simulation"]
446 ce207617 Iustin Pop
   (NoArg (\opts -> Ok opts {optNoSimulation = True}))
447 ce207617 Iustin Pop
   "do not perform rebalancing simulation",
448 ce207617 Iustin Pop
   OptComplNone)
449 22e513e7 Agata Murawska
450 df18fdfe Iustin Pop
oNodeSim :: OptType
451 ce207617 Iustin Pop
oNodeSim =
452 ce207617 Iustin Pop
  (Option "" ["simulate"]
453 ce207617 Iustin Pop
   (ReqArg (\ f o -> Ok o { optNodeSim = f:optNodeSim o }) "SPEC")
454 ce207617 Iustin Pop
   "simulate an empty cluster, given as\
455 ce207617 Iustin Pop
   \ 'alloc_policy,num_nodes,disk,ram,cpu'",
456 ce207617 Iustin Pop
   OptComplString)
457 df18fdfe Iustin Pop
458 313fdabc Klaus Aehlig
oNodeTags :: OptType
459 313fdabc Klaus Aehlig
oNodeTags =
460 313fdabc Klaus Aehlig
  (Option "" ["node-tags"]
461 313fdabc Klaus Aehlig
   (ReqArg (\ f opts -> Ok opts { optNodeTags = Just $ sepSplit ',' f })
462 313fdabc Klaus Aehlig
    "TAG,...") "Restrict to nodes with the given tags",
463 313fdabc Klaus Aehlig
   OptComplString)
464 313fdabc Klaus Aehlig
     
465 df18fdfe Iustin Pop
oOfflineNode :: OptType
466 ce207617 Iustin Pop
oOfflineNode =
467 ce207617 Iustin Pop
  (Option "O" ["offline"]
468 ce207617 Iustin Pop
   (ReqArg (\ n o -> Ok o { optOffline = n:optOffline o }) "NODE")
469 ce207617 Iustin Pop
   "set node as offline",
470 ce207617 Iustin Pop
   OptComplOneNode)
471 df18fdfe Iustin Pop
472 df18fdfe Iustin Pop
oOutputDir :: OptType
473 ce207617 Iustin Pop
oOutputDir =
474 ce207617 Iustin Pop
  (Option "d" ["output-dir"]
475 ce207617 Iustin Pop
   (ReqArg (\ d opts -> Ok opts { optOutPath = d }) "PATH")
476 ce207617 Iustin Pop
   "directory in which to write output files",
477 ce207617 Iustin Pop
   OptComplDir)
478 df18fdfe Iustin Pop
479 df18fdfe Iustin Pop
oPrintCommands :: OptType
480 ce207617 Iustin Pop
oPrintCommands =
481 ce207617 Iustin Pop
  (Option "C" ["print-commands"]
482 ce207617 Iustin Pop
   (OptArg ((\ f opts -> Ok opts { optShowCmds = Just f }) .
483 ce207617 Iustin Pop
            fromMaybe "-")
484 ce207617 Iustin Pop
    "FILE")
485 ce207617 Iustin Pop
   "print the ganeti command list for reaching the solution,\
486 ce207617 Iustin Pop
   \ if an argument is passed then write the commands to a\
487 ce207617 Iustin Pop
   \ file named as such",
488 ce207617 Iustin Pop
   OptComplNone)
489 df18fdfe Iustin Pop
490 df18fdfe Iustin Pop
oPrintInsts :: OptType
491 ce207617 Iustin Pop
oPrintInsts =
492 ce207617 Iustin Pop
  (Option "" ["print-instances"]
493 ce207617 Iustin Pop
   (NoArg (\ opts -> Ok opts { optShowInsts = True }))
494 ce207617 Iustin Pop
   "print the final instance map",
495 ce207617 Iustin Pop
   OptComplNone)
496 df18fdfe Iustin Pop
497 df18fdfe Iustin Pop
oPrintNodes :: OptType
498 ce207617 Iustin Pop
oPrintNodes =
499 ce207617 Iustin Pop
  (Option "p" ["print-nodes"]
500 ce207617 Iustin Pop
   (OptArg ((\ f opts ->
501 ce207617 Iustin Pop
               let (prefix, realf) = case f of
502 ce207617 Iustin Pop
                                       '+':rest -> (["+"], rest)
503 ce207617 Iustin Pop
                                       _ -> ([], f)
504 ce207617 Iustin Pop
                   splitted = prefix ++ sepSplit ',' realf
505 ce207617 Iustin Pop
               in Ok opts { optShowNodes = Just splitted }) .
506 ce207617 Iustin Pop
            fromMaybe []) "FIELDS")
507 ce207617 Iustin Pop
   "print the final node list",
508 ce207617 Iustin Pop
   OptComplNone)
509 df18fdfe Iustin Pop
510 df18fdfe Iustin Pop
oQuiet :: OptType
511 ce207617 Iustin Pop
oQuiet =
512 ce207617 Iustin Pop
  (Option "q" ["quiet"]
513 ce207617 Iustin Pop
   (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts - 1 }))
514 ce207617 Iustin Pop
   "decrease the verbosity level",
515 ce207617 Iustin Pop
   OptComplNone)
516 df18fdfe Iustin Pop
517 df18fdfe Iustin Pop
oRapiMaster :: OptType
518 ce207617 Iustin Pop
oRapiMaster =
519 ce207617 Iustin Pop
  (Option "m" ["master"]
520 ce207617 Iustin Pop
   (ReqArg (\ m opts -> Ok opts { optMaster = m }) "ADDRESS")
521 ce207617 Iustin Pop
   "collect data via RAPI at the given ADDRESS",
522 ce207617 Iustin Pop
   OptComplHost)
523 df18fdfe Iustin Pop
524 02da9d07 Iustin Pop
oSaveCluster :: OptType
525 ce207617 Iustin Pop
oSaveCluster =
526 ce207617 Iustin Pop
  (Option "S" ["save"]
527 ce207617 Iustin Pop
   (ReqArg (\ f opts -> Ok opts { optSaveCluster = Just f }) "FILE")
528 ce207617 Iustin Pop
   "Save cluster state at the end of the processing to FILE",
529 ce207617 Iustin Pop
   OptComplNone)
530 02da9d07 Iustin Pop
531 294bb337 Iustin Pop
oStdSpec :: OptType
532 ce207617 Iustin Pop
oStdSpec =
533 ce207617 Iustin Pop
  (Option "" ["standard-alloc"]
534 ce207617 Iustin Pop
   (ReqArg (\ inp opts -> do
535 ce207617 Iustin Pop
              tspec <- parseISpecString "standard" inp
536 ce207617 Iustin Pop
              return $ opts { optStdSpec = Just tspec } )
537 ce207617 Iustin Pop
    "STDSPEC")
538 ce207617 Iustin Pop
   "enable standard specs allocation, given as 'disk,ram,cpu'",
539 ce207617 Iustin Pop
   OptComplString)
540 294bb337 Iustin Pop
541 1f9066c0 Iustin Pop
oTieredSpec :: OptType
542 ce207617 Iustin Pop
oTieredSpec =
543 ce207617 Iustin Pop
  (Option "" ["tiered-alloc"]
544 ce207617 Iustin Pop
   (ReqArg (\ inp opts -> do
545 ce207617 Iustin Pop
              tspec <- parseISpecString "tiered" inp
546 ce207617 Iustin Pop
              return $ opts { optTieredSpec = Just tspec } )
547 ce207617 Iustin Pop
    "TSPEC")
548 ce207617 Iustin Pop
   "enable tiered specs allocation, given as 'disk,ram,cpu'",
549 ce207617 Iustin Pop
   OptComplString)
550 1f9066c0 Iustin Pop
551 df18fdfe Iustin Pop
oVerbose :: OptType
552 ce207617 Iustin Pop
oVerbose =
553 ce207617 Iustin Pop
  (Option "v" ["verbose"]
554 ce207617 Iustin Pop
   (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts + 1 }))
555 ce207617 Iustin Pop
   "increase the verbosity level",
556 ce207617 Iustin Pop
   OptComplNone)
557 fae371cc Iustin Pop
558 e247747c Iustin Pop
oPriority :: OptType
559 e247747c Iustin Pop
oPriority =
560 e247747c Iustin Pop
  (Option "" ["priority"]
561 e247747c Iustin Pop
   (ReqArg (\ inp opts -> do
562 e247747c Iustin Pop
              prio <- parseSubmitPriority inp
563 e247747c Iustin Pop
              Ok opts { optPriority = Just prio }) "PRIO")
564 e247747c Iustin Pop
   "set the priority of submitted jobs",
565 e247747c Iustin Pop
    OptComplChoices (map fmtSubmitPriority [minBound..maxBound]))
566 e247747c Iustin Pop
567 42834645 Iustin Pop
-- | Generic options.
568 42834645 Iustin Pop
genericOpts :: [GenericOptType Options]
569 42834645 Iustin Pop
genericOpts =  [ oShowVer
570 42834645 Iustin Pop
               , oShowHelp
571 097ad7ee Iustin Pop
               , oShowComp
572 42834645 Iustin Pop
               ]
573 42834645 Iustin Pop
574 525bfb36 Iustin Pop
-- * Functions
575 525bfb36 Iustin Pop
576 51000365 Iustin Pop
-- | Wrapper over 'Common.parseOpts' with our custom options.
577 0427285d Iustin Pop
parseOpts :: [String]               -- ^ The command line arguments
578 0427285d Iustin Pop
          -> String                 -- ^ The program name
579 0427285d Iustin Pop
          -> [OptType]              -- ^ The supported command line options
580 22278fa7 Iustin Pop
          -> [ArgCompletion]        -- ^ The supported command line arguments
581 0427285d Iustin Pop
          -> IO (Options, [String]) -- ^ The resulting options and leftover
582 0427285d Iustin Pop
                                    -- arguments
583 51000365 Iustin Pop
parseOpts = Common.parseOpts defaultOptions
584 51000365 Iustin Pop
585 209b3711 Iustin Pop
586 9188aeef Iustin Pop
-- | A shell script template for autogenerated scripts.
587 e0eb63f0 Iustin Pop
shTemplate :: String
588 e0eb63f0 Iustin Pop
shTemplate =
589 cd08cfa4 Iustin Pop
  printf "#!/bin/sh\n\n\
590 cd08cfa4 Iustin Pop
         \# Auto-generated script for executing cluster rebalancing\n\n\
591 cd08cfa4 Iustin Pop
         \# To stop, touch the file /tmp/stop-htools\n\n\
592 cd08cfa4 Iustin Pop
         \set -e\n\n\
593 cd08cfa4 Iustin Pop
         \check() {\n\
594 cd08cfa4 Iustin Pop
         \  if [ -f /tmp/stop-htools ]; then\n\
595 cd08cfa4 Iustin Pop
         \    echo 'Stop requested, exiting'\n\
596 cd08cfa4 Iustin Pop
         \    exit 0\n\
597 cd08cfa4 Iustin Pop
         \  fi\n\
598 cd08cfa4 Iustin Pop
         \}\n\n"
599 417f6b50 Iustin Pop
600 417f6b50 Iustin Pop
-- | Optionally print the node list.
601 417f6b50 Iustin Pop
maybePrintNodes :: Maybe [String]       -- ^ The field list
602 417f6b50 Iustin Pop
                -> String               -- ^ Informational message
603 417f6b50 Iustin Pop
                -> ([String] -> String) -- ^ Function to generate the listing
604 417f6b50 Iustin Pop
                -> IO ()
605 417f6b50 Iustin Pop
maybePrintNodes Nothing _ _ = return ()
606 417f6b50 Iustin Pop
maybePrintNodes (Just fields) msg fn = do
607 417f6b50 Iustin Pop
  hPutStrLn stderr ""
608 417f6b50 Iustin Pop
  hPutStrLn stderr (msg ++ " status:")
609 417f6b50 Iustin Pop
  hPutStrLn stderr $ fn fields
610 33e44f0c Iustin Pop
611 33e44f0c Iustin Pop
-- | Optionally print the instance list.
612 33e44f0c Iustin Pop
maybePrintInsts :: Bool   -- ^ Whether to print the instance list
613 33e44f0c Iustin Pop
                -> String -- ^ Type of the instance map (e.g. initial)
614 33e44f0c Iustin Pop
                -> String -- ^ The instance data
615 33e44f0c Iustin Pop
                -> IO ()
616 33e44f0c Iustin Pop
maybePrintInsts do_print msg instdata =
617 33e44f0c Iustin Pop
  when do_print $ do
618 33e44f0c Iustin Pop
    hPutStrLn stderr ""
619 33e44f0c Iustin Pop
    hPutStrLn stderr $ msg ++ " instance map:"
620 33e44f0c Iustin Pop
    hPutStr stderr instdata
621 8cd36391 Iustin Pop
622 8cd36391 Iustin Pop
-- | Function to display warning messages from parsing the cluster
623 8cd36391 Iustin Pop
-- state.
624 8cd36391 Iustin Pop
maybeShowWarnings :: [String] -- ^ The warning messages
625 8cd36391 Iustin Pop
                  -> IO ()
626 8cd36391 Iustin Pop
maybeShowWarnings fix_msgs =
627 8cd36391 Iustin Pop
  unless (null fix_msgs) $ do
628 8cd36391 Iustin Pop
    hPutStrLn stderr "Warning: cluster has inconsistent data:"
629 8cd36391 Iustin Pop
    hPutStrLn stderr . unlines . map (printf "  - %s") $ fix_msgs
630 5296ee23 Iustin Pop
631 79eef90b Agata Murawska
-- | Format a list of key, value as a shell fragment.
632 e60fa4af Agata Murawska
printKeys :: String              -- ^ Prefix to printed variables
633 e60fa4af Agata Murawska
          -> [(String, String)]  -- ^ List of (key, value) pairs to be printed
634 e60fa4af Agata Murawska
          -> IO ()
635 51000365 Iustin Pop
printKeys prefix =
636 51000365 Iustin Pop
  mapM_ (\(k, v) ->
637 51000365 Iustin Pop
           printf "%s_%s=%s\n" prefix (map toUpper k) (ensureQuoted v))
638 79eef90b Agata Murawska
639 79eef90b Agata Murawska
-- | Prints the final @OK@ marker in machine readable output.
640 e60fa4af Agata Murawska
printFinal :: String    -- ^ Prefix to printed variable
641 51000365 Iustin Pop
           -> Bool      -- ^ Whether output should be machine readable;
642 51000365 Iustin Pop
                        -- note: if not, there is nothing to print
643 e60fa4af Agata Murawska
           -> IO ()
644 79eef90b Agata Murawska
printFinal prefix True =
645 79eef90b Agata Murawska
  -- this should be the final entry
646 79eef90b Agata Murawska
  printKeys prefix [("OK", "1")]
647 79eef90b Agata Murawska
648 79eef90b Agata Murawska
printFinal _ False = return ()
649 79eef90b Agata Murawska
650 284e9822 Iustin Pop
-- | Potentially set the node as offline based on passed offline list.
651 284e9822 Iustin Pop
setNodeOffline :: [Ndx] -> Node.Node -> Node.Node
652 284e9822 Iustin Pop
setNodeOffline offline_indices n =
653 284e9822 Iustin Pop
  if Node.idx n `elem` offline_indices
654 284e9822 Iustin Pop
    then Node.setOffline n True
655 284e9822 Iustin Pop
    else n
656 284e9822 Iustin Pop
657 5296ee23 Iustin Pop
-- | Set node properties based on command line options.
658 5296ee23 Iustin Pop
setNodeStatus :: Options -> Node.List -> IO Node.List
659 5296ee23 Iustin Pop
setNodeStatus opts fixed_nl = do
660 5296ee23 Iustin Pop
  let offline_passed = optOffline opts
661 5296ee23 Iustin Pop
      all_nodes = Container.elems fixed_nl
662 5296ee23 Iustin Pop
      offline_lkp = map (lookupName (map Node.name all_nodes)) offline_passed
663 5296ee23 Iustin Pop
      offline_wrong = filter (not . goodLookupResult) offline_lkp
664 5296ee23 Iustin Pop
      offline_names = map lrContent offline_lkp
665 5296ee23 Iustin Pop
      offline_indices = map Node.idx $
666 5296ee23 Iustin Pop
                        filter (\n -> Node.name n `elem` offline_names)
667 5296ee23 Iustin Pop
                               all_nodes
668 5296ee23 Iustin Pop
      m_cpu = optMcpu opts
669 5296ee23 Iustin Pop
      m_dsk = optMdsk opts
670 5296ee23 Iustin Pop
671 5b11f8db Iustin Pop
  unless (null offline_wrong) .
672 88a10df5 Iustin Pop
         exitErr $ printf "wrong node name(s) set as offline: %s\n"
673 88a10df5 Iustin Pop
                   (commaJoin (map lrContent offline_wrong))
674 284e9822 Iustin Pop
  let setMCpuFn = case m_cpu of
675 284e9822 Iustin Pop
                    Nothing -> id
676 284e9822 Iustin Pop
                    Just new_mcpu -> flip Node.setMcpu new_mcpu
677 284e9822 Iustin Pop
  let nm = Container.map (setNodeOffline offline_indices .
678 284e9822 Iustin Pop
                          flip Node.setMdsk m_dsk .
679 284e9822 Iustin Pop
                          setMCpuFn) fixed_nl
680 284e9822 Iustin Pop
  return nm