root / Ganeti / HTools / CLI.hs @ 78694255
History | View | Annotate | Download (5.5 kB)
1 |
{-| Implementation of command-line functions. |
---|---|
2 |
|
3 |
This module holds the common cli-related functions for the binaries, |
4 |
separated into this module since Utils.hs is used in many other places |
5 |
and this is more IO oriented. |
6 |
|
7 |
-} |
8 |
|
9 |
{- |
10 |
|
11 |
Copyright (C) 2009 Google Inc. |
12 |
|
13 |
This program is free software; you can redistribute it and/or modify |
14 |
it under the terms of the GNU General Public License as published by |
15 |
the Free Software Foundation; either version 2 of the License, or |
16 |
(at your option) any later version. |
17 |
|
18 |
This program is distributed in the hope that it will be useful, but |
19 |
WITHOUT ANY WARRANTY; without even the implied warranty of |
20 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
21 |
General Public License for more details. |
22 |
|
23 |
You should have received a copy of the GNU General Public License |
24 |
along with this program; if not, write to the Free Software |
25 |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
26 |
02110-1301, USA. |
27 |
|
28 |
-} |
29 |
|
30 |
module Ganeti.HTools.CLI |
31 |
( CLIOptions(..) |
32 |
, EToolOptions(..) |
33 |
, parseOpts |
34 |
, parseEnv |
35 |
, shTemplate |
36 |
, loadExternalData |
37 |
) where |
38 |
|
39 |
import System.Console.GetOpt |
40 |
import System.Posix.Env |
41 |
import System.IO |
42 |
import System.Info |
43 |
import System |
44 |
import Monad |
45 |
import Text.Printf (printf) |
46 |
import qualified Data.Version |
47 |
|
48 |
import qualified Ganeti.HTools.Version as Version(version) |
49 |
import qualified Ganeti.HTools.Rapi as Rapi |
50 |
import qualified Ganeti.HTools.Text as Text |
51 |
import qualified Ganeti.HTools.Loader as Loader |
52 |
import qualified Ganeti.HTools.Instance as Instance |
53 |
import qualified Ganeti.HTools.Node as Node |
54 |
|
55 |
import Ganeti.HTools.Types |
56 |
|
57 |
-- | Class for types which support show help and show version. |
58 |
class CLIOptions a where |
59 |
-- | Denotes whether the show help option has been passed. |
60 |
showHelp :: a -> Bool |
61 |
-- | Denotes whether the show version option has been passed. |
62 |
showVersion :: a -> Bool |
63 |
|
64 |
-- | Class for types which support the -i\/-n\/-m options. |
65 |
class EToolOptions a where |
66 |
-- | Returns the node file name. |
67 |
nodeFile :: a -> FilePath |
68 |
-- | Tells whether the node file has been passed as an option. |
69 |
nodeSet :: a -> Bool |
70 |
-- | Returns the instance file name. |
71 |
instFile :: a -> FilePath |
72 |
-- | Tells whether the instance file has been passed as an option. |
73 |
instSet :: a -> Bool |
74 |
-- | Rapi target, if one has been passed. |
75 |
masterName :: a -> String |
76 |
-- | Whether to be less verbose. |
77 |
silent :: a -> Bool |
78 |
|
79 |
-- | Usage info |
80 |
usageHelp :: (CLIOptions a) => String -> [OptDescr (a -> a)] -> String |
81 |
usageHelp progname options = |
82 |
usageInfo (printf "%s %s\nUsage: %s [OPTION...]" |
83 |
progname Version.version progname) options |
84 |
|
85 |
-- | Command line parser, using the 'options' structure. |
86 |
parseOpts :: (CLIOptions b) => |
87 |
[String] -- ^ The command line arguments |
88 |
-> String -- ^ The program name |
89 |
-> [OptDescr (b -> b)] -- ^ The supported command line options |
90 |
-> b -- ^ The default options record |
91 |
-> IO (b, [String]) -- ^ The resulting options a leftover |
92 |
-- arguments |
93 |
parseOpts argv progname options defaultOptions = |
94 |
case getOpt Permute options argv of |
95 |
(o, n, []) -> |
96 |
do |
97 |
let resu@(po, _) = (foldl (flip id) defaultOptions o, n) |
98 |
when (showHelp po) $ do |
99 |
putStr $ usageHelp progname options |
100 |
exitWith ExitSuccess |
101 |
when (showVersion po) $ do |
102 |
printf "%s %s\ncompiled with %s %s\nrunning on %s %s\n" |
103 |
progname Version.version |
104 |
compilerName (Data.Version.showVersion compilerVersion) |
105 |
os arch |
106 |
exitWith ExitSuccess |
107 |
return resu |
108 |
(_, _, errs) -> |
109 |
ioError (userError (concat errs ++ usageHelp progname options)) |
110 |
|
111 |
-- | Parse the environment and return the node\/instance names. |
112 |
-- |
113 |
-- This also hardcodes here the default node\/instance file names. |
114 |
parseEnv :: () -> IO (String, String) |
115 |
parseEnv () = do |
116 |
a <- getEnvDefault "HTOOLS_NODES" "nodes" |
117 |
b <- getEnvDefault "HTOOLS_INSTANCES" "instances" |
118 |
return (a, b) |
119 |
|
120 |
-- | A shell script template for autogenerated scripts. |
121 |
shTemplate :: String |
122 |
shTemplate = |
123 |
printf "#!/bin/sh\n\n\ |
124 |
\# Auto-generated script for executing cluster rebalancing\n\n\ |
125 |
\# To stop, touch the file /tmp/stop-htools\n\n\ |
126 |
\set -e\n\n\ |
127 |
\check() {\n\ |
128 |
\ if [ -f /tmp/stop-htools ]; then\n\ |
129 |
\ echo 'Stop requested, exiting'\n\ |
130 |
\ exit 0\n\ |
131 |
\ fi\n\ |
132 |
\}\n\n" |
133 |
|
134 |
-- | External tool data loader from a variety of sources. |
135 |
loadExternalData :: (EToolOptions a) => |
136 |
a |
137 |
-> IO (Node.List, Instance.List, String) |
138 |
loadExternalData opts = do |
139 |
(env_node, env_inst) <- parseEnv () |
140 |
let nodef = if nodeSet opts then nodeFile opts |
141 |
else env_node |
142 |
instf = if instSet opts then instFile opts |
143 |
else env_inst |
144 |
input_data <- |
145 |
case masterName opts of |
146 |
"" -> Text.loadData nodef instf |
147 |
host -> Rapi.loadData host |
148 |
|
149 |
let ldresult = input_data >>= Loader.mergeData |
150 |
(loaded_nl, il, csf) <- |
151 |
(case ldresult of |
152 |
Ok x -> return x |
153 |
Bad s -> do |
154 |
printf "Error: failed to load data. Details:\n%s\n" s |
155 |
exitWith $ ExitFailure 1 |
156 |
) |
157 |
let (fix_msgs, fixed_nl) = Loader.checkData loaded_nl il |
158 |
|
159 |
unless (null fix_msgs || silent opts) $ do |
160 |
putStrLn "Warning: cluster has inconsistent data:" |
161 |
putStrLn . unlines . map (\s -> printf " - %s" s) $ fix_msgs |
162 |
|
163 |
return (fixed_nl, il, csf) |