Statistics
| Branch: | Tag: | Revision:

root / htools / Ganeti / HTools / CLI.hs @ 2ef8013f

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