Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / CLI.hs @ 4f83a560

History | View | Annotate | Download (11.5 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 0427285d Iustin Pop
    -- * The options
36 0427285d Iustin Pop
    , oPrintNodes
37 507fda3f Iustin Pop
    , oPrintInsts
38 0427285d Iustin Pop
    , oPrintCommands
39 0427285d Iustin Pop
    , oOneline
40 0427285d Iustin Pop
    , oNoHeaders
41 0427285d Iustin Pop
    , oOutputDir
42 0427285d Iustin Pop
    , oNodeFile
43 0427285d Iustin Pop
    , oInstFile
44 b2278348 Iustin Pop
    , oNodeSim
45 0427285d Iustin Pop
    , oRapiMaster
46 0427285d Iustin Pop
    , oLuxiSocket
47 0df5a1b4 Iustin Pop
    , oExecJobs
48 0427285d Iustin Pop
    , oMaxSolLength
49 0427285d Iustin Pop
    , oVerbose
50 0427285d Iustin Pop
    , oQuiet
51 0427285d Iustin Pop
    , oOfflineNode
52 0427285d Iustin Pop
    , oMinScore
53 0427285d Iustin Pop
    , oIMem
54 0427285d Iustin Pop
    , oIDisk
55 0427285d Iustin Pop
    , oIVcpus
56 0427285d Iustin Pop
    , oINodes
57 0427285d Iustin Pop
    , oMaxCpu
58 0427285d Iustin Pop
    , oMinDisk
59 c0501c69 Iustin Pop
    , oDiskMoves
60 4f83a560 Iustin Pop
    , oDynuFile
61 0427285d Iustin Pop
    , oShowVer
62 0427285d Iustin Pop
    , oShowHelp
63 209b3711 Iustin Pop
    ) where
64 209b3711 Iustin Pop
65 e8f89bb6 Iustin Pop
import Data.Maybe (fromMaybe)
66 8e445e6d Iustin Pop
import qualified Data.Version
67 8e445e6d Iustin Pop
import Monad
68 209b3711 Iustin Pop
import System.Console.GetOpt
69 209b3711 Iustin Pop
import System.IO
70 209b3711 Iustin Pop
import System.Info
71 209b3711 Iustin Pop
import System
72 e8f89bb6 Iustin Pop
import Text.Printf (printf)
73 209b3711 Iustin Pop
74 209b3711 Iustin Pop
import qualified Ganeti.HTools.Version as Version(version)
75 92e32d76 Iustin Pop
import Ganeti.HTools.Types
76 fae371cc Iustin Pop
77 8e445e6d Iustin Pop
-- | The default value for the luxi socket
78 8e445e6d Iustin Pop
defaultLuxiSocket :: FilePath
79 8e445e6d Iustin Pop
defaultLuxiSocket = "/var/run/ganeti/socket/ganeti-master"
80 8e445e6d Iustin Pop
81 0427285d Iustin Pop
-- | Command line options structure.
82 0427285d Iustin Pop
data Options = Options
83 0427285d Iustin Pop
    { optShowNodes :: Bool           -- ^ Whether to show node status
84 507fda3f Iustin Pop
    , optShowInsts :: Bool           -- ^ Whether to show the instance map
85 0427285d Iustin Pop
    , optShowCmds  :: Maybe FilePath -- ^ Whether to show the command list
86 0427285d Iustin Pop
    , optOneline   :: Bool           -- ^ Switch output to a single line
87 0427285d Iustin Pop
    , optOutPath   :: FilePath       -- ^ Path to the output directory
88 0427285d Iustin Pop
    , optNoHeaders :: Bool           -- ^ Do not show a header line
89 0427285d Iustin Pop
    , optNodeFile  :: FilePath       -- ^ Path to the nodes file
90 0427285d Iustin Pop
    , optNodeSet   :: Bool           -- ^ The nodes have been set by options
91 0427285d Iustin Pop
    , optInstFile  :: FilePath       -- ^ Path to the instances file
92 0427285d Iustin Pop
    , optInstSet   :: Bool           -- ^ The insts have been set by options
93 b2278348 Iustin Pop
    , optNodeSim   :: Maybe String   -- ^ Cluster simulation mode
94 0427285d Iustin Pop
    , optMaxLength :: Int            -- ^ Stop after this many steps
95 0427285d Iustin Pop
    , optMaster    :: String         -- ^ Collect data from RAPI
96 0427285d Iustin Pop
    , optLuxi      :: Maybe FilePath -- ^ Collect data from Luxi
97 0df5a1b4 Iustin Pop
    , optExecJobs  :: Bool           -- ^ Execute the commands via Luxi
98 0427285d Iustin Pop
    , optOffline   :: [String]       -- ^ Names of offline nodes
99 0427285d Iustin Pop
    , optIMem      :: Int            -- ^ Instance memory
100 0427285d Iustin Pop
    , optIDsk      :: Int            -- ^ Instance disk
101 0427285d Iustin Pop
    , optIVCPUs    :: Int            -- ^ Instance VCPUs
102 0427285d Iustin Pop
    , optINodes    :: Int            -- ^ Nodes required for an instance
103 92e32d76 Iustin Pop
    , optMinScore  :: Score          -- ^ The minimum score we aim for
104 0427285d Iustin Pop
    , optMcpu      :: Double         -- ^ Max cpu ratio for nodes
105 0427285d Iustin Pop
    , optMdsk      :: Double         -- ^ Max disk usage ratio for nodes
106 c0501c69 Iustin Pop
    , optDiskMoves :: Bool           -- ^ Allow disk moves
107 4f83a560 Iustin Pop
    , optDynuFile  :: Maybe FilePath -- ^ Optional file with dynamic use data
108 0427285d Iustin Pop
    , optVerbose   :: Int            -- ^ Verbosity level
109 0427285d Iustin Pop
    , optShowVer   :: Bool           -- ^ Just show the program version
110 0427285d Iustin Pop
    , optShowHelp  :: Bool           -- ^ Just show the help
111 0427285d Iustin Pop
    } deriving Show
112 0427285d Iustin Pop
113 0427285d Iustin Pop
-- | Default values for the command line options.
114 0427285d Iustin Pop
defaultOptions :: Options
115 0427285d Iustin Pop
defaultOptions  = Options
116 0427285d Iustin Pop
 { optShowNodes = False
117 507fda3f Iustin Pop
 , optShowInsts = False
118 0427285d Iustin Pop
 , optShowCmds  = Nothing
119 0427285d Iustin Pop
 , optOneline   = False
120 0427285d Iustin Pop
 , optNoHeaders = False
121 0427285d Iustin Pop
 , optOutPath   = "."
122 0427285d Iustin Pop
 , optNodeFile  = "nodes"
123 0427285d Iustin Pop
 , optNodeSet   = False
124 0427285d Iustin Pop
 , optInstFile  = "instances"
125 0427285d Iustin Pop
 , optInstSet   = False
126 b2278348 Iustin Pop
 , optNodeSim   = Nothing
127 0427285d Iustin Pop
 , optMaxLength = -1
128 0427285d Iustin Pop
 , optMaster    = ""
129 0427285d Iustin Pop
 , optLuxi      = Nothing
130 0df5a1b4 Iustin Pop
 , optExecJobs  = False
131 0427285d Iustin Pop
 , optOffline   = []
132 0427285d Iustin Pop
 , optIMem      = 4096
133 0427285d Iustin Pop
 , optIDsk      = 102400
134 0427285d Iustin Pop
 , optIVCPUs    = 1
135 0427285d Iustin Pop
 , optINodes    = 2
136 0427285d Iustin Pop
 , optMinScore  = 1e-9
137 0427285d Iustin Pop
 , optMcpu      = -1
138 0427285d Iustin Pop
 , optMdsk      = -1
139 c0501c69 Iustin Pop
 , optDiskMoves = True
140 4f83a560 Iustin Pop
 , optDynuFile  = Nothing
141 0427285d Iustin Pop
 , optVerbose   = 1
142 0427285d Iustin Pop
 , optShowVer   = False
143 0427285d Iustin Pop
 , optShowHelp  = False
144 0427285d Iustin Pop
 }
145 0427285d Iustin Pop
146 0427285d Iustin Pop
-- | Abrreviation for the option type
147 0427285d Iustin Pop
type OptType = OptDescr (Options -> Options)
148 0427285d Iustin Pop
149 0427285d Iustin Pop
oPrintNodes :: OptType
150 0427285d Iustin Pop
oPrintNodes = Option "p" ["print-nodes"]
151 0427285d Iustin Pop
              (NoArg (\ opts -> opts { optShowNodes = True }))
152 0427285d Iustin Pop
              "print the final node list"
153 0427285d Iustin Pop
154 507fda3f Iustin Pop
oPrintInsts :: OptType
155 507fda3f Iustin Pop
oPrintInsts = Option "" ["print-instances"]
156 507fda3f Iustin Pop
              (NoArg (\ opts -> opts { optShowInsts = True }))
157 507fda3f Iustin Pop
              "print the final instance map"
158 507fda3f Iustin Pop
159 0427285d Iustin Pop
oPrintCommands :: OptType
160 0427285d Iustin Pop
oPrintCommands = Option "C" ["print-commands"]
161 0427285d Iustin Pop
                 (OptArg ((\ f opts -> opts { optShowCmds = Just f }) .
162 0427285d Iustin Pop
                          fromMaybe "-")
163 0427285d Iustin Pop
                  "FILE")
164 0427285d Iustin Pop
                 "print the ganeti command list for reaching the solution,\
165 0427285d Iustin Pop
                 \ if an argument is passed then write the commands to a\
166 0427285d Iustin Pop
                 \ file named as such"
167 0427285d Iustin Pop
168 0427285d Iustin Pop
oOneline :: OptType
169 0427285d Iustin Pop
oOneline = Option "o" ["oneline"]
170 0427285d Iustin Pop
           (NoArg (\ opts -> opts { optOneline = True }))
171 0427285d Iustin Pop
           "print the ganeti command list for reaching the solution"
172 0427285d Iustin Pop
173 0427285d Iustin Pop
oNoHeaders :: OptType
174 0427285d Iustin Pop
oNoHeaders = Option "" ["no-headers"]
175 0427285d Iustin Pop
             (NoArg (\ opts -> opts { optNoHeaders = True }))
176 0427285d Iustin Pop
             "do not show a header line"
177 0427285d Iustin Pop
178 0427285d Iustin Pop
oOutputDir :: OptType
179 0427285d Iustin Pop
oOutputDir = Option "d" ["output-dir"]
180 0427285d Iustin Pop
             (ReqArg (\ d opts -> opts { optOutPath = d }) "PATH")
181 0427285d Iustin Pop
             "directory in which to write output files"
182 0427285d Iustin Pop
183 0427285d Iustin Pop
oNodeFile :: OptType
184 0427285d Iustin Pop
oNodeFile = Option "n" ["nodes"]
185 0427285d Iustin Pop
            (ReqArg (\ f o -> o { optNodeFile = f, optNodeSet = True }) "FILE")
186 0427285d Iustin Pop
            "the node list FILE"
187 0427285d Iustin Pop
188 0427285d Iustin Pop
oInstFile :: OptType
189 0427285d Iustin Pop
oInstFile = Option "i" ["instances"]
190 0427285d Iustin Pop
            (ReqArg (\ f o -> o { optInstFile = f, optInstSet = True }) "FILE")
191 0427285d Iustin Pop
            "the instance list FILE"
192 0427285d Iustin Pop
193 b2278348 Iustin Pop
oNodeSim :: OptType
194 b2278348 Iustin Pop
oNodeSim = Option "" ["simulate"]
195 b2278348 Iustin Pop
            (ReqArg (\ f o -> o { optNodeSim = Just f }) "SPEC")
196 b2278348 Iustin Pop
            "simulate an empty cluster, given as 'num_nodes,disk,memory,cpus'"
197 b2278348 Iustin Pop
198 0427285d Iustin Pop
oRapiMaster :: OptType
199 0427285d Iustin Pop
oRapiMaster = Option "m" ["master"]
200 0427285d Iustin Pop
              (ReqArg (\ m opts -> opts { optMaster = m }) "ADDRESS")
201 0427285d Iustin Pop
              "collect data via RAPI at the given ADDRESS"
202 0427285d Iustin Pop
203 0427285d Iustin Pop
oLuxiSocket :: OptType
204 0427285d Iustin Pop
oLuxiSocket = Option "L" ["luxi"]
205 0427285d Iustin Pop
              (OptArg ((\ f opts -> opts { optLuxi = Just f }) .
206 0427285d Iustin Pop
                       fromMaybe defaultLuxiSocket) "SOCKET")
207 0427285d Iustin Pop
              "collect data via Luxi, optionally using the given SOCKET path"
208 0427285d Iustin Pop
209 0df5a1b4 Iustin Pop
oExecJobs :: OptType
210 0df5a1b4 Iustin Pop
oExecJobs = Option "X" ["exec"]
211 0df5a1b4 Iustin Pop
             (NoArg (\ opts -> opts { optExecJobs = True}))
212 0df5a1b4 Iustin Pop
             "execute the suggested moves via Luxi (only available when using\
213 0df5a1b4 Iustin Pop
             \ it for data gathering"
214 0df5a1b4 Iustin Pop
215 0427285d Iustin Pop
oVerbose :: OptType
216 0427285d Iustin Pop
oVerbose = Option "v" ["verbose"]
217 0427285d Iustin Pop
           (NoArg (\ opts -> opts { optVerbose = optVerbose opts + 1 }))
218 0427285d Iustin Pop
           "increase the verbosity level"
219 0427285d Iustin Pop
220 0427285d Iustin Pop
oQuiet :: OptType
221 0427285d Iustin Pop
oQuiet = Option "q" ["quiet"]
222 0427285d Iustin Pop
         (NoArg (\ opts -> opts { optVerbose = optVerbose opts - 1 }))
223 0427285d Iustin Pop
         "decrease the verbosity level"
224 0427285d Iustin Pop
225 0427285d Iustin Pop
oOfflineNode :: OptType
226 0427285d Iustin Pop
oOfflineNode = Option "O" ["offline"]
227 0427285d Iustin Pop
               (ReqArg (\ n o -> o { optOffline = n:optOffline o }) "NODE")
228 0427285d Iustin Pop
               "set node as offline"
229 0427285d Iustin Pop
230 0427285d Iustin Pop
oMaxSolLength :: OptType
231 0427285d Iustin Pop
oMaxSolLength = Option "l" ["max-length"]
232 0427285d Iustin Pop
                (ReqArg (\ i opts -> opts { optMaxLength =  read i::Int }) "N")
233 0427285d Iustin Pop
                "cap the solution at this many moves (useful for very\
234 0427285d Iustin Pop
                \ unbalanced clusters)"
235 0427285d Iustin Pop
236 0427285d Iustin Pop
oMinScore :: OptType
237 0427285d Iustin Pop
oMinScore = Option "e" ["min-score"]
238 0427285d Iustin Pop
            (ReqArg (\ e opts -> opts { optMinScore = read e }) "EPSILON")
239 0427285d Iustin Pop
            " mininum score to aim for"
240 0427285d Iustin Pop
241 0427285d Iustin Pop
oIMem :: OptType
242 0427285d Iustin Pop
oIMem = Option "" ["memory"]
243 0427285d Iustin Pop
        (ReqArg (\ m opts -> opts { optIMem = read m }) "MEMORY")
244 0427285d Iustin Pop
        "memory size for instances"
245 0427285d Iustin Pop
246 0427285d Iustin Pop
oIDisk :: OptType
247 0427285d Iustin Pop
oIDisk = Option "" ["disk"]
248 0427285d Iustin Pop
         (ReqArg (\ d opts -> opts { optIDsk = read d }) "DISK")
249 0427285d Iustin Pop
         "disk size for instances"
250 0427285d Iustin Pop
251 0427285d Iustin Pop
oIVcpus :: OptType
252 0427285d Iustin Pop
oIVcpus = Option "" ["vcpus"]
253 0427285d Iustin Pop
          (ReqArg (\ p opts -> opts { optIVCPUs = read p }) "NUM")
254 0427285d Iustin Pop
          "number of virtual cpus for instances"
255 0427285d Iustin Pop
256 0427285d Iustin Pop
oINodes :: OptType
257 0427285d Iustin Pop
oINodes = Option "" ["req-nodes"]
258 0427285d Iustin Pop
          (ReqArg (\ n opts -> opts { optINodes = read n }) "NODES")
259 0427285d Iustin Pop
          "number of nodes for the new instances (1=plain, 2=mirrored)"
260 0427285d Iustin Pop
261 0427285d Iustin Pop
oMaxCpu :: OptType
262 0427285d Iustin Pop
oMaxCpu = Option "" ["max-cpu"]
263 0427285d Iustin Pop
          (ReqArg (\ n opts -> opts { optMcpu = read n }) "RATIO")
264 0427285d Iustin Pop
          "maximum virtual-to-physical cpu ratio for nodes"
265 0427285d Iustin Pop
266 0427285d Iustin Pop
oMinDisk :: OptType
267 0427285d Iustin Pop
oMinDisk = Option "" ["min-disk"]
268 0427285d Iustin Pop
           (ReqArg (\ n opts -> opts { optMdsk = read n }) "RATIO")
269 0427285d Iustin Pop
           "minimum free disk space for nodes (between 0 and 1)"
270 0427285d Iustin Pop
271 c0501c69 Iustin Pop
oDiskMoves :: OptType
272 c0501c69 Iustin Pop
oDiskMoves = Option "" ["no-disk-moves"]
273 c0501c69 Iustin Pop
             (NoArg (\ opts -> opts { optDiskMoves = False}))
274 c0501c69 Iustin Pop
             "disallow disk moves from the list of allowed instance changes,\
275 c0501c69 Iustin Pop
             \ thus allowing only the 'cheap' failover/migrate operations"
276 c0501c69 Iustin Pop
277 4f83a560 Iustin Pop
oDynuFile :: OptType
278 4f83a560 Iustin Pop
oDynuFile = Option "U" ["dynu-file"]
279 4f83a560 Iustin Pop
            (ReqArg (\ f opts -> opts { optDynuFile = Just f }) "FILE")
280 4f83a560 Iustin Pop
            "Import dynamic utilisation data from the given FILE"
281 4f83a560 Iustin Pop
282 0427285d Iustin Pop
oShowVer :: OptType
283 0427285d Iustin Pop
oShowVer = Option "V" ["version"]
284 0427285d Iustin Pop
           (NoArg (\ opts -> opts { optShowVer = True}))
285 0427285d Iustin Pop
           "show the version of the program"
286 0427285d Iustin Pop
287 0427285d Iustin Pop
oShowHelp :: OptType
288 0427285d Iustin Pop
oShowHelp = Option "h" ["help"]
289 0427285d Iustin Pop
            (NoArg (\ opts -> opts { optShowHelp = True}))
290 0427285d Iustin Pop
            "show help"
291 fae371cc Iustin Pop
292 78694255 Iustin Pop
-- | Usage info
293 0427285d Iustin Pop
usageHelp :: String -> [OptType] -> String
294 9f6dcdea Iustin Pop
usageHelp progname =
295 78694255 Iustin Pop
    usageInfo (printf "%s %s\nUsage: %s [OPTION...]"
296 9f6dcdea Iustin Pop
               progname Version.version progname)
297 78694255 Iustin Pop
298 209b3711 Iustin Pop
-- | Command line parser, using the 'options' structure.
299 0427285d Iustin Pop
parseOpts :: [String]               -- ^ The command line arguments
300 0427285d Iustin Pop
          -> String                 -- ^ The program name
301 0427285d Iustin Pop
          -> [OptType]              -- ^ The supported command line options
302 0427285d Iustin Pop
          -> IO (Options, [String]) -- ^ The resulting options and leftover
303 0427285d Iustin Pop
                                    -- arguments
304 0427285d Iustin Pop
parseOpts argv progname options =
305 209b3711 Iustin Pop
    case getOpt Permute options argv of
306 209b3711 Iustin Pop
      (o, n, []) ->
307 209b3711 Iustin Pop
          do
308 209b3711 Iustin Pop
            let resu@(po, _) = (foldl (flip id) defaultOptions o, n)
309 0427285d Iustin Pop
            when (optShowHelp po) $ do
310 78694255 Iustin Pop
              putStr $ usageHelp progname options
311 209b3711 Iustin Pop
              exitWith ExitSuccess
312 0427285d Iustin Pop
            when (optShowVer po) $ do
313 75d1edf8 Iustin Pop
              printf "%s %s\ncompiled with %s %s\nrunning on %s %s\n"
314 75d1edf8 Iustin Pop
                     progname Version.version
315 75d1edf8 Iustin Pop
                     compilerName (Data.Version.showVersion compilerVersion)
316 75d1edf8 Iustin Pop
                     os arch
317 75d1edf8 Iustin Pop
              exitWith ExitSuccess
318 209b3711 Iustin Pop
            return resu
319 f723de38 Iustin Pop
      (_, _, errs) -> do
320 f723de38 Iustin Pop
        hPutStrLn stderr $ "Command line error: "  ++ concat errs
321 f723de38 Iustin Pop
        hPutStrLn stderr $ usageHelp progname options
322 f723de38 Iustin Pop
        exitWith $ ExitFailure 2
323 209b3711 Iustin Pop
324 9188aeef Iustin Pop
-- | A shell script template for autogenerated scripts.
325 e0eb63f0 Iustin Pop
shTemplate :: String
326 e0eb63f0 Iustin Pop
shTemplate =
327 e0eb63f0 Iustin Pop
    printf "#!/bin/sh\n\n\
328 e0eb63f0 Iustin Pop
           \# Auto-generated script for executing cluster rebalancing\n\n\
329 e0eb63f0 Iustin Pop
           \# To stop, touch the file /tmp/stop-htools\n\n\
330 e0eb63f0 Iustin Pop
           \set -e\n\n\
331 e0eb63f0 Iustin Pop
           \check() {\n\
332 e0eb63f0 Iustin Pop
           \  if [ -f /tmp/stop-htools ]; then\n\
333 e0eb63f0 Iustin Pop
           \    echo 'Stop requested, exiting'\n\
334 e0eb63f0 Iustin Pop
           \    exit 0\n\
335 e0eb63f0 Iustin Pop
           \  fi\n\
336 e0eb63f0 Iustin Pop
           \}\n\n"