Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / CLI.hs @ f5ed8632

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