Revision df18fdfe Ganeti/HTools/CLI.hs

b/Ganeti/HTools/CLI.hs
33 33
    , parseOpts
34 34
    , shTemplate
35 35
    -- * The options
36
    , oPrintNodes
37
    , oPrintInsts
38
    , oPrintCommands
39
    , oOneline
40
    , oNoHeaders
41
    , oOutputDir
42 36
    , oDataFile
43
    , oNodeSim
44
    , oRapiMaster
45
    , oLuxiSocket
37
    , oDiskMoves
38
    , oDynuFile
39
    , oExTags
46 40
    , oExecJobs
47
    , oMaxSolLength
48
    , oVerbose
49
    , oQuiet
50
    , oOfflineNode
51
    , oMinScore
52
    , oIMem
53 41
    , oIDisk
54
    , oIVcpus
42
    , oIMem
55 43
    , oINodes
44
    , oIVcpus
45
    , oLuxiSocket
56 46
    , oMaxCpu
47
    , oMaxSolLength
57 48
    , oMinDisk
58
    , oDiskMoves
59
    , oDynuFile
60
    , oTieredSpec
61
    , oExTags
62
    , oShowVer
49
    , oMinScore
50
    , oNoHeaders
51
    , oNodeSim
52
    , oOfflineNode
53
    , oOneline
54
    , oOutputDir
55
    , oPrintCommands
56
    , oPrintInsts
57
    , oPrintNodes
58
    , oQuiet
59
    , oRapiMaster
63 60
    , oShowHelp
61
    , oShowVer
62
    , oTieredSpec
63
    , oVerbose
64 64
    ) where
65 65

  
66 66
import Data.Maybe (fromMaybe)
......
82 82

  
83 83
-- | Command line options structure.
84 84
data Options = Options
85
    { optShowNodes   :: Maybe [String] -- ^ Whether to show node status
86
    , optShowInsts   :: Bool           -- ^ Whether to show the instance map
87
    , optShowCmds    :: Maybe FilePath -- ^ Whether to show the command list
88
    , optOneline     :: Bool           -- ^ Switch output to a single line
89
    , optOutPath     :: FilePath       -- ^ Path to the output directory
90
    , optNoHeaders   :: Bool           -- ^ Do not show a header line
91
    , optDataFile    :: Maybe FilePath -- ^ Path to the cluster data file
92
    , optNodeSim     :: Maybe String   -- ^ Cluster simulation mode
93
    , optMaxLength   :: Int            -- ^ Stop after this many steps
94
    , optMaster      :: String         -- ^ Collect data from RAPI
95
    , optLuxi        :: Maybe FilePath -- ^ Collect data from Luxi
85
    { optDataFile    :: Maybe FilePath -- ^ Path to the cluster data file
86
    , optDiskMoves   :: Bool           -- ^ Allow disk moves
87
    , optDynuFile    :: Maybe FilePath -- ^ Optional file with dynamic use data
88
    , optExTags      :: Maybe [String] -- ^ Tags to use for exclusion
96 89
    , optExecJobs    :: Bool           -- ^ Execute the commands via Luxi
97
    , optOffline     :: [String]       -- ^ Names of offline nodes
98 90
    , optINodes      :: Int            -- ^ Nodes required for an instance
99 91
    , optISpec       :: RSpec          -- ^ Requested instance specs
100
    , optTieredSpec  :: Maybe RSpec    -- ^ Requested specs for tiered mode
101
    , optMinScore    :: Score          -- ^ The minimum score we aim for
92
    , optLuxi        :: Maybe FilePath -- ^ Collect data from Luxi
93
    , optMaster      :: String         -- ^ Collect data from RAPI
94
    , optMaxLength   :: Int            -- ^ Stop after this many steps
102 95
    , optMcpu        :: Double         -- ^ Max cpu ratio for nodes
103 96
    , optMdsk        :: Double         -- ^ Max disk usage ratio for nodes
104
    , optDiskMoves   :: Bool           -- ^ Allow disk moves
105
    , optDynuFile    :: Maybe FilePath -- ^ Optional file with dynamic use data
106
    , optExTags      :: Maybe [String] -- ^ Tags to use for exclusion
107
    , optVerbose     :: Int            -- ^ Verbosity level
108
    , optShowVer     :: Bool           -- ^ Just show the program version
97
    , optMinScore    :: Score          -- ^ The minimum score we aim for
98
    , optNoHeaders   :: Bool           -- ^ Do not show a header line
99
    , optNodeSim     :: Maybe String   -- ^ Cluster simulation mode
100
    , optOffline     :: [String]       -- ^ Names of offline nodes
101
    , optOneline     :: Bool           -- ^ Switch output to a single line
102
    , optOutPath     :: FilePath       -- ^ Path to the output directory
103
    , optShowCmds    :: Maybe FilePath -- ^ Whether to show the command list
109 104
    , optShowHelp    :: Bool           -- ^ Just show the help
105
    , optShowInsts   :: Bool           -- ^ Whether to show the instance map
106
    , optShowNodes   :: Maybe [String] -- ^ Whether to show node status
107
    , optShowVer     :: Bool           -- ^ Just show the program version
108
    , optTieredSpec  :: Maybe RSpec    -- ^ Requested specs for tiered mode
109
    , optVerbose     :: Int            -- ^ Verbosity level
110 110
    } deriving Show
111 111

  
112 112
-- | Default values for the command line options.
113 113
defaultOptions :: Options
114 114
defaultOptions  = Options
115
 { optShowNodes   = Nothing
116
 , optShowInsts   = False
117
 , optShowCmds    = Nothing
118
 , optOneline     = False
119
 , optNoHeaders   = False
120
 , optOutPath     = "."
121
 , optDataFile    = Nothing
122
 , optNodeSim     = Nothing
123
 , optMaxLength   = -1
124
 , optMaster      = ""
125
 , optLuxi        = Nothing
115
 { optDataFile    = Nothing
116
 , optDiskMoves   = True
117
 , optDynuFile    = Nothing
118
 , optExTags      = Nothing
126 119
 , optExecJobs    = False
127
 , optOffline     = []
128 120
 , optINodes      = 2
129 121
 , optISpec       = RSpec 1 4096 102400
130
 , optTieredSpec  = Nothing
131
 , optMinScore    = 1e-9
122
 , optLuxi        = Nothing
123
 , optMaster      = ""
124
 , optMaxLength   = -1
132 125
 , optMcpu        = -1
133 126
 , optMdsk        = -1
134
 , optDiskMoves   = True
135
 , optDynuFile    = Nothing
136
 , optExTags      = Nothing
137
 , optVerbose     = 1
138
 , optShowVer     = False
127
 , optMinScore    = 1e-9
128
 , optNoHeaders   = False
129
 , optNodeSim     = Nothing
130
 , optOffline     = []
131
 , optOneline     = False
132
 , optOutPath     = "."
133
 , optShowCmds    = Nothing
139 134
 , optShowHelp    = False
135
 , optShowInsts   = False
136
 , optShowNodes   = Nothing
137
 , optShowVer     = False
138
 , optTieredSpec  = Nothing
139
 , optVerbose     = 1
140 140
 }
141 141

  
142 142
-- | Abrreviation for the option type
143 143
type OptType = OptDescr (Options -> Result Options)
144 144

  
145
oPrintNodes :: OptType
146
oPrintNodes = Option "p" ["print-nodes"]
147
              (OptArg ((\ f opts ->
148
                            let splitted = sepSplit ',' f
149
                            in Ok opts { optShowNodes = Just splitted }) .
150
                       fromMaybe []) "FIELDS")
151
              "print the final node list"
152

  
153
oPrintInsts :: OptType
154
oPrintInsts = Option "" ["print-instances"]
155
              (NoArg (\ opts -> Ok opts { optShowInsts = True }))
156
              "print the final instance map"
157

  
158
oPrintCommands :: OptType
159
oPrintCommands = Option "C" ["print-commands"]
160
                 (OptArg ((\ f opts -> Ok opts { optShowCmds = Just f }) .
161
                          fromMaybe "-")
162
                  "FILE")
163
                 "print the ganeti command list for reaching the solution,\
164
                 \ if an argument is passed then write the commands to a\
165
                 \ file named as such"
166

  
167
oOneline :: OptType
168
oOneline = Option "o" ["oneline"]
169
           (NoArg (\ opts -> Ok opts { optOneline = True }))
170
           "print the ganeti command list for reaching the solution"
171

  
172
oNoHeaders :: OptType
173
oNoHeaders = Option "" ["no-headers"]
174
             (NoArg (\ opts -> Ok opts { optNoHeaders = True }))
175
             "do not show a header line"
176

  
177
oOutputDir :: OptType
178
oOutputDir = Option "d" ["output-dir"]
179
             (ReqArg (\ d opts -> Ok opts { optOutPath = d }) "PATH")
180
             "directory in which to write output files"
181

  
182 145
oDataFile :: OptType
183 146
oDataFile = Option "t" ["text-data"]
184 147
            (ReqArg (\ f o -> Ok o { optDataFile = Just f }) "FILE")
185 148
            "the cluster data FILE"
186 149

  
187
oNodeSim :: OptType
188
oNodeSim = Option "" ["simulate"]
189
            (ReqArg (\ f o -> Ok o { optNodeSim = Just f }) "SPEC")
190
            "simulate an empty cluster, given as 'num_nodes,disk,ram,cpu'"
150
oDiskMoves :: OptType
151
oDiskMoves = Option "" ["no-disk-moves"]
152
             (NoArg (\ opts -> Ok opts { optDiskMoves = False}))
153
             "disallow disk moves from the list of allowed instance changes,\
154
             \ thus allowing only the 'cheap' failover/migrate operations"
191 155

  
192
oRapiMaster :: OptType
193
oRapiMaster = Option "m" ["master"]
194
              (ReqArg (\ m opts -> Ok opts { optMaster = m }) "ADDRESS")
195
              "collect data via RAPI at the given ADDRESS"
156
oDynuFile :: OptType
157
oDynuFile = Option "U" ["dynu-file"]
158
            (ReqArg (\ f opts -> Ok opts { optDynuFile = Just f }) "FILE")
159
            "Import dynamic utilisation data from the given FILE"
196 160

  
197
oLuxiSocket :: OptType
198
oLuxiSocket = Option "L" ["luxi"]
199
              (OptArg ((\ f opts -> Ok opts { optLuxi = Just f }) .
200
                       fromMaybe defaultLuxiSocket) "SOCKET")
201
              "collect data via Luxi, optionally using the given SOCKET path"
161
oExTags :: OptType
162
oExTags = Option "" ["exclusion-tags"]
163
            (ReqArg (\ f opts -> Ok opts { optExTags = Just $ sepSplit ',' f })
164
             "TAG,...") "Enable instance exclusion based on given tag prefix"
202 165

  
203 166
oExecJobs :: OptType
204 167
oExecJobs = Option "X" ["exec"]
......
206 169
             "execute the suggested moves via Luxi (only available when using\
207 170
             \ it for data gathering)"
208 171

  
209
oVerbose :: OptType
210
oVerbose = Option "v" ["verbose"]
211
           (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts + 1 }))
212
           "increase the verbosity level"
213

  
214
oQuiet :: OptType
215
oQuiet = Option "q" ["quiet"]
216
         (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts - 1 }))
217
         "decrease the verbosity level"
218

  
219
oOfflineNode :: OptType
220
oOfflineNode = Option "O" ["offline"]
221
               (ReqArg (\ n o -> Ok o { optOffline = n:optOffline o }) "NODE")
222
               "set node as offline"
223

  
224
oMaxSolLength :: OptType
225
oMaxSolLength = Option "l" ["max-length"]
226
                (ReqArg (\ i opts -> Ok opts { optMaxLength = read i }) "N")
227
                "cap the solution at this many moves (useful for very\
228
                \ unbalanced clusters)"
229

  
230
oMinScore :: OptType
231
oMinScore = Option "e" ["min-score"]
232
            (ReqArg (\ e opts -> Ok opts { optMinScore = read e }) "EPSILON")
233
            " mininum score to aim for"
172
oIDisk :: OptType
173
oIDisk = Option "" ["disk"]
174
         (ReqArg (\ d opts ->
175
                     let ospec = optISpec opts
176
                         nspec = ospec { rspecDsk = read d }
177
                     in Ok opts { optISpec = nspec }) "DISK")
178
         "disk size for instances"
234 179

  
235 180
oIMem :: OptType
236 181
oIMem = Option "" ["memory"]
......
240 185
                     in Ok opts { optISpec = nspec }) "MEMORY")
241 186
        "memory size for instances"
242 187

  
243
oIDisk :: OptType
244
oIDisk = Option "" ["disk"]
245
         (ReqArg (\ d opts ->
246
                     let ospec = optISpec opts
247
                         nspec = ospec { rspecDsk = read d }
248
                     in Ok opts { optISpec = nspec }) "DISK")
249
         "disk size for instances"
188
oINodes :: OptType
189
oINodes = Option "" ["req-nodes"]
190
          (ReqArg (\ n opts -> Ok opts { optINodes = read n }) "NODES")
191
          "number of nodes for the new instances (1=plain, 2=mirrored)"
250 192

  
251 193
oIVcpus :: OptType
252 194
oIVcpus = Option "" ["vcpus"]
......
256 198
                       in Ok opts { optISpec = nspec }) "NUM")
257 199
          "number of virtual cpus for instances"
258 200

  
259
oINodes :: OptType
260
oINodes = Option "" ["req-nodes"]
261
          (ReqArg (\ n opts -> Ok opts { optINodes = read n }) "NODES")
262
          "number of nodes for the new instances (1=plain, 2=mirrored)"
201
oLuxiSocket :: OptType
202
oLuxiSocket = Option "L" ["luxi"]
203
              (OptArg ((\ f opts -> Ok opts { optLuxi = Just f }) .
204
                       fromMaybe defaultLuxiSocket) "SOCKET")
205
              "collect data via Luxi, optionally using the given SOCKET path"
263 206

  
264 207
oMaxCpu :: OptType
265 208
oMaxCpu = Option "" ["max-cpu"]
266 209
          (ReqArg (\ n opts -> Ok opts { optMcpu = read n }) "RATIO")
267 210
          "maximum virtual-to-physical cpu ratio for nodes"
268 211

  
212
oMaxSolLength :: OptType
213
oMaxSolLength = Option "l" ["max-length"]
214
                (ReqArg (\ i opts -> Ok opts { optMaxLength = read i }) "N")
215
                "cap the solution at this many moves (useful for very\
216
                \ unbalanced clusters)"
217

  
269 218
oMinDisk :: OptType
270 219
oMinDisk = Option "" ["min-disk"]
271 220
           (ReqArg (\ n opts -> Ok opts { optMdsk = read n }) "RATIO")
272 221
           "minimum free disk space for nodes (between 0 and 1)"
273 222

  
274
oDiskMoves :: OptType
275
oDiskMoves = Option "" ["no-disk-moves"]
276
             (NoArg (\ opts -> Ok opts { optDiskMoves = False}))
277
             "disallow disk moves from the list of allowed instance changes,\
278
             \ thus allowing only the 'cheap' failover/migrate operations"
223
oMinScore :: OptType
224
oMinScore = Option "e" ["min-score"]
225
            (ReqArg (\ e opts -> Ok opts { optMinScore = read e }) "EPSILON")
226
            " mininum score to aim for"
279 227

  
280
oDynuFile :: OptType
281
oDynuFile = Option "U" ["dynu-file"]
282
            (ReqArg (\ f opts -> Ok opts { optDynuFile = Just f }) "FILE")
283
            "Import dynamic utilisation data from the given FILE"
228
oNoHeaders :: OptType
229
oNoHeaders = Option "" ["no-headers"]
230
             (NoArg (\ opts -> Ok opts { optNoHeaders = True }))
231
             "do not show a header line"
284 232

  
285
oExTags :: OptType
286
oExTags = Option "" ["exclusion-tags"]
287
            (ReqArg (\ f opts -> Ok opts { optExTags = Just $ sepSplit ',' f })
288
             "TAG,...") "Enable instance exclusion based on given tag prefix"
233
oNodeSim :: OptType
234
oNodeSim = Option "" ["simulate"]
235
            (ReqArg (\ f o -> Ok o { optNodeSim = Just f }) "SPEC")
236
            "simulate an empty cluster, given as 'num_nodes,disk,ram,cpu'"
237

  
238
oOfflineNode :: OptType
239
oOfflineNode = Option "O" ["offline"]
240
               (ReqArg (\ n o -> Ok o { optOffline = n:optOffline o }) "NODE")
241
               "set node as offline"
242

  
243
oOneline :: OptType
244
oOneline = Option "o" ["oneline"]
245
           (NoArg (\ opts -> Ok opts { optOneline = True }))
246
           "print the ganeti command list for reaching the solution"
247

  
248
oOutputDir :: OptType
249
oOutputDir = Option "d" ["output-dir"]
250
             (ReqArg (\ d opts -> Ok opts { optOutPath = d }) "PATH")
251
             "directory in which to write output files"
252

  
253
oPrintCommands :: OptType
254
oPrintCommands = Option "C" ["print-commands"]
255
                 (OptArg ((\ f opts -> Ok opts { optShowCmds = Just f }) .
256
                          fromMaybe "-")
257
                  "FILE")
258
                 "print the ganeti command list for reaching the solution,\
259
                 \ if an argument is passed then write the commands to a\
260
                 \ file named as such"
261

  
262
oPrintInsts :: OptType
263
oPrintInsts = Option "" ["print-instances"]
264
              (NoArg (\ opts -> Ok opts { optShowInsts = True }))
265
              "print the final instance map"
266

  
267
oPrintNodes :: OptType
268
oPrintNodes = Option "p" ["print-nodes"]
269
              (OptArg ((\ f opts ->
270
                            let splitted = sepSplit ',' f
271
                            in Ok opts { optShowNodes = Just splitted }) .
272
                       fromMaybe []) "FIELDS")
273
              "print the final node list"
274

  
275
oQuiet :: OptType
276
oQuiet = Option "q" ["quiet"]
277
         (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts - 1 }))
278
         "decrease the verbosity level"
279

  
280
oRapiMaster :: OptType
281
oRapiMaster = Option "m" ["master"]
282
              (ReqArg (\ m opts -> Ok opts { optMaster = m }) "ADDRESS")
283
              "collect data via RAPI at the given ADDRESS"
284

  
285
oShowHelp :: OptType
286
oShowHelp = Option "h" ["help"]
287
            (NoArg (\ opts -> Ok opts { optShowHelp = True}))
288
            "show help"
289

  
290
oShowVer :: OptType
291
oShowVer = Option "V" ["version"]
292
           (NoArg (\ opts -> Ok opts { optShowVer = True}))
293
           "show the version of the program"
289 294

  
290 295
oTieredSpec :: OptType
291 296
oTieredSpec = Option "" ["tiered-alloc"]
......
300 305
              "TSPEC")
301 306
             "enable tiered specs allocation, given as 'disk,ram,cpu'"
302 307

  
303
oShowVer :: OptType
304
oShowVer = Option "V" ["version"]
305
           (NoArg (\ opts -> Ok opts { optShowVer = True}))
306
           "show the version of the program"
307

  
308
oShowHelp :: OptType
309
oShowHelp = Option "h" ["help"]
310
            (NoArg (\ opts -> Ok opts { optShowHelp = True}))
311
            "show help"
308
oVerbose :: OptType
309
oVerbose = Option "v" ["verbose"]
310
           (NoArg (\ opts -> Ok opts { optVerbose = optVerbose opts + 1 }))
311
           "increase the verbosity level"
312 312

  
313 313
-- | Usage info
314 314
usageHelp :: String -> [OptType] -> String

Also available in: Unified diff