Statistics
| Branch: | Tag: | Revision:

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

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