Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / CLI.hs @ f4c0b8c5

History | View | Annotate | Download (13.8 kB)

1 209b3711 Iustin Pop
{-| Implementation of command-line functions.
2 209b3711 Iustin Pop
3 209b3711 Iustin Pop
This module holds the common cli-related functions for the binaries,
4 209b3711 Iustin Pop
separated into this module since Utils.hs is used in many other places
5 6ef35e3c Iustin Pop
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 e2fa2baf Iustin Pop
Copyright (C) 2009 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 0427285d Iustin Pop
    -- * The options
37 16c2369c Iustin Pop
    , oDataFile
38 df18fdfe Iustin Pop
    , oDiskMoves
39 df18fdfe Iustin Pop
    , oDynuFile
40 f0f21ec4 Iustin Pop
    , oEvacMode
41 10f396e1 Iustin Pop
    , oExInst
42 df18fdfe Iustin Pop
    , oExTags
43 0df5a1b4 Iustin Pop
    , oExecJobs
44 0427285d Iustin Pop
    , oIDisk
45 df18fdfe Iustin Pop
    , oIMem
46 0427285d Iustin Pop
    , oINodes
47 df18fdfe Iustin Pop
    , oIVcpus
48 df18fdfe Iustin Pop
    , oLuxiSocket
49 0427285d Iustin Pop
    , oMaxCpu
50 df18fdfe Iustin Pop
    , oMaxSolLength
51 0427285d Iustin Pop
    , oMinDisk
52 df18fdfe Iustin Pop
    , oMinScore
53 df18fdfe Iustin Pop
    , oNoHeaders
54 df18fdfe Iustin Pop
    , oNodeSim
55 df18fdfe Iustin Pop
    , oOfflineNode
56 df18fdfe Iustin Pop
    , oOneline
57 df18fdfe Iustin Pop
    , oOutputDir
58 df18fdfe Iustin Pop
    , oPrintCommands
59 df18fdfe Iustin Pop
    , oPrintInsts
60 df18fdfe Iustin Pop
    , oPrintNodes
61 df18fdfe Iustin Pop
    , oQuiet
62 df18fdfe Iustin Pop
    , oRapiMaster
63 0427285d Iustin Pop
    , oShowHelp
64 df18fdfe Iustin Pop
    , oShowVer
65 df18fdfe Iustin Pop
    , oTieredSpec
66 df18fdfe Iustin Pop
    , oVerbose
67 209b3711 Iustin Pop
    ) where
68 209b3711 Iustin Pop
69 e8f89bb6 Iustin Pop
import Data.Maybe (fromMaybe)
70 8e445e6d Iustin Pop
import qualified Data.Version
71 8e445e6d Iustin Pop
import Monad
72 209b3711 Iustin Pop
import System.Console.GetOpt
73 209b3711 Iustin Pop
import System.IO
74 209b3711 Iustin Pop
import System.Info
75 209b3711 Iustin Pop
import System
76 e8f89bb6 Iustin Pop
import Text.Printf (printf)
77 209b3711 Iustin Pop
78 209b3711 Iustin Pop
import qualified Ganeti.HTools.Version as Version(version)
79 92e32d76 Iustin Pop
import Ganeti.HTools.Types
80 1f9066c0 Iustin Pop
import Ganeti.HTools.Utils
81 fae371cc Iustin Pop
82 8e445e6d Iustin Pop
-- | The default value for the luxi socket
83 8e445e6d Iustin Pop
defaultLuxiSocket :: FilePath
84 8e445e6d Iustin Pop
defaultLuxiSocket = "/var/run/ganeti/socket/ganeti-master"
85 8e445e6d Iustin Pop
86 0427285d Iustin Pop
-- | Command line options structure.
87 0427285d Iustin Pop
data Options = Options
88 df18fdfe Iustin Pop
    { optDataFile    :: Maybe FilePath -- ^ Path to the cluster data file
89 df18fdfe Iustin Pop
    , optDiskMoves   :: Bool           -- ^ Allow disk moves
90 df18fdfe Iustin Pop
    , optDynuFile    :: Maybe FilePath -- ^ Optional file with dynamic use data
91 f0f21ec4 Iustin Pop
    , optEvacMode    :: Bool           -- ^ Enable evacuation mode
92 10f396e1 Iustin Pop
    , optExInst      :: [String]       -- ^ Instances to be excluded
93 df18fdfe Iustin Pop
    , optExTags      :: Maybe [String] -- ^ Tags to use for exclusion
94 1f9066c0 Iustin Pop
    , optExecJobs    :: Bool           -- ^ Execute the commands via Luxi
95 1f9066c0 Iustin Pop
    , optINodes      :: Int            -- ^ Nodes required for an instance
96 1f9066c0 Iustin Pop
    , optISpec       :: RSpec          -- ^ Requested instance specs
97 df18fdfe Iustin Pop
    , optLuxi        :: Maybe FilePath -- ^ Collect data from Luxi
98 df18fdfe Iustin Pop
    , optMaster      :: String         -- ^ Collect data from RAPI
99 df18fdfe Iustin Pop
    , optMaxLength   :: Int            -- ^ Stop after this many steps
100 1f9066c0 Iustin Pop
    , optMcpu        :: Double         -- ^ Max cpu ratio for nodes
101 1f9066c0 Iustin Pop
    , optMdsk        :: Double         -- ^ Max disk usage ratio for nodes
102 df18fdfe Iustin Pop
    , optMinScore    :: Score          -- ^ The minimum score we aim for
103 df18fdfe Iustin Pop
    , optNoHeaders   :: Bool           -- ^ Do not show a header line
104 df18fdfe Iustin Pop
    , optNodeSim     :: Maybe String   -- ^ Cluster simulation mode
105 df18fdfe Iustin Pop
    , optOffline     :: [String]       -- ^ Names of offline nodes
106 df18fdfe Iustin Pop
    , optOneline     :: Bool           -- ^ Switch output to a single line
107 df18fdfe Iustin Pop
    , optOutPath     :: FilePath       -- ^ Path to the output directory
108 df18fdfe Iustin Pop
    , optShowCmds    :: Maybe FilePath -- ^ Whether to show the command list
109 1f9066c0 Iustin Pop
    , optShowHelp    :: Bool           -- ^ Just show the help
110 df18fdfe Iustin Pop
    , optShowInsts   :: Bool           -- ^ Whether to show the instance map
111 df18fdfe Iustin Pop
    , optShowNodes   :: Maybe [String] -- ^ Whether to show node status
112 df18fdfe Iustin Pop
    , optShowVer     :: Bool           -- ^ Just show the program version
113 df18fdfe Iustin Pop
    , optTieredSpec  :: Maybe RSpec    -- ^ Requested specs for tiered mode
114 df18fdfe Iustin Pop
    , optVerbose     :: Int            -- ^ Verbosity level
115 0427285d Iustin Pop
    } deriving Show
116 0427285d Iustin Pop
117 0427285d Iustin Pop
-- | Default values for the command line options.
118 0427285d Iustin Pop
defaultOptions :: Options
119 0427285d Iustin Pop
defaultOptions  = Options
120 df18fdfe Iustin Pop
 { optDataFile    = Nothing
121 df18fdfe Iustin Pop
 , optDiskMoves   = True
122 df18fdfe Iustin Pop
 , optDynuFile    = Nothing
123 f0f21ec4 Iustin Pop
 , optEvacMode    = False
124 10f396e1 Iustin Pop
 , optExInst      = []
125 df18fdfe Iustin Pop
 , optExTags      = Nothing
126 1f9066c0 Iustin Pop
 , optExecJobs    = False
127 1f9066c0 Iustin Pop
 , optINodes      = 2
128 1f9066c0 Iustin Pop
 , optISpec       = RSpec 1 4096 102400
129 df18fdfe Iustin Pop
 , optLuxi        = Nothing
130 df18fdfe Iustin Pop
 , optMaster      = ""
131 df18fdfe Iustin Pop
 , optMaxLength   = -1
132 f4c0b8c5 Iustin Pop
 , optMcpu        = defVcpuRatio
133 f4c0b8c5 Iustin Pop
 , optMdsk        = defReservedDiskRatio
134 df18fdfe Iustin Pop
 , optMinScore    = 1e-9
135 df18fdfe Iustin Pop
 , optNoHeaders   = False
136 df18fdfe Iustin Pop
 , optNodeSim     = Nothing
137 df18fdfe Iustin Pop
 , optOffline     = []
138 df18fdfe Iustin Pop
 , optOneline     = False
139 df18fdfe Iustin Pop
 , optOutPath     = "."
140 df18fdfe Iustin Pop
 , optShowCmds    = Nothing
141 1f9066c0 Iustin Pop
 , optShowHelp    = False
142 df18fdfe Iustin Pop
 , optShowInsts   = False
143 df18fdfe Iustin Pop
 , optShowNodes   = Nothing
144 df18fdfe Iustin Pop
 , optShowVer     = False
145 df18fdfe Iustin Pop
 , optTieredSpec  = Nothing
146 df18fdfe Iustin Pop
 , optVerbose     = 1
147 0427285d Iustin Pop
 }
148 0427285d Iustin Pop
149 0427285d Iustin Pop
-- | Abrreviation for the option type
150 2f567ac0 Iustin Pop
type OptType = OptDescr (Options -> Result Options)
151 0427285d Iustin Pop
152 16c2369c Iustin Pop
oDataFile :: OptType
153 16c2369c Iustin Pop
oDataFile = Option "t" ["text-data"]
154 16c2369c Iustin Pop
            (ReqArg (\ f o -> Ok o { optDataFile = Just f }) "FILE")
155 16c2369c Iustin Pop
            "the cluster data FILE"
156 0427285d Iustin Pop
157 df18fdfe Iustin Pop
oDiskMoves :: OptType
158 df18fdfe Iustin Pop
oDiskMoves = Option "" ["no-disk-moves"]
159 df18fdfe Iustin Pop
             (NoArg (\ opts -> Ok opts { optDiskMoves = False}))
160 df18fdfe Iustin Pop
             "disallow disk moves from the list of allowed instance changes,\
161 df18fdfe Iustin Pop
             \ thus allowing only the 'cheap' failover/migrate operations"
162 b2278348 Iustin Pop
163 df18fdfe Iustin Pop
oDynuFile :: OptType
164 df18fdfe Iustin Pop
oDynuFile = Option "U" ["dynu-file"]
165 df18fdfe Iustin Pop
            (ReqArg (\ f opts -> Ok opts { optDynuFile = Just f }) "FILE")
166 df18fdfe Iustin Pop
            "Import dynamic utilisation data from the given FILE"
167 0427285d Iustin Pop
168 f0f21ec4 Iustin Pop
oEvacMode :: OptType
169 f0f21ec4 Iustin Pop
oEvacMode = Option "E" ["evac-mode"]
170 f0f21ec4 Iustin Pop
            (NoArg (\opts -> Ok opts { optEvacMode = True }))
171 f0f21ec4 Iustin Pop
            "enable evacuation mode, where the algorithm only moves \
172 f0f21ec4 Iustin Pop
            \ instances away from offline and drained nodes"
173 f0f21ec4 Iustin Pop
174 10f396e1 Iustin Pop
oExInst :: OptType
175 10f396e1 Iustin Pop
oExInst = Option "" ["exclude-instances"]
176 10f396e1 Iustin Pop
          (ReqArg (\ f opts -> Ok opts { optExInst = sepSplit ',' f }) "INSTS")
177 10f396e1 Iustin Pop
          "exclude given instances  from any moves"
178 10f396e1 Iustin Pop
179 df18fdfe Iustin Pop
oExTags :: OptType
180 df18fdfe Iustin Pop
oExTags = Option "" ["exclusion-tags"]
181 df18fdfe Iustin Pop
            (ReqArg (\ f opts -> Ok opts { optExTags = Just $ sepSplit ',' f })
182 df18fdfe Iustin Pop
             "TAG,...") "Enable instance exclusion based on given tag prefix"
183 0427285d Iustin Pop
184 0df5a1b4 Iustin Pop
oExecJobs :: OptType
185 0df5a1b4 Iustin Pop
oExecJobs = Option "X" ["exec"]
186 2f567ac0 Iustin Pop
             (NoArg (\ opts -> Ok opts { optExecJobs = True}))
187 0df5a1b4 Iustin Pop
             "execute the suggested moves via Luxi (only available when using\
188 71e635f3 René Nussbaumer
             \ it for data gathering)"
189 0df5a1b4 Iustin Pop
190 df18fdfe Iustin Pop
oIDisk :: OptType
191 df18fdfe Iustin Pop
oIDisk = Option "" ["disk"]
192 df18fdfe Iustin Pop
         (ReqArg (\ d opts ->
193 df18fdfe Iustin Pop
                     let ospec = optISpec opts
194 df18fdfe Iustin Pop
                         nspec = ospec { rspecDsk = read d }
195 df18fdfe Iustin Pop
                     in Ok opts { optISpec = nspec }) "DISK")
196 df18fdfe Iustin Pop
         "disk size for instances"
197 0427285d Iustin Pop
198 0427285d Iustin Pop
oIMem :: OptType
199 0427285d Iustin Pop
oIMem = Option "" ["memory"]
200 1f9066c0 Iustin Pop
        (ReqArg (\ m opts ->
201 1f9066c0 Iustin Pop
                     let ospec = optISpec opts
202 1f9066c0 Iustin Pop
                         nspec = ospec { rspecMem = read m }
203 1f9066c0 Iustin Pop
                     in Ok opts { optISpec = nspec }) "MEMORY")
204 0427285d Iustin Pop
        "memory size for instances"
205 0427285d Iustin Pop
206 df18fdfe Iustin Pop
oINodes :: OptType
207 df18fdfe Iustin Pop
oINodes = Option "" ["req-nodes"]
208 df18fdfe Iustin Pop
          (ReqArg (\ n opts -> Ok opts { optINodes = read n }) "NODES")
209 df18fdfe Iustin Pop
          "number of nodes for the new instances (1=plain, 2=mirrored)"
210 0427285d Iustin Pop
211 0427285d Iustin Pop
oIVcpus :: OptType
212 0427285d Iustin Pop
oIVcpus = Option "" ["vcpus"]
213 1f9066c0 Iustin Pop
          (ReqArg (\ p opts ->
214 1f9066c0 Iustin Pop
                       let ospec = optISpec opts
215 1f9066c0 Iustin Pop
                           nspec = ospec { rspecCpu = read p }
216 1f9066c0 Iustin Pop
                       in Ok opts { optISpec = nspec }) "NUM")
217 0427285d Iustin Pop
          "number of virtual cpus for instances"
218 0427285d Iustin Pop
219 df18fdfe Iustin Pop
oLuxiSocket :: OptType
220 df18fdfe Iustin Pop
oLuxiSocket = Option "L" ["luxi"]
221 df18fdfe Iustin Pop
              (OptArg ((\ f opts -> Ok opts { optLuxi = Just f }) .
222 df18fdfe Iustin Pop
                       fromMaybe defaultLuxiSocket) "SOCKET")
223 df18fdfe Iustin Pop
              "collect data via Luxi, optionally using the given SOCKET path"
224 0427285d Iustin Pop
225 0427285d Iustin Pop
oMaxCpu :: OptType
226 0427285d Iustin Pop
oMaxCpu = Option "" ["max-cpu"]
227 2f567ac0 Iustin Pop
          (ReqArg (\ n opts -> Ok opts { optMcpu = read n }) "RATIO")
228 f4c0b8c5 Iustin Pop
          "maximum virtual-to-physical cpu ratio for nodes (from 1\
229 f4c0b8c5 Iustin Pop
          \ upwards) [64]"
230 0427285d Iustin Pop
231 df18fdfe Iustin Pop
oMaxSolLength :: OptType
232 df18fdfe Iustin Pop
oMaxSolLength = Option "l" ["max-length"]
233 df18fdfe Iustin Pop
                (ReqArg (\ i opts -> Ok opts { optMaxLength = read i }) "N")
234 df18fdfe Iustin Pop
                "cap the solution at this many moves (useful for very\
235 df18fdfe Iustin Pop
                \ unbalanced clusters)"
236 df18fdfe Iustin Pop
237 0427285d Iustin Pop
oMinDisk :: OptType
238 0427285d Iustin Pop
oMinDisk = Option "" ["min-disk"]
239 2f567ac0 Iustin Pop
           (ReqArg (\ n opts -> Ok opts { optMdsk = read n }) "RATIO")
240 f4c0b8c5 Iustin Pop
           "minimum free disk space for nodes (between 0 and 1) [0]"
241 0427285d Iustin Pop
242 df18fdfe Iustin Pop
oMinScore :: OptType
243 df18fdfe Iustin Pop
oMinScore = Option "e" ["min-score"]
244 df18fdfe Iustin Pop
            (ReqArg (\ e opts -> Ok opts { optMinScore = read e }) "EPSILON")
245 df18fdfe Iustin Pop
            " mininum score to aim for"
246 c0501c69 Iustin Pop
247 df18fdfe Iustin Pop
oNoHeaders :: OptType
248 df18fdfe Iustin Pop
oNoHeaders = Option "" ["no-headers"]
249 df18fdfe Iustin Pop
             (NoArg (\ opts -> Ok opts { optNoHeaders = True }))
250 df18fdfe Iustin Pop
             "do not show a header line"
251 4f83a560 Iustin Pop
252 df18fdfe Iustin Pop
oNodeSim :: OptType
253 df18fdfe Iustin Pop
oNodeSim = Option "" ["simulate"]
254 df18fdfe Iustin Pop
            (ReqArg (\ f o -> Ok o { optNodeSim = Just f }) "SPEC")
255 df18fdfe Iustin Pop
            "simulate an empty cluster, given as 'num_nodes,disk,ram,cpu'"
256 df18fdfe Iustin Pop
257 df18fdfe Iustin Pop
oOfflineNode :: OptType
258 df18fdfe Iustin Pop
oOfflineNode = Option "O" ["offline"]
259 df18fdfe Iustin Pop
               (ReqArg (\ n o -> Ok o { optOffline = n:optOffline o }) "NODE")
260 df18fdfe Iustin Pop
               "set node as offline"
261 df18fdfe Iustin Pop
262 df18fdfe Iustin Pop
oOneline :: OptType
263 df18fdfe Iustin Pop
oOneline = Option "o" ["oneline"]
264 df18fdfe Iustin Pop
           (NoArg (\ opts -> Ok opts { optOneline = True }))
265 df18fdfe Iustin Pop
           "print the ganeti command list for reaching the solution"
266 df18fdfe Iustin Pop
267 df18fdfe Iustin Pop
oOutputDir :: OptType
268 df18fdfe Iustin Pop
oOutputDir = Option "d" ["output-dir"]
269 df18fdfe Iustin Pop
             (ReqArg (\ d opts -> Ok opts { optOutPath = d }) "PATH")
270 df18fdfe Iustin Pop
             "directory in which to write output files"
271 df18fdfe Iustin Pop
272 df18fdfe Iustin Pop
oPrintCommands :: OptType
273 df18fdfe Iustin Pop
oPrintCommands = Option "C" ["print-commands"]
274 df18fdfe Iustin Pop
                 (OptArg ((\ f opts -> Ok opts { optShowCmds = Just f }) .
275 df18fdfe Iustin Pop
                          fromMaybe "-")
276 df18fdfe Iustin Pop
                  "FILE")
277 df18fdfe Iustin Pop
                 "print the ganeti command list for reaching the solution,\
278 df18fdfe Iustin Pop
                 \ if an argument is passed then write the commands to a\
279 df18fdfe Iustin Pop
                 \ file named as such"
280 df18fdfe Iustin Pop
281 df18fdfe Iustin Pop
oPrintInsts :: OptType
282 df18fdfe Iustin Pop
oPrintInsts = Option "" ["print-instances"]
283 df18fdfe Iustin Pop
              (NoArg (\ opts -> Ok opts { optShowInsts = True }))
284 df18fdfe Iustin Pop
              "print the final instance map"
285 df18fdfe Iustin Pop
286 df18fdfe Iustin Pop
oPrintNodes :: OptType
287 df18fdfe Iustin Pop
oPrintNodes = Option "p" ["print-nodes"]
288 df18fdfe Iustin Pop
              (OptArg ((\ f opts ->
289 df18fdfe Iustin Pop
                            let splitted = sepSplit ',' f
290 df18fdfe Iustin Pop
                            in Ok opts { optShowNodes = Just splitted }) .
291 df18fdfe Iustin Pop
                       fromMaybe []) "FIELDS")
292 df18fdfe Iustin Pop
              "print the final node list"
293 df18fdfe Iustin Pop
294 df18fdfe Iustin Pop
oQuiet :: OptType
295 df18fdfe Iustin Pop
oQuiet = Option "q" ["quiet"]
296 df18fdfe Iustin Pop
         (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts - 1 }))
297 df18fdfe Iustin Pop
         "decrease the verbosity level"
298 df18fdfe Iustin Pop
299 df18fdfe Iustin Pop
oRapiMaster :: OptType
300 df18fdfe Iustin Pop
oRapiMaster = Option "m" ["master"]
301 df18fdfe Iustin Pop
              (ReqArg (\ m opts -> Ok opts { optMaster = m }) "ADDRESS")
302 df18fdfe Iustin Pop
              "collect data via RAPI at the given ADDRESS"
303 df18fdfe Iustin Pop
304 df18fdfe Iustin Pop
oShowHelp :: OptType
305 df18fdfe Iustin Pop
oShowHelp = Option "h" ["help"]
306 df18fdfe Iustin Pop
            (NoArg (\ opts -> Ok opts { optShowHelp = True}))
307 df18fdfe Iustin Pop
            "show help"
308 df18fdfe Iustin Pop
309 df18fdfe Iustin Pop
oShowVer :: OptType
310 df18fdfe Iustin Pop
oShowVer = Option "V" ["version"]
311 df18fdfe Iustin Pop
           (NoArg (\ opts -> Ok opts { optShowVer = True}))
312 df18fdfe Iustin Pop
           "show the version of the program"
313 0f15cc76 Iustin Pop
314 1f9066c0 Iustin Pop
oTieredSpec :: OptType
315 1f9066c0 Iustin Pop
oTieredSpec = Option "" ["tiered-alloc"]
316 1f9066c0 Iustin Pop
             (ReqArg (\ inp opts -> do
317 1f9066c0 Iustin Pop
                          let sp = sepSplit ',' inp
318 1f9066c0 Iustin Pop
                          prs <- mapM (tryRead "tiered specs") sp
319 1f9066c0 Iustin Pop
                          tspec <-
320 1f9066c0 Iustin Pop
                              case prs of
321 7f4e37f0 Iustin Pop
                                [dsk, ram, cpu] -> return $ RSpec cpu ram dsk
322 1f9066c0 Iustin Pop
                                _ -> Bad $ "Invalid specification: " ++ inp
323 1f9066c0 Iustin Pop
                          return $ opts { optTieredSpec = Just tspec } )
324 1f9066c0 Iustin Pop
              "TSPEC")
325 7f4e37f0 Iustin Pop
             "enable tiered specs allocation, given as 'disk,ram,cpu'"
326 1f9066c0 Iustin Pop
327 df18fdfe Iustin Pop
oVerbose :: OptType
328 df18fdfe Iustin Pop
oVerbose = Option "v" ["verbose"]
329 df18fdfe Iustin Pop
           (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts + 1 }))
330 df18fdfe Iustin Pop
           "increase the verbosity level"
331 fae371cc Iustin Pop
332 78694255 Iustin Pop
-- | Usage info
333 0427285d Iustin Pop
usageHelp :: String -> [OptType] -> String
334 9f6dcdea Iustin Pop
usageHelp progname =
335 78694255 Iustin Pop
    usageInfo (printf "%s %s\nUsage: %s [OPTION...]"
336 9f6dcdea Iustin Pop
               progname Version.version progname)
337 78694255 Iustin Pop
338 209b3711 Iustin Pop
-- | Command line parser, using the 'options' structure.
339 0427285d Iustin Pop
parseOpts :: [String]               -- ^ The command line arguments
340 0427285d Iustin Pop
          -> String                 -- ^ The program name
341 0427285d Iustin Pop
          -> [OptType]              -- ^ The supported command line options
342 0427285d Iustin Pop
          -> IO (Options, [String]) -- ^ The resulting options and leftover
343 0427285d Iustin Pop
                                    -- arguments
344 0427285d Iustin Pop
parseOpts argv progname options =
345 209b3711 Iustin Pop
    case getOpt Permute options argv of
346 209b3711 Iustin Pop
      (o, n, []) ->
347 209b3711 Iustin Pop
          do
348 2f567ac0 Iustin Pop
            let (pr, args) = (foldM (flip id) defaultOptions o, n)
349 2f567ac0 Iustin Pop
            po <- (case pr of
350 2f567ac0 Iustin Pop
                     Bad msg -> do
351 2f567ac0 Iustin Pop
                       hPutStrLn stderr "Error while parsing command\
352 2f567ac0 Iustin Pop
                                        \line arguments:"
353 2f567ac0 Iustin Pop
                       hPutStrLn stderr msg
354 2f567ac0 Iustin Pop
                       exitWith $ ExitFailure 1
355 2f567ac0 Iustin Pop
                     Ok val -> return val)
356 0427285d Iustin Pop
            when (optShowHelp po) $ do
357 78694255 Iustin Pop
              putStr $ usageHelp progname options
358 209b3711 Iustin Pop
              exitWith ExitSuccess
359 0427285d Iustin Pop
            when (optShowVer po) $ do
360 75d1edf8 Iustin Pop
              printf "%s %s\ncompiled with %s %s\nrunning on %s %s\n"
361 75d1edf8 Iustin Pop
                     progname Version.version
362 75d1edf8 Iustin Pop
                     compilerName (Data.Version.showVersion compilerVersion)
363 c939b58e Iustin Pop
                     os arch :: IO ()
364 75d1edf8 Iustin Pop
              exitWith ExitSuccess
365 2f567ac0 Iustin Pop
            return (po, args)
366 f723de38 Iustin Pop
      (_, _, errs) -> do
367 f723de38 Iustin Pop
        hPutStrLn stderr $ "Command line error: "  ++ concat errs
368 f723de38 Iustin Pop
        hPutStrLn stderr $ usageHelp progname options
369 f723de38 Iustin Pop
        exitWith $ ExitFailure 2
370 209b3711 Iustin Pop
371 9188aeef Iustin Pop
-- | A shell script template for autogenerated scripts.
372 e0eb63f0 Iustin Pop
shTemplate :: String
373 e0eb63f0 Iustin Pop
shTemplate =
374 e0eb63f0 Iustin Pop
    printf "#!/bin/sh\n\n\
375 e0eb63f0 Iustin Pop
           \# Auto-generated script for executing cluster rebalancing\n\n\
376 e0eb63f0 Iustin Pop
           \# To stop, touch the file /tmp/stop-htools\n\n\
377 e0eb63f0 Iustin Pop
           \set -e\n\n\
378 e0eb63f0 Iustin Pop
           \check() {\n\
379 e0eb63f0 Iustin Pop
           \  if [ -f /tmp/stop-htools ]; then\n\
380 e0eb63f0 Iustin Pop
           \    echo 'Stop requested, exiting'\n\
381 e0eb63f0 Iustin Pop
           \    exit 0\n\
382 e0eb63f0 Iustin Pop
           \  fi\n\
383 e0eb63f0 Iustin Pop
           \}\n\n"