Statistics
| Branch: | Tag: | Revision:

root / htools / Ganeti / HTools / CLI.hs @ e19ee6e4

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