Statistics
| Branch: | Tag: | Revision:

root / htools / Ganeti / HTools / CLI.hs @ 5f828ce4

History | View | Annotate | Download (20.3 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 525bfb36 Iustin Pop
binaries, separated into this module since "Ganeti.HTools.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 a69ff623 Iustin Pop
Copyright (C) 2009, 2010, 2011 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 0427285d Iustin Pop
    ( Options(..)
32 0427285d Iustin Pop
    , OptType
33 75d1edf8 Iustin Pop
    , parseOpts
34 e0eb63f0 Iustin Pop
    , shTemplate
35 ba9349b8 Iustin Pop
    , defaultLuxiSocket
36 417f6b50 Iustin Pop
    , maybePrintNodes
37 33e44f0c Iustin Pop
    , maybePrintInsts
38 8cd36391 Iustin Pop
    , maybeShowWarnings
39 5296ee23 Iustin Pop
    , setNodeStatus
40 0427285d Iustin Pop
    -- * The options
41 16c2369c Iustin Pop
    , oDataFile
42 df18fdfe Iustin Pop
    , oDiskMoves
43 c4bb977b Iustin Pop
    , oDiskTemplate
44 df18fdfe Iustin Pop
    , oDynuFile
45 f0f21ec4 Iustin Pop
    , oEvacMode
46 10f396e1 Iustin Pop
    , oExInst
47 df18fdfe Iustin Pop
    , oExTags
48 0df5a1b4 Iustin Pop
    , oExecJobs
49 a423b510 Iustin Pop
    , oGroup
50 0427285d Iustin Pop
    , oIDisk
51 df18fdfe Iustin Pop
    , oIMem
52 df18fdfe Iustin Pop
    , oIVcpus
53 c4bb977b Iustin Pop
    , oInstMoves
54 df18fdfe Iustin Pop
    , oLuxiSocket
55 519edd9f Iustin Pop
    , oMachineReadable
56 0427285d Iustin Pop
    , oMaxCpu
57 df18fdfe Iustin Pop
    , oMaxSolLength
58 0427285d Iustin Pop
    , oMinDisk
59 4f807a57 Iustin Pop
    , oMinGain
60 4f807a57 Iustin Pop
    , oMinGainLim
61 df18fdfe Iustin Pop
    , oMinScore
62 df18fdfe Iustin Pop
    , oNoHeaders
63 df18fdfe Iustin Pop
    , oNodeSim
64 df18fdfe Iustin Pop
    , oOfflineNode
65 df18fdfe Iustin Pop
    , oOutputDir
66 df18fdfe Iustin Pop
    , oPrintCommands
67 df18fdfe Iustin Pop
    , oPrintInsts
68 df18fdfe Iustin Pop
    , oPrintNodes
69 df18fdfe Iustin Pop
    , oQuiet
70 df18fdfe Iustin Pop
    , oRapiMaster
71 509809db Iustin Pop
    , oReplay
72 02da9d07 Iustin Pop
    , oSaveCluster
73 c4bb977b Iustin Pop
    , oSelInst
74 0427285d Iustin Pop
    , oShowHelp
75 df18fdfe Iustin Pop
    , oShowVer
76 df18fdfe Iustin Pop
    , oTieredSpec
77 df18fdfe Iustin Pop
    , oVerbose
78 209b3711 Iustin Pop
    ) where
79 209b3711 Iustin Pop
80 cc532bdd Iustin Pop
import Control.Monad
81 e8f89bb6 Iustin Pop
import Data.Maybe (fromMaybe)
82 8e445e6d Iustin Pop
import qualified Data.Version
83 209b3711 Iustin Pop
import System.Console.GetOpt
84 209b3711 Iustin Pop
import System.IO
85 209b3711 Iustin Pop
import System.Info
86 209b3711 Iustin Pop
import System
87 5296ee23 Iustin Pop
import Text.Printf (printf, hPrintf)
88 209b3711 Iustin Pop
89 209b3711 Iustin Pop
import qualified Ganeti.HTools.Version as Version(version)
90 5296ee23 Iustin Pop
import qualified Ganeti.HTools.Container as Container
91 5296ee23 Iustin Pop
import qualified Ganeti.HTools.Node as Node
92 a69ff623 Iustin Pop
import qualified Ganeti.Constants as C
93 92e32d76 Iustin Pop
import Ganeti.HTools.Types
94 1f9066c0 Iustin Pop
import Ganeti.HTools.Utils
95 5296ee23 Iustin Pop
import Ganeti.HTools.Loader
96 fae371cc Iustin Pop
97 525bfb36 Iustin Pop
-- * Constants
98 525bfb36 Iustin Pop
99 525bfb36 Iustin Pop
-- | The default value for the luxi socket.
100 525bfb36 Iustin Pop
--
101 525bfb36 Iustin Pop
-- This is re-exported from the "Ganeti.Constants" module.
102 8e445e6d Iustin Pop
defaultLuxiSocket :: FilePath
103 a69ff623 Iustin Pop
defaultLuxiSocket = C.masterSocket
104 8e445e6d Iustin Pop
105 525bfb36 Iustin Pop
-- * Data types
106 525bfb36 Iustin Pop
107 0427285d Iustin Pop
-- | Command line options structure.
108 0427285d Iustin Pop
data Options = Options
109 df18fdfe Iustin Pop
    { optDataFile    :: Maybe FilePath -- ^ Path to the cluster data file
110 df18fdfe Iustin Pop
    , optDiskMoves   :: Bool           -- ^ Allow disk moves
111 8fcfb767 Guido Trotter
    , optInstMoves   :: Bool           -- ^ Allow instance moves
112 c4bb977b Iustin Pop
    , optDiskTemplate :: DiskTemplate  -- ^ The requested disk template
113 df18fdfe Iustin Pop
    , optDynuFile    :: Maybe FilePath -- ^ Optional file with dynamic use data
114 f0f21ec4 Iustin Pop
    , optEvacMode    :: Bool           -- ^ Enable evacuation mode
115 10f396e1 Iustin Pop
    , optExInst      :: [String]       -- ^ Instances to be excluded
116 df18fdfe Iustin Pop
    , optExTags      :: Maybe [String] -- ^ Tags to use for exclusion
117 1f9066c0 Iustin Pop
    , optExecJobs    :: Bool           -- ^ Execute the commands via Luxi
118 a423b510 Iustin Pop
    , optGroup       :: Maybe GroupID  -- ^ The UUID of the group to process
119 ddef0585 Guido Trotter
    , optSelInst     :: [String]       -- ^ Instances to be excluded
120 1f9066c0 Iustin Pop
    , optISpec       :: RSpec          -- ^ Requested instance specs
121 df18fdfe Iustin Pop
    , optLuxi        :: Maybe FilePath -- ^ Collect data from Luxi
122 519edd9f Iustin Pop
    , optMachineReadable :: Bool       -- ^ Output machine-readable format
123 df18fdfe Iustin Pop
    , optMaster      :: String         -- ^ Collect data from RAPI
124 df18fdfe Iustin Pop
    , optMaxLength   :: Int            -- ^ Stop after this many steps
125 1f9066c0 Iustin Pop
    , optMcpu        :: Double         -- ^ Max cpu ratio for nodes
126 1f9066c0 Iustin Pop
    , optMdsk        :: Double         -- ^ Max disk usage ratio for nodes
127 4f807a57 Iustin Pop
    , optMinGain     :: Score          -- ^ Min gain we aim for in a step
128 4f807a57 Iustin Pop
    , optMinGainLim  :: Score          -- ^ Limit below which we apply mingain
129 df18fdfe Iustin Pop
    , optMinScore    :: Score          -- ^ The minimum score we aim for
130 df18fdfe Iustin Pop
    , optNoHeaders   :: Bool           -- ^ Do not show a header line
131 9983063b Iustin Pop
    , optNodeSim     :: [String]       -- ^ Cluster simulation mode
132 df18fdfe Iustin Pop
    , optOffline     :: [String]       -- ^ Names of offline nodes
133 df18fdfe Iustin Pop
    , optOutPath     :: FilePath       -- ^ Path to the output directory
134 02da9d07 Iustin Pop
    , optSaveCluster :: Maybe FilePath -- ^ Save cluster state to this file
135 df18fdfe Iustin Pop
    , optShowCmds    :: Maybe FilePath -- ^ Whether to show the command list
136 1f9066c0 Iustin Pop
    , optShowHelp    :: Bool           -- ^ Just show the help
137 df18fdfe Iustin Pop
    , optShowInsts   :: Bool           -- ^ Whether to show the instance map
138 df18fdfe Iustin Pop
    , optShowNodes   :: Maybe [String] -- ^ Whether to show node status
139 df18fdfe Iustin Pop
    , optShowVer     :: Bool           -- ^ Just show the program version
140 df18fdfe Iustin Pop
    , optTieredSpec  :: Maybe RSpec    -- ^ Requested specs for tiered mode
141 509809db Iustin Pop
    , optReplay      :: Maybe String   -- ^ Unittests: RNG state
142 df18fdfe Iustin Pop
    , optVerbose     :: Int            -- ^ Verbosity level
143 0427285d Iustin Pop
    } deriving Show
144 0427285d Iustin Pop
145 0427285d Iustin Pop
-- | Default values for the command line options.
146 0427285d Iustin Pop
defaultOptions :: Options
147 0427285d Iustin Pop
defaultOptions  = Options
148 df18fdfe Iustin Pop
 { optDataFile    = Nothing
149 df18fdfe Iustin Pop
 , optDiskMoves   = True
150 8fcfb767 Guido Trotter
 , optInstMoves   = True
151 c4bb977b Iustin Pop
 , optDiskTemplate = DTDrbd8
152 df18fdfe Iustin Pop
 , optDynuFile    = Nothing
153 f0f21ec4 Iustin Pop
 , optEvacMode    = False
154 10f396e1 Iustin Pop
 , optExInst      = []
155 df18fdfe Iustin Pop
 , optExTags      = Nothing
156 1f9066c0 Iustin Pop
 , optExecJobs    = False
157 a423b510 Iustin Pop
 , optGroup       = Nothing
158 ddef0585 Guido Trotter
 , optSelInst     = []
159 1f9066c0 Iustin Pop
 , optISpec       = RSpec 1 4096 102400
160 df18fdfe Iustin Pop
 , optLuxi        = Nothing
161 519edd9f Iustin Pop
 , optMachineReadable = False
162 df18fdfe Iustin Pop
 , optMaster      = ""
163 df18fdfe Iustin Pop
 , optMaxLength   = -1
164 f4c0b8c5 Iustin Pop
 , optMcpu        = defVcpuRatio
165 f4c0b8c5 Iustin Pop
 , optMdsk        = defReservedDiskRatio
166 4f807a57 Iustin Pop
 , optMinGain     = 1e-2
167 4f807a57 Iustin Pop
 , optMinGainLim  = 1e-1
168 df18fdfe Iustin Pop
 , optMinScore    = 1e-9
169 df18fdfe Iustin Pop
 , optNoHeaders   = False
170 9983063b Iustin Pop
 , optNodeSim     = []
171 df18fdfe Iustin Pop
 , optOffline     = []
172 df18fdfe Iustin Pop
 , optOutPath     = "."
173 02da9d07 Iustin Pop
 , optSaveCluster = Nothing
174 df18fdfe Iustin Pop
 , optShowCmds    = Nothing
175 1f9066c0 Iustin Pop
 , optShowHelp    = False
176 df18fdfe Iustin Pop
 , optShowInsts   = False
177 df18fdfe Iustin Pop
 , optShowNodes   = Nothing
178 df18fdfe Iustin Pop
 , optShowVer     = False
179 df18fdfe Iustin Pop
 , optTieredSpec  = Nothing
180 509809db Iustin Pop
 , optReplay      = Nothing
181 df18fdfe Iustin Pop
 , optVerbose     = 1
182 0427285d Iustin Pop
 }
183 0427285d Iustin Pop
184 525bfb36 Iustin Pop
-- | Abrreviation for the option type.
185 2f567ac0 Iustin Pop
type OptType = OptDescr (Options -> Result Options)
186 0427285d Iustin Pop
187 525bfb36 Iustin Pop
-- * Command line options
188 525bfb36 Iustin Pop
189 16c2369c Iustin Pop
oDataFile :: OptType
190 16c2369c Iustin Pop
oDataFile = Option "t" ["text-data"]
191 16c2369c Iustin Pop
            (ReqArg (\ f o -> Ok o { optDataFile = Just f }) "FILE")
192 16c2369c Iustin Pop
            "the cluster data FILE"
193 0427285d Iustin Pop
194 df18fdfe Iustin Pop
oDiskMoves :: OptType
195 df18fdfe Iustin Pop
oDiskMoves = Option "" ["no-disk-moves"]
196 df18fdfe Iustin Pop
             (NoArg (\ opts -> Ok opts { optDiskMoves = False}))
197 df18fdfe Iustin Pop
             "disallow disk moves from the list of allowed instance changes,\
198 df18fdfe Iustin Pop
             \ thus allowing only the 'cheap' failover/migrate operations"
199 b2278348 Iustin Pop
200 c4bb977b Iustin Pop
oDiskTemplate :: OptType
201 c4bb977b Iustin Pop
oDiskTemplate = Option "" ["disk-template"]
202 c4bb977b Iustin Pop
                (ReqArg (\ t opts -> do
203 5f828ce4 Agata Murawska
                           dt <- diskTemplateFromRaw t
204 c4bb977b Iustin Pop
                           return $ opts { optDiskTemplate = dt }) "TEMPLATE")
205 c4bb977b Iustin Pop
                "select the desired disk template"
206 c4bb977b Iustin Pop
207 ddef0585 Guido Trotter
oSelInst :: OptType
208 ddef0585 Guido Trotter
oSelInst = Option "" ["select-instances"]
209 ddef0585 Guido Trotter
          (ReqArg (\ f opts -> Ok opts { optSelInst = sepSplit ',' f }) "INSTS")
210 ddef0585 Guido Trotter
          "only select given instances for any moves"
211 ddef0585 Guido Trotter
212 8fcfb767 Guido Trotter
oInstMoves :: OptType
213 8fcfb767 Guido Trotter
oInstMoves = Option "" ["no-instance-moves"]
214 8fcfb767 Guido Trotter
             (NoArg (\ opts -> Ok opts { optInstMoves = False}))
215 8fcfb767 Guido Trotter
             "disallow instance (primary node) moves from the list of allowed,\
216 8fcfb767 Guido Trotter
             \ instance changes, thus allowing only slower, but sometimes\
217 8fcfb767 Guido Trotter
             \ safer, drbd secondary changes"
218 8fcfb767 Guido Trotter
219 df18fdfe Iustin Pop
oDynuFile :: OptType
220 df18fdfe Iustin Pop
oDynuFile = Option "U" ["dynu-file"]
221 df18fdfe Iustin Pop
            (ReqArg (\ f opts -> Ok opts { optDynuFile = Just f }) "FILE")
222 df18fdfe Iustin Pop
            "Import dynamic utilisation data from the given FILE"
223 0427285d Iustin Pop
224 f0f21ec4 Iustin Pop
oEvacMode :: OptType
225 f0f21ec4 Iustin Pop
oEvacMode = Option "E" ["evac-mode"]
226 f0f21ec4 Iustin Pop
            (NoArg (\opts -> Ok opts { optEvacMode = True }))
227 f0f21ec4 Iustin Pop
            "enable evacuation mode, where the algorithm only moves \
228 f0f21ec4 Iustin Pop
            \ instances away from offline and drained nodes"
229 f0f21ec4 Iustin Pop
230 10f396e1 Iustin Pop
oExInst :: OptType
231 10f396e1 Iustin Pop
oExInst = Option "" ["exclude-instances"]
232 10f396e1 Iustin Pop
          (ReqArg (\ f opts -> Ok opts { optExInst = sepSplit ',' f }) "INSTS")
233 6c30ce16 Guido Trotter
          "exclude given instances from any moves"
234 10f396e1 Iustin Pop
235 df18fdfe Iustin Pop
oExTags :: OptType
236 df18fdfe Iustin Pop
oExTags = Option "" ["exclusion-tags"]
237 df18fdfe Iustin Pop
            (ReqArg (\ f opts -> Ok opts { optExTags = Just $ sepSplit ',' f })
238 df18fdfe Iustin Pop
             "TAG,...") "Enable instance exclusion based on given tag prefix"
239 0427285d Iustin Pop
240 0df5a1b4 Iustin Pop
oExecJobs :: OptType
241 0df5a1b4 Iustin Pop
oExecJobs = Option "X" ["exec"]
242 2f567ac0 Iustin Pop
             (NoArg (\ opts -> Ok opts { optExecJobs = True}))
243 0df5a1b4 Iustin Pop
             "execute the suggested moves via Luxi (only available when using\
244 71e635f3 René Nussbaumer
             \ it for data gathering)"
245 0df5a1b4 Iustin Pop
246 a423b510 Iustin Pop
oGroup :: OptType
247 a423b510 Iustin Pop
oGroup = Option "G" ["group"]
248 a423b510 Iustin Pop
            (ReqArg (\ f o -> Ok o { optGroup = Just f }) "ID")
249 a423b510 Iustin Pop
            "the ID of the group to balance"
250 a423b510 Iustin Pop
251 df18fdfe Iustin Pop
oIDisk :: OptType
252 df18fdfe Iustin Pop
oIDisk = Option "" ["disk"]
253 247f77b7 Iustin Pop
         (ReqArg (\ d opts -> do
254 1b0a6356 Iustin Pop
                    dsk <- annotateResult "--disk option" (parseUnit d)
255 247f77b7 Iustin Pop
                    let ospec = optISpec opts
256 247f77b7 Iustin Pop
                        nspec = ospec { rspecDsk = dsk }
257 247f77b7 Iustin Pop
                    return $ opts { optISpec = nspec }) "DISK")
258 df18fdfe Iustin Pop
         "disk size for instances"
259 0427285d Iustin Pop
260 0427285d Iustin Pop
oIMem :: OptType
261 0427285d Iustin Pop
oIMem = Option "" ["memory"]
262 247f77b7 Iustin Pop
        (ReqArg (\ m opts -> do
263 1b0a6356 Iustin Pop
                   mem <- annotateResult "--memory option" (parseUnit m)
264 247f77b7 Iustin Pop
                   let ospec = optISpec opts
265 247f77b7 Iustin Pop
                       nspec = ospec { rspecMem = mem }
266 247f77b7 Iustin Pop
                   return $ opts { optISpec = nspec }) "MEMORY")
267 0427285d Iustin Pop
        "memory size for instances"
268 0427285d Iustin Pop
269 0427285d Iustin Pop
oIVcpus :: OptType
270 0427285d Iustin Pop
oIVcpus = Option "" ["vcpus"]
271 247f77b7 Iustin Pop
          (ReqArg (\ p opts -> do
272 247f77b7 Iustin Pop
                     vcpus <- tryRead "--vcpus option" p
273 247f77b7 Iustin Pop
                     let ospec = optISpec opts
274 247f77b7 Iustin Pop
                         nspec = ospec { rspecCpu = vcpus }
275 247f77b7 Iustin Pop
                     return $ opts { optISpec = nspec }) "NUM")
276 0427285d Iustin Pop
          "number of virtual cpus for instances"
277 0427285d Iustin Pop
278 df18fdfe Iustin Pop
oLuxiSocket :: OptType
279 df18fdfe Iustin Pop
oLuxiSocket = Option "L" ["luxi"]
280 df18fdfe Iustin Pop
              (OptArg ((\ f opts -> Ok opts { optLuxi = Just f }) .
281 df18fdfe Iustin Pop
                       fromMaybe defaultLuxiSocket) "SOCKET")
282 df18fdfe Iustin Pop
              "collect data via Luxi, optionally using the given SOCKET path"
283 0427285d Iustin Pop
284 519edd9f Iustin Pop
oMachineReadable :: OptType
285 519edd9f Iustin Pop
oMachineReadable = Option "" ["machine-readable"]
286 519edd9f Iustin Pop
          (OptArg (\ f opts -> do
287 519edd9f Iustin Pop
                     flag <- parseYesNo True f
288 519edd9f Iustin Pop
                     return $ opts { optMachineReadable = flag }) "CHOICE")
289 519edd9f Iustin Pop
          "enable machine readable output (pass either 'yes' or 'no' to\
290 519edd9f Iustin Pop
          \ explicitely control the flag, or without an argument defaults to\
291 519edd9f Iustin Pop
          \ yes"
292 519edd9f Iustin Pop
293 0427285d Iustin Pop
oMaxCpu :: OptType
294 0427285d Iustin Pop
oMaxCpu = Option "" ["max-cpu"]
295 2f567ac0 Iustin Pop
          (ReqArg (\ n opts -> Ok opts { optMcpu = read n }) "RATIO")
296 f4c0b8c5 Iustin Pop
          "maximum virtual-to-physical cpu ratio for nodes (from 1\
297 f4c0b8c5 Iustin Pop
          \ upwards) [64]"
298 0427285d Iustin Pop
299 df18fdfe Iustin Pop
oMaxSolLength :: OptType
300 df18fdfe Iustin Pop
oMaxSolLength = Option "l" ["max-length"]
301 df18fdfe Iustin Pop
                (ReqArg (\ i opts -> Ok opts { optMaxLength = read i }) "N")
302 b8a2c0ab Iustin Pop
                "cap the solution at this many balancing or allocation \
303 b8a2c0ab Iustin Pop
                \ rounds (useful for very unbalanced clusters or empty \
304 b8a2c0ab Iustin Pop
                \ clusters)"
305 df18fdfe Iustin Pop
306 0427285d Iustin Pop
oMinDisk :: OptType
307 0427285d Iustin Pop
oMinDisk = Option "" ["min-disk"]
308 2f567ac0 Iustin Pop
           (ReqArg (\ n opts -> Ok opts { optMdsk = read n }) "RATIO")
309 f4c0b8c5 Iustin Pop
           "minimum free disk space for nodes (between 0 and 1) [0]"
310 0427285d Iustin Pop
311 4f807a57 Iustin Pop
oMinGain :: OptType
312 4f807a57 Iustin Pop
oMinGain = Option "g" ["min-gain"]
313 4f807a57 Iustin Pop
            (ReqArg (\ g opts -> Ok opts { optMinGain = read g }) "DELTA")
314 4f807a57 Iustin Pop
            "minimum gain to aim for in a balancing step before giving up"
315 4f807a57 Iustin Pop
316 4f807a57 Iustin Pop
oMinGainLim :: OptType
317 4f807a57 Iustin Pop
oMinGainLim = Option "" ["min-gain-limit"]
318 4f807a57 Iustin Pop
            (ReqArg (\ g opts -> Ok opts { optMinGainLim = read g }) "SCORE")
319 4f807a57 Iustin Pop
            "minimum cluster score for which we start checking the min-gain"
320 4f807a57 Iustin Pop
321 df18fdfe Iustin Pop
oMinScore :: OptType
322 df18fdfe Iustin Pop
oMinScore = Option "e" ["min-score"]
323 df18fdfe Iustin Pop
            (ReqArg (\ e opts -> Ok opts { optMinScore = read e }) "EPSILON")
324 4f807a57 Iustin Pop
            "mininum score to aim for"
325 c0501c69 Iustin Pop
326 df18fdfe Iustin Pop
oNoHeaders :: OptType
327 df18fdfe Iustin Pop
oNoHeaders = Option "" ["no-headers"]
328 df18fdfe Iustin Pop
             (NoArg (\ opts -> Ok opts { optNoHeaders = True }))
329 df18fdfe Iustin Pop
             "do not show a header line"
330 4f83a560 Iustin Pop
331 df18fdfe Iustin Pop
oNodeSim :: OptType
332 df18fdfe Iustin Pop
oNodeSim = Option "" ["simulate"]
333 9983063b Iustin Pop
            (ReqArg (\ f o -> Ok o { optNodeSim = f:optNodeSim o }) "SPEC")
334 df18fdfe Iustin Pop
            "simulate an empty cluster, given as 'num_nodes,disk,ram,cpu'"
335 df18fdfe Iustin Pop
336 df18fdfe Iustin Pop
oOfflineNode :: OptType
337 df18fdfe Iustin Pop
oOfflineNode = Option "O" ["offline"]
338 df18fdfe Iustin Pop
               (ReqArg (\ n o -> Ok o { optOffline = n:optOffline o }) "NODE")
339 df18fdfe Iustin Pop
               "set node as offline"
340 df18fdfe Iustin Pop
341 df18fdfe Iustin Pop
oOutputDir :: OptType
342 df18fdfe Iustin Pop
oOutputDir = Option "d" ["output-dir"]
343 df18fdfe Iustin Pop
             (ReqArg (\ d opts -> Ok opts { optOutPath = d }) "PATH")
344 df18fdfe Iustin Pop
             "directory in which to write output files"
345 df18fdfe Iustin Pop
346 df18fdfe Iustin Pop
oPrintCommands :: OptType
347 df18fdfe Iustin Pop
oPrintCommands = Option "C" ["print-commands"]
348 df18fdfe Iustin Pop
                 (OptArg ((\ f opts -> Ok opts { optShowCmds = Just f }) .
349 df18fdfe Iustin Pop
                          fromMaybe "-")
350 df18fdfe Iustin Pop
                  "FILE")
351 df18fdfe Iustin Pop
                 "print the ganeti command list for reaching the solution,\
352 df18fdfe Iustin Pop
                 \ if an argument is passed then write the commands to a\
353 df18fdfe Iustin Pop
                 \ file named as such"
354 df18fdfe Iustin Pop
355 df18fdfe Iustin Pop
oPrintInsts :: OptType
356 df18fdfe Iustin Pop
oPrintInsts = Option "" ["print-instances"]
357 df18fdfe Iustin Pop
              (NoArg (\ opts -> Ok opts { optShowInsts = True }))
358 df18fdfe Iustin Pop
              "print the final instance map"
359 df18fdfe Iustin Pop
360 df18fdfe Iustin Pop
oPrintNodes :: OptType
361 df18fdfe Iustin Pop
oPrintNodes = Option "p" ["print-nodes"]
362 df18fdfe Iustin Pop
              (OptArg ((\ f opts ->
363 6dfa04fd Iustin Pop
                            let (prefix, realf) = case f of
364 6dfa04fd Iustin Pop
                                  '+':rest -> (["+"], rest)
365 6dfa04fd Iustin Pop
                                  _ -> ([], f)
366 6dfa04fd Iustin Pop
                                splitted = prefix ++ sepSplit ',' realf
367 df18fdfe Iustin Pop
                            in Ok opts { optShowNodes = Just splitted }) .
368 df18fdfe Iustin Pop
                       fromMaybe []) "FIELDS")
369 df18fdfe Iustin Pop
              "print the final node list"
370 df18fdfe Iustin Pop
371 df18fdfe Iustin Pop
oQuiet :: OptType
372 df18fdfe Iustin Pop
oQuiet = Option "q" ["quiet"]
373 df18fdfe Iustin Pop
         (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts - 1 }))
374 df18fdfe Iustin Pop
         "decrease the verbosity level"
375 df18fdfe Iustin Pop
376 df18fdfe Iustin Pop
oRapiMaster :: OptType
377 df18fdfe Iustin Pop
oRapiMaster = Option "m" ["master"]
378 df18fdfe Iustin Pop
              (ReqArg (\ m opts -> Ok opts { optMaster = m }) "ADDRESS")
379 df18fdfe Iustin Pop
              "collect data via RAPI at the given ADDRESS"
380 df18fdfe Iustin Pop
381 02da9d07 Iustin Pop
oSaveCluster :: OptType
382 02da9d07 Iustin Pop
oSaveCluster = Option "S" ["save"]
383 02da9d07 Iustin Pop
            (ReqArg (\ f opts -> Ok opts { optSaveCluster = Just f }) "FILE")
384 02da9d07 Iustin Pop
            "Save cluster state at the end of the processing to FILE"
385 02da9d07 Iustin Pop
386 df18fdfe Iustin Pop
oShowHelp :: OptType
387 df18fdfe Iustin Pop
oShowHelp = Option "h" ["help"]
388 df18fdfe Iustin Pop
            (NoArg (\ opts -> Ok opts { optShowHelp = True}))
389 df18fdfe Iustin Pop
            "show help"
390 df18fdfe Iustin Pop
391 df18fdfe Iustin Pop
oShowVer :: OptType
392 df18fdfe Iustin Pop
oShowVer = Option "V" ["version"]
393 df18fdfe Iustin Pop
           (NoArg (\ opts -> Ok opts { optShowVer = True}))
394 df18fdfe Iustin Pop
           "show the version of the program"
395 0f15cc76 Iustin Pop
396 1f9066c0 Iustin Pop
oTieredSpec :: OptType
397 1f9066c0 Iustin Pop
oTieredSpec = Option "" ["tiered-alloc"]
398 1f9066c0 Iustin Pop
             (ReqArg (\ inp opts -> do
399 1f9066c0 Iustin Pop
                          let sp = sepSplit ',' inp
400 247f77b7 Iustin Pop
                          prs <- mapM (\(fn, val) -> fn val) $
401 247f77b7 Iustin Pop
                                 zip [ annotateResult "tiered specs memory" .
402 247f77b7 Iustin Pop
                                       parseUnit
403 247f77b7 Iustin Pop
                                     , annotateResult "tiered specs disk" .
404 247f77b7 Iustin Pop
                                       parseUnit
405 247f77b7 Iustin Pop
                                     , tryRead "tiered specs cpus"
406 247f77b7 Iustin Pop
                                     ] sp
407 1f9066c0 Iustin Pop
                          tspec <-
408 1f9066c0 Iustin Pop
                              case prs of
409 7f4e37f0 Iustin Pop
                                [dsk, ram, cpu] -> return $ RSpec cpu ram dsk
410 03c6d8fa Iustin Pop
                                _ -> Bad $ "Invalid specification: " ++ inp ++
411 03c6d8fa Iustin Pop
                                     ", expected disk,ram,cpu"
412 1f9066c0 Iustin Pop
                          return $ opts { optTieredSpec = Just tspec } )
413 1f9066c0 Iustin Pop
              "TSPEC")
414 7f4e37f0 Iustin Pop
             "enable tiered specs allocation, given as 'disk,ram,cpu'"
415 1f9066c0 Iustin Pop
416 509809db Iustin Pop
oReplay :: OptType
417 509809db Iustin Pop
oReplay = Option "" ["replay"]
418 509809db Iustin Pop
          (ReqArg (\ stat opts -> Ok opts { optReplay = Just stat } ) "STATE")
419 509809db Iustin Pop
          "Pre-seed the random number generator with STATE"
420 509809db Iustin Pop
421 df18fdfe Iustin Pop
oVerbose :: OptType
422 df18fdfe Iustin Pop
oVerbose = Option "v" ["verbose"]
423 df18fdfe Iustin Pop
           (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts + 1 }))
424 df18fdfe Iustin Pop
           "increase the verbosity level"
425 fae371cc Iustin Pop
426 525bfb36 Iustin Pop
-- * Functions
427 525bfb36 Iustin Pop
428 519edd9f Iustin Pop
-- | Helper for parsing a yes\/no command line flag.
429 519edd9f Iustin Pop
parseYesNo :: Bool         -- ^ Default whalue (when we get a @Nothing@)
430 519edd9f Iustin Pop
           -> Maybe String -- ^ Parameter value
431 519edd9f Iustin Pop
           -> Result Bool  -- ^ Resulting boolean value
432 519edd9f Iustin Pop
parseYesNo v Nothing      = return v
433 519edd9f Iustin Pop
parseYesNo _ (Just "yes") = return True
434 519edd9f Iustin Pop
parseYesNo _ (Just "no")  = return False
435 519edd9f Iustin Pop
parseYesNo _ (Just s)     = fail $ "Invalid choice '" ++ s ++
436 519edd9f Iustin Pop
                            "', pass one of 'yes' or 'no'"
437 519edd9f Iustin Pop
438 525bfb36 Iustin Pop
-- | Usage info.
439 0427285d Iustin Pop
usageHelp :: String -> [OptType] -> String
440 9f6dcdea Iustin Pop
usageHelp progname =
441 78694255 Iustin Pop
    usageInfo (printf "%s %s\nUsage: %s [OPTION...]"
442 9f6dcdea Iustin Pop
               progname Version.version progname)
443 78694255 Iustin Pop
444 525bfb36 Iustin Pop
-- | Command line parser, using the 'Options' structure.
445 0427285d Iustin Pop
parseOpts :: [String]               -- ^ The command line arguments
446 0427285d Iustin Pop
          -> String                 -- ^ The program name
447 0427285d Iustin Pop
          -> [OptType]              -- ^ The supported command line options
448 0427285d Iustin Pop
          -> IO (Options, [String]) -- ^ The resulting options and leftover
449 0427285d Iustin Pop
                                    -- arguments
450 0427285d Iustin Pop
parseOpts argv progname options =
451 209b3711 Iustin Pop
    case getOpt Permute options argv of
452 209b3711 Iustin Pop
      (o, n, []) ->
453 209b3711 Iustin Pop
          do
454 2f567ac0 Iustin Pop
            let (pr, args) = (foldM (flip id) defaultOptions o, n)
455 2f567ac0 Iustin Pop
            po <- (case pr of
456 2f567ac0 Iustin Pop
                     Bad msg -> do
457 2f567ac0 Iustin Pop
                       hPutStrLn stderr "Error while parsing command\
458 2f567ac0 Iustin Pop
                                        \line arguments:"
459 2f567ac0 Iustin Pop
                       hPutStrLn stderr msg
460 2f567ac0 Iustin Pop
                       exitWith $ ExitFailure 1
461 2f567ac0 Iustin Pop
                     Ok val -> return val)
462 0427285d Iustin Pop
            when (optShowHelp po) $ do
463 78694255 Iustin Pop
              putStr $ usageHelp progname options
464 209b3711 Iustin Pop
              exitWith ExitSuccess
465 0427285d Iustin Pop
            when (optShowVer po) $ do
466 75d1edf8 Iustin Pop
              printf "%s %s\ncompiled with %s %s\nrunning on %s %s\n"
467 75d1edf8 Iustin Pop
                     progname Version.version
468 75d1edf8 Iustin Pop
                     compilerName (Data.Version.showVersion compilerVersion)
469 c939b58e Iustin Pop
                     os arch :: IO ()
470 75d1edf8 Iustin Pop
              exitWith ExitSuccess
471 2f567ac0 Iustin Pop
            return (po, args)
472 f723de38 Iustin Pop
      (_, _, errs) -> do
473 f723de38 Iustin Pop
        hPutStrLn stderr $ "Command line error: "  ++ concat errs
474 f723de38 Iustin Pop
        hPutStrLn stderr $ usageHelp progname options
475 f723de38 Iustin Pop
        exitWith $ ExitFailure 2
476 209b3711 Iustin Pop
477 9188aeef Iustin Pop
-- | A shell script template for autogenerated scripts.
478 e0eb63f0 Iustin Pop
shTemplate :: String
479 e0eb63f0 Iustin Pop
shTemplate =
480 e0eb63f0 Iustin Pop
    printf "#!/bin/sh\n\n\
481 e0eb63f0 Iustin Pop
           \# Auto-generated script for executing cluster rebalancing\n\n\
482 e0eb63f0 Iustin Pop
           \# To stop, touch the file /tmp/stop-htools\n\n\
483 e0eb63f0 Iustin Pop
           \set -e\n\n\
484 e0eb63f0 Iustin Pop
           \check() {\n\
485 e0eb63f0 Iustin Pop
           \  if [ -f /tmp/stop-htools ]; then\n\
486 e0eb63f0 Iustin Pop
           \    echo 'Stop requested, exiting'\n\
487 e0eb63f0 Iustin Pop
           \    exit 0\n\
488 e0eb63f0 Iustin Pop
           \  fi\n\
489 e0eb63f0 Iustin Pop
           \}\n\n"
490 417f6b50 Iustin Pop
491 417f6b50 Iustin Pop
-- | Optionally print the node list.
492 417f6b50 Iustin Pop
maybePrintNodes :: Maybe [String]       -- ^ The field list
493 417f6b50 Iustin Pop
                -> String               -- ^ Informational message
494 417f6b50 Iustin Pop
                -> ([String] -> String) -- ^ Function to generate the listing
495 417f6b50 Iustin Pop
                -> IO ()
496 417f6b50 Iustin Pop
maybePrintNodes Nothing _ _ = return ()
497 417f6b50 Iustin Pop
maybePrintNodes (Just fields) msg fn = do
498 417f6b50 Iustin Pop
  hPutStrLn stderr ""
499 417f6b50 Iustin Pop
  hPutStrLn stderr (msg ++ " status:")
500 417f6b50 Iustin Pop
  hPutStrLn stderr $ fn fields
501 33e44f0c Iustin Pop
502 33e44f0c Iustin Pop
503 33e44f0c Iustin Pop
-- | Optionally print the instance list.
504 33e44f0c Iustin Pop
maybePrintInsts :: Bool   -- ^ Whether to print the instance list
505 33e44f0c Iustin Pop
                -> String -- ^ Type of the instance map (e.g. initial)
506 33e44f0c Iustin Pop
                -> String -- ^ The instance data
507 33e44f0c Iustin Pop
                -> IO ()
508 33e44f0c Iustin Pop
maybePrintInsts do_print msg instdata =
509 33e44f0c Iustin Pop
  when do_print $ do
510 33e44f0c Iustin Pop
    hPutStrLn stderr ""
511 33e44f0c Iustin Pop
    hPutStrLn stderr $ msg ++ " instance map:"
512 33e44f0c Iustin Pop
    hPutStr stderr instdata
513 8cd36391 Iustin Pop
514 8cd36391 Iustin Pop
-- | Function to display warning messages from parsing the cluster
515 8cd36391 Iustin Pop
-- state.
516 8cd36391 Iustin Pop
maybeShowWarnings :: [String] -- ^ The warning messages
517 8cd36391 Iustin Pop
                  -> IO ()
518 8cd36391 Iustin Pop
maybeShowWarnings fix_msgs =
519 8cd36391 Iustin Pop
  unless (null fix_msgs) $ do
520 8cd36391 Iustin Pop
    hPutStrLn stderr "Warning: cluster has inconsistent data:"
521 8cd36391 Iustin Pop
    hPutStrLn stderr . unlines . map (printf "  - %s") $ fix_msgs
522 5296ee23 Iustin Pop
523 5296ee23 Iustin Pop
-- | Set node properties based on command line options.
524 5296ee23 Iustin Pop
setNodeStatus :: Options -> Node.List -> IO Node.List
525 5296ee23 Iustin Pop
setNodeStatus opts fixed_nl = do
526 5296ee23 Iustin Pop
  let offline_passed = optOffline opts
527 5296ee23 Iustin Pop
      all_nodes = Container.elems fixed_nl
528 5296ee23 Iustin Pop
      offline_lkp = map (lookupName (map Node.name all_nodes)) offline_passed
529 5296ee23 Iustin Pop
      offline_wrong = filter (not . goodLookupResult) offline_lkp
530 5296ee23 Iustin Pop
      offline_names = map lrContent offline_lkp
531 5296ee23 Iustin Pop
      offline_indices = map Node.idx $
532 5296ee23 Iustin Pop
                        filter (\n -> Node.name n `elem` offline_names)
533 5296ee23 Iustin Pop
                               all_nodes
534 5296ee23 Iustin Pop
      m_cpu = optMcpu opts
535 5296ee23 Iustin Pop
      m_dsk = optMdsk opts
536 5296ee23 Iustin Pop
537 5296ee23 Iustin Pop
  when (not (null offline_wrong)) $ do
538 5296ee23 Iustin Pop
         hPrintf stderr "Error: Wrong node name(s) set as offline: %s\n"
539 5296ee23 Iustin Pop
                     (commaJoin (map lrContent offline_wrong)) :: IO ()
540 5296ee23 Iustin Pop
         exitWith $ ExitFailure 1
541 5296ee23 Iustin Pop
542 5296ee23 Iustin Pop
  let nm = Container.map (\n -> if Node.idx n `elem` offline_indices
543 5296ee23 Iustin Pop
                                then Node.setOffline n True
544 5296ee23 Iustin Pop
                                else n) fixed_nl
545 5296ee23 Iustin Pop
      nlf = Container.map (flip Node.setMdsk m_dsk . flip Node.setMcpu m_cpu)
546 5296ee23 Iustin Pop
            nm
547 5296ee23 Iustin Pop
  return nlf