Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ e7e09483

History | View | Annotate | Download (47.4 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 a8083063 Iustin Pop
"""Module dealing with command line parsing"""
23 a8083063 Iustin Pop
24 a8083063 Iustin Pop
25 a8083063 Iustin Pop
import sys
26 a8083063 Iustin Pop
import textwrap
27 a8083063 Iustin Pop
import os.path
28 a8083063 Iustin Pop
import copy
29 685ee993 Iustin Pop
import time
30 46fbdd04 Iustin Pop
import logging
31 73702ee7 Iustin Pop
from cStringIO import StringIO
32 a8083063 Iustin Pop
33 a8083063 Iustin Pop
from ganeti import utils
34 a8083063 Iustin Pop
from ganeti import errors
35 a8083063 Iustin Pop
from ganeti import constants
36 846baef9 Iustin Pop
from ganeti import opcodes
37 ceab32dd Iustin Pop
from ganeti import luxi
38 b33e986b Iustin Pop
from ganeti import ssconf
39 4331f6cd Michael Hanselmann
from ganeti import rpc
40 a8083063 Iustin Pop
41 c38c44ad Michael Hanselmann
from optparse import (OptionParser, TitledHelpFormatter,
42 38206f3c Iustin Pop
                      Option, OptionValueError)
43 a8083063 Iustin Pop
44 03298ebe Michael Hanselmann
45 4abc4f1e Iustin Pop
__all__ = [
46 4abc4f1e Iustin Pop
  # Command line options
47 e7e09483 Iustin Pop
  "ALLOCATABLE_OPT",
48 2d5e7ae1 Iustin Pop
  "ALL_OPT",
49 e00f7a05 Iustin Pop
  "AUTO_REPLACE_OPT",
50 087ed2ed Iustin Pop
  "BACKEND_OPT",
51 baef337d Iustin Pop
  "CLEANUP_OPT",
52 4abc4f1e Iustin Pop
  "CONFIRM_OPT",
53 4abc4f1e Iustin Pop
  "DEBUG_OPT",
54 a0c9776a Iustin Pop
  "DEBUG_SIMERR_OPT",
55 4b038a1e Iustin Pop
  "DISKIDX_OPT",
56 e3876ccb Iustin Pop
  "DISK_OPT",
57 4b038a1e Iustin Pop
  "DISK_TEMPLATE_OPT",
58 771734c9 Iustin Pop
  "DRAINED_OPT",
59 4abc4f1e Iustin Pop
  "FIELDS_OPT",
60 4a25828c Iustin Pop
  "FILESTORE_DIR_OPT",
61 0f87c43e Iustin Pop
  "FILESTORE_DRIVER_OPT",
62 073271f6 Iustin Pop
  "HVLIST_OPT",
63 48f212d7 Iustin Pop
  "HVOPTS_OPT",
64 236fd9c4 Iustin Pop
  "HYPERVISOR_OPT",
65 4eb62659 Iustin Pop
  "IALLOCATOR_OPT",
66 82a786d5 Iustin Pop
  "IGNORE_CONSIST_OPT",
67 b6e841a8 Iustin Pop
  "IGNORE_FAILURES_OPT",
68 05586c90 Iustin Pop
  "IGNORE_SIZE_OPT",
69 4abc4f1e Iustin Pop
  "FORCE_OPT",
70 771734c9 Iustin Pop
  "MC_OPT",
71 7d3a9fab Iustin Pop
  "NET_OPT",
72 a14db5ff Iustin Pop
  "NEW_SECONDARY_OPT",
73 7edc4637 Iustin Pop
  "NODE_LIST_OPT",
74 990b7886 Iustin Pop
  "NODE_PLACEMENT_OPT",
75 4abc4f1e Iustin Pop
  "NOHDR_OPT",
76 91e0748c Iustin Pop
  "NOIPCHECK_OPT",
77 26023ecd Iustin Pop
  "NONICS_OPT",
78 f2a0828c Iustin Pop
  "NONLIVE_OPT",
79 edeb878a Iustin Pop
  "NOSTART_OPT",
80 fcdde7f2 Iustin Pop
  "NOSSH_KEYCHECK_OPT",
81 3f75b4f3 Iustin Pop
  "NWSYNC_OPT",
82 a72d0a79 Iustin Pop
  "ON_PRIMARY_OPT",
83 feb09e6a Iustin Pop
  "ON_SECONDARY_OPT",
84 771734c9 Iustin Pop
  "OFFLINE_OPT",
85 d3ed23ff Iustin Pop
  "OS_OPT",
86 ff00c1a7 Iustin Pop
  "OS_SIZE_OPT",
87 b8d0f938 Iustin Pop
  "READD_OPT",
88 8d823629 Iustin Pop
  "SECONDARY_IP_OPT",
89 67840b40 Iustin Pop
  "SELECT_OS_OPT",
90 4abc4f1e Iustin Pop
  "SEP_OPT",
91 fdcf4d84 Iustin Pop
  "SHOWCMD_OPT",
92 f36d7d81 Iustin Pop
  "SINGLE_NODE_OPT",
93 df62e5db Iustin Pop
  "SRC_DIR_OPT",
94 df62e5db Iustin Pop
  "SRC_NODE_OPT",
95 4abc4f1e Iustin Pop
  "SUBMIT_OPT",
96 99a8c799 Iustin Pop
  "STATIC_OPT",
97 4abc4f1e Iustin Pop
  "SYNC_OPT",
98 4abc4f1e Iustin Pop
  "TAG_SRC_OPT",
99 4abc4f1e Iustin Pop
  "USEUNITS_OPT",
100 9cdb9578 Iustin Pop
  "VERBOSE_OPT",
101 4abc4f1e Iustin Pop
  # Generic functions for CLI programs
102 4abc4f1e Iustin Pop
  "GenericMain",
103 4abc4f1e Iustin Pop
  "GetClient",
104 4abc4f1e Iustin Pop
  "GetOnlineNodes",
105 4abc4f1e Iustin Pop
  "JobExecutor",
106 4abc4f1e Iustin Pop
  "JobSubmittedException",
107 4abc4f1e Iustin Pop
  "ParseTimespec",
108 4abc4f1e Iustin Pop
  "SubmitOpCode",
109 4abc4f1e Iustin Pop
  "SubmitOrSend",
110 4abc4f1e Iustin Pop
  "UsesRPC",
111 4abc4f1e Iustin Pop
  # Formatting functions
112 4abc4f1e Iustin Pop
  "ToStderr", "ToStdout",
113 4abc4f1e Iustin Pop
  "FormatError",
114 4abc4f1e Iustin Pop
  "GenerateTable",
115 4abc4f1e Iustin Pop
  "AskUser",
116 4abc4f1e Iustin Pop
  "FormatTimestamp",
117 4abc4f1e Iustin Pop
  # Tags functions
118 4abc4f1e Iustin Pop
  "ListTags",
119 4abc4f1e Iustin Pop
  "AddTags",
120 4abc4f1e Iustin Pop
  "RemoveTags",
121 4abc4f1e Iustin Pop
  # command line options support infrastructure
122 4abc4f1e Iustin Pop
  "ARGS_MANY_INSTANCES",
123 4abc4f1e Iustin Pop
  "ARGS_MANY_NODES",
124 4abc4f1e Iustin Pop
  "ARGS_NONE",
125 4abc4f1e Iustin Pop
  "ARGS_ONE_INSTANCE",
126 4abc4f1e Iustin Pop
  "ARGS_ONE_NODE",
127 4abc4f1e Iustin Pop
  "ArgChoice",
128 4abc4f1e Iustin Pop
  "ArgCommand",
129 4abc4f1e Iustin Pop
  "ArgFile",
130 4abc4f1e Iustin Pop
  "ArgHost",
131 4abc4f1e Iustin Pop
  "ArgInstance",
132 4abc4f1e Iustin Pop
  "ArgJobId",
133 4abc4f1e Iustin Pop
  "ArgNode",
134 4abc4f1e Iustin Pop
  "ArgSuggest",
135 4abc4f1e Iustin Pop
  "ArgUnknown",
136 4abc4f1e Iustin Pop
  "OPT_COMPL_INST_ADD_NODES",
137 4abc4f1e Iustin Pop
  "OPT_COMPL_MANY_NODES",
138 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_IALLOCATOR",
139 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_INSTANCE",
140 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_NODE",
141 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_OS",
142 4abc4f1e Iustin Pop
  "cli_option",
143 4abc4f1e Iustin Pop
  "SplitNodeOption",
144 4abc4f1e Iustin Pop
  ]
145 846baef9 Iustin Pop
146 8b46606c Guido Trotter
NO_PREFIX = "no_"
147 8b46606c Guido Trotter
UN_PREFIX = "-"
148 846baef9 Iustin Pop
149 03298ebe Michael Hanselmann
150 863d7f46 Michael Hanselmann
class _Argument:
151 dff85078 Michael Hanselmann
  def __init__(self, min=0, max=None):
152 863d7f46 Michael Hanselmann
    self.min = min
153 863d7f46 Michael Hanselmann
    self.max = max
154 863d7f46 Michael Hanselmann
155 863d7f46 Michael Hanselmann
  def __repr__(self):
156 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s>" %
157 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max))
158 863d7f46 Michael Hanselmann
159 863d7f46 Michael Hanselmann
160 863d7f46 Michael Hanselmann
class ArgSuggest(_Argument):
161 863d7f46 Michael Hanselmann
  """Suggesting argument.
162 863d7f46 Michael Hanselmann

163 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor.
164 863d7f46 Michael Hanselmann

165 863d7f46 Michael Hanselmann
  """
166 863d7f46 Michael Hanselmann
  def __init__(self, min=0, max=None, choices=None):
167 863d7f46 Michael Hanselmann
    _Argument.__init__(self, min=min, max=max)
168 863d7f46 Michael Hanselmann
    self.choices = choices
169 863d7f46 Michael Hanselmann
170 863d7f46 Michael Hanselmann
  def __repr__(self):
171 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s choices=%r>" %
172 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max, self.choices))
173 863d7f46 Michael Hanselmann
174 863d7f46 Michael Hanselmann
175 863d7f46 Michael Hanselmann
class ArgChoice(ArgSuggest):
176 863d7f46 Michael Hanselmann
  """Choice argument.
177 863d7f46 Michael Hanselmann

178 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor. Like L{ArgSuggest},
179 863d7f46 Michael Hanselmann
  but value must be one of the choices.
180 863d7f46 Michael Hanselmann

181 863d7f46 Michael Hanselmann
  """
182 863d7f46 Michael Hanselmann
183 863d7f46 Michael Hanselmann
184 863d7f46 Michael Hanselmann
class ArgUnknown(_Argument):
185 863d7f46 Michael Hanselmann
  """Unknown argument to program (e.g. determined at runtime).
186 863d7f46 Michael Hanselmann

187 863d7f46 Michael Hanselmann
  """
188 863d7f46 Michael Hanselmann
189 863d7f46 Michael Hanselmann
190 863d7f46 Michael Hanselmann
class ArgInstance(_Argument):
191 863d7f46 Michael Hanselmann
  """Instances argument.
192 863d7f46 Michael Hanselmann

193 863d7f46 Michael Hanselmann
  """
194 863d7f46 Michael Hanselmann
195 863d7f46 Michael Hanselmann
196 863d7f46 Michael Hanselmann
class ArgNode(_Argument):
197 863d7f46 Michael Hanselmann
  """Node argument.
198 863d7f46 Michael Hanselmann

199 863d7f46 Michael Hanselmann
  """
200 863d7f46 Michael Hanselmann
201 863d7f46 Michael Hanselmann
class ArgJobId(_Argument):
202 863d7f46 Michael Hanselmann
  """Job ID argument.
203 863d7f46 Michael Hanselmann

204 863d7f46 Michael Hanselmann
  """
205 863d7f46 Michael Hanselmann
206 863d7f46 Michael Hanselmann
207 863d7f46 Michael Hanselmann
class ArgFile(_Argument):
208 863d7f46 Michael Hanselmann
  """File path argument.
209 863d7f46 Michael Hanselmann

210 863d7f46 Michael Hanselmann
  """
211 863d7f46 Michael Hanselmann
212 863d7f46 Michael Hanselmann
213 863d7f46 Michael Hanselmann
class ArgCommand(_Argument):
214 863d7f46 Michael Hanselmann
  """Command argument.
215 863d7f46 Michael Hanselmann

216 863d7f46 Michael Hanselmann
  """
217 863d7f46 Michael Hanselmann
218 863d7f46 Michael Hanselmann
219 83ec7961 Michael Hanselmann
class ArgHost(_Argument):
220 83ec7961 Michael Hanselmann
  """Host argument.
221 83ec7961 Michael Hanselmann

222 83ec7961 Michael Hanselmann
  """
223 83ec7961 Michael Hanselmann
224 83ec7961 Michael Hanselmann
225 4a265c08 Michael Hanselmann
ARGS_NONE = []
226 4a265c08 Michael Hanselmann
ARGS_MANY_INSTANCES = [ArgInstance()]
227 4a265c08 Michael Hanselmann
ARGS_MANY_NODES = [ArgNode()]
228 4a265c08 Michael Hanselmann
ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
229 4a265c08 Michael Hanselmann
ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
230 4a265c08 Michael Hanselmann
231 4a265c08 Michael Hanselmann
232 73b90123 Michael Hanselmann
233 846baef9 Iustin Pop
def _ExtractTagsObject(opts, args):
234 846baef9 Iustin Pop
  """Extract the tag type object.
235 846baef9 Iustin Pop

236 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
237 846baef9 Iustin Pop

238 846baef9 Iustin Pop
  """
239 846baef9 Iustin Pop
  if not hasattr(opts, "tag_type"):
240 846baef9 Iustin Pop
    raise errors.ProgrammerError("tag_type not passed to _ExtractTagsObject")
241 846baef9 Iustin Pop
  kind = opts.tag_type
242 846baef9 Iustin Pop
  if kind == constants.TAG_CLUSTER:
243 846baef9 Iustin Pop
    retval = kind, kind
244 846baef9 Iustin Pop
  elif kind == constants.TAG_NODE or kind == constants.TAG_INSTANCE:
245 846baef9 Iustin Pop
    if not args:
246 0c434948 Iustin Pop
      raise errors.OpPrereqError("no arguments passed to the command")
247 846baef9 Iustin Pop
    name = args.pop(0)
248 846baef9 Iustin Pop
    retval = kind, name
249 846baef9 Iustin Pop
  else:
250 846baef9 Iustin Pop
    raise errors.ProgrammerError("Unhandled tag type '%s'" % kind)
251 846baef9 Iustin Pop
  return retval
252 846baef9 Iustin Pop
253 846baef9 Iustin Pop
254 810c50b7 Iustin Pop
def _ExtendTags(opts, args):
255 810c50b7 Iustin Pop
  """Extend the args if a source file has been given.
256 810c50b7 Iustin Pop

257 810c50b7 Iustin Pop
  This function will extend the tags with the contents of the file
258 810c50b7 Iustin Pop
  passed in the 'tags_source' attribute of the opts parameter. A file
259 810c50b7 Iustin Pop
  named '-' will be replaced by stdin.
260 810c50b7 Iustin Pop

261 810c50b7 Iustin Pop
  """
262 810c50b7 Iustin Pop
  fname = opts.tags_source
263 810c50b7 Iustin Pop
  if fname is None:
264 810c50b7 Iustin Pop
    return
265 810c50b7 Iustin Pop
  if fname == "-":
266 810c50b7 Iustin Pop
    new_fh = sys.stdin
267 810c50b7 Iustin Pop
  else:
268 810c50b7 Iustin Pop
    new_fh = open(fname, "r")
269 810c50b7 Iustin Pop
  new_data = []
270 810c50b7 Iustin Pop
  try:
271 810c50b7 Iustin Pop
    # we don't use the nice 'new_data = [line.strip() for line in fh]'
272 810c50b7 Iustin Pop
    # because of python bug 1633941
273 810c50b7 Iustin Pop
    while True:
274 810c50b7 Iustin Pop
      line = new_fh.readline()
275 810c50b7 Iustin Pop
      if not line:
276 810c50b7 Iustin Pop
        break
277 810c50b7 Iustin Pop
      new_data.append(line.strip())
278 810c50b7 Iustin Pop
  finally:
279 810c50b7 Iustin Pop
    new_fh.close()
280 810c50b7 Iustin Pop
  args.extend(new_data)
281 810c50b7 Iustin Pop
282 810c50b7 Iustin Pop
283 846baef9 Iustin Pop
def ListTags(opts, args):
284 846baef9 Iustin Pop
  """List the tags on a given object.
285 846baef9 Iustin Pop

286 846baef9 Iustin Pop
  This is a generic implementation that knows how to deal with all
287 846baef9 Iustin Pop
  three cases of tag objects (cluster, node, instance). The opts
288 846baef9 Iustin Pop
  argument is expected to contain a tag_type field denoting what
289 846baef9 Iustin Pop
  object type we work on.
290 846baef9 Iustin Pop

291 846baef9 Iustin Pop
  """
292 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
293 846baef9 Iustin Pop
  op = opcodes.OpGetTags(kind=kind, name=name)
294 846baef9 Iustin Pop
  result = SubmitOpCode(op)
295 846baef9 Iustin Pop
  result = list(result)
296 846baef9 Iustin Pop
  result.sort()
297 846baef9 Iustin Pop
  for tag in result:
298 03298ebe Michael Hanselmann
    ToStdout(tag)
299 846baef9 Iustin Pop
300 846baef9 Iustin Pop
301 846baef9 Iustin Pop
def AddTags(opts, args):
302 846baef9 Iustin Pop
  """Add tags on a given object.
303 846baef9 Iustin Pop

304 846baef9 Iustin Pop
  This is a generic implementation that knows how to deal with all
305 846baef9 Iustin Pop
  three cases of tag objects (cluster, node, instance). The opts
306 846baef9 Iustin Pop
  argument is expected to contain a tag_type field denoting what
307 846baef9 Iustin Pop
  object type we work on.
308 846baef9 Iustin Pop

309 846baef9 Iustin Pop
  """
310 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
311 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
312 846baef9 Iustin Pop
  if not args:
313 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be added")
314 846baef9 Iustin Pop
  op = opcodes.OpAddTags(kind=kind, name=name, tags=args)
315 846baef9 Iustin Pop
  SubmitOpCode(op)
316 846baef9 Iustin Pop
317 846baef9 Iustin Pop
318 846baef9 Iustin Pop
def RemoveTags(opts, args):
319 846baef9 Iustin Pop
  """Remove tags from a given object.
320 846baef9 Iustin Pop

321 846baef9 Iustin Pop
  This is a generic implementation that knows how to deal with all
322 846baef9 Iustin Pop
  three cases of tag objects (cluster, node, instance). The opts
323 846baef9 Iustin Pop
  argument is expected to contain a tag_type field denoting what
324 846baef9 Iustin Pop
  object type we work on.
325 846baef9 Iustin Pop

326 846baef9 Iustin Pop
  """
327 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
328 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
329 846baef9 Iustin Pop
  if not args:
330 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be removed")
331 846baef9 Iustin Pop
  op = opcodes.OpDelTags(kind=kind, name=name, tags=args)
332 846baef9 Iustin Pop
  SubmitOpCode(op)
333 846baef9 Iustin Pop
334 a8083063 Iustin Pop
335 a8083063 Iustin Pop
def check_unit(option, opt, value):
336 65fe4693 Iustin Pop
  """OptParsers custom converter for units.
337 65fe4693 Iustin Pop

338 65fe4693 Iustin Pop
  """
339 a8083063 Iustin Pop
  try:
340 a8083063 Iustin Pop
    return utils.ParseUnit(value)
341 a8083063 Iustin Pop
  except errors.UnitParseError, err:
342 3ecf6786 Iustin Pop
    raise OptionValueError("option %s: %s" % (opt, err))
343 a8083063 Iustin Pop
344 a8083063 Iustin Pop
345 a8469393 Iustin Pop
def _SplitKeyVal(opt, data):
346 a8469393 Iustin Pop
  """Convert a KeyVal string into a dict.
347 a8469393 Iustin Pop

348 a8469393 Iustin Pop
  This function will convert a key=val[,...] string into a dict. Empty
349 a8469393 Iustin Pop
  values will be converted specially: keys which have the prefix 'no_'
350 a8469393 Iustin Pop
  will have the value=False and the prefix stripped, the others will
351 a8469393 Iustin Pop
  have value=True.
352 a8469393 Iustin Pop

353 a8469393 Iustin Pop
  @type opt: string
354 a8469393 Iustin Pop
  @param opt: a string holding the option name for which we process the
355 a8469393 Iustin Pop
      data, used in building error messages
356 a8469393 Iustin Pop
  @type data: string
357 a8469393 Iustin Pop
  @param data: a string of the format key=val,key=val,...
358 a8469393 Iustin Pop
  @rtype: dict
359 a8469393 Iustin Pop
  @return: {key=val, key=val}
360 a8469393 Iustin Pop
  @raises errors.ParameterError: if there are duplicate keys
361 a8469393 Iustin Pop

362 a8469393 Iustin Pop
  """
363 a8469393 Iustin Pop
  kv_dict = {}
364 4f31882e Guido Trotter
  if data:
365 4f31882e Guido Trotter
    for elem in data.split(","):
366 4f31882e Guido Trotter
      if "=" in elem:
367 4f31882e Guido Trotter
        key, val = elem.split("=", 1)
368 a8469393 Iustin Pop
      else:
369 4f31882e Guido Trotter
        if elem.startswith(NO_PREFIX):
370 4f31882e Guido Trotter
          key, val = elem[len(NO_PREFIX):], False
371 4f31882e Guido Trotter
        elif elem.startswith(UN_PREFIX):
372 4f31882e Guido Trotter
          key, val = elem[len(UN_PREFIX):], None
373 4f31882e Guido Trotter
        else:
374 4f31882e Guido Trotter
          key, val = elem, True
375 4f31882e Guido Trotter
      if key in kv_dict:
376 4f31882e Guido Trotter
        raise errors.ParameterError("Duplicate key '%s' in option %s" %
377 4f31882e Guido Trotter
                                    (key, opt))
378 4f31882e Guido Trotter
      kv_dict[key] = val
379 a8469393 Iustin Pop
  return kv_dict
380 a8469393 Iustin Pop
381 a8469393 Iustin Pop
382 a8469393 Iustin Pop
def check_ident_key_val(option, opt, value):
383 552c8dff Michael Hanselmann
  """Custom parser for ident:key=val,key=val options.
384 552c8dff Michael Hanselmann

385 552c8dff Michael Hanselmann
  This will store the parsed values as a tuple (ident, {key: val}). As such,
386 552c8dff Michael Hanselmann
  multiple uses of this option via action=append is possible.
387 a8469393 Iustin Pop

388 a8469393 Iustin Pop
  """
389 a8469393 Iustin Pop
  if ":" not in value:
390 8b46606c Guido Trotter
    ident, rest = value, ''
391 a8469393 Iustin Pop
  else:
392 a8469393 Iustin Pop
    ident, rest = value.split(":", 1)
393 8b46606c Guido Trotter
394 8b46606c Guido Trotter
  if ident.startswith(NO_PREFIX):
395 8b46606c Guido Trotter
    if rest:
396 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
397 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
398 8b46606c Guido Trotter
    retval = (ident[len(NO_PREFIX):], False)
399 8b46606c Guido Trotter
  elif ident.startswith(UN_PREFIX):
400 8b46606c Guido Trotter
    if rest:
401 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
402 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
403 8b46606c Guido Trotter
    retval = (ident[len(UN_PREFIX):], None)
404 8b46606c Guido Trotter
  else:
405 a8469393 Iustin Pop
    kv_dict = _SplitKeyVal(opt, rest)
406 a8469393 Iustin Pop
    retval = (ident, kv_dict)
407 a8469393 Iustin Pop
  return retval
408 a8469393 Iustin Pop
409 a8469393 Iustin Pop
410 a8469393 Iustin Pop
def check_key_val(option, opt, value):
411 552c8dff Michael Hanselmann
  """Custom parser class for key=val,key=val options.
412 552c8dff Michael Hanselmann

413 552c8dff Michael Hanselmann
  This will store the parsed values as a dict {key: val}.
414 a8469393 Iustin Pop

415 a8469393 Iustin Pop
  """
416 a8469393 Iustin Pop
  return _SplitKeyVal(opt, value)
417 a8469393 Iustin Pop
418 a8469393 Iustin Pop
419 63d44c55 Michael Hanselmann
# completion_suggestion is normally a list. Using numeric values not evaluating
420 63d44c55 Michael Hanselmann
# to False for dynamic completion.
421 63d44c55 Michael Hanselmann
(OPT_COMPL_MANY_NODES,
422 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_NODE,
423 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_INSTANCE,
424 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_OS,
425 2d3ed64b Michael Hanselmann
 OPT_COMPL_ONE_IALLOCATOR,
426 2d3ed64b Michael Hanselmann
 OPT_COMPL_INST_ADD_NODES) = range(100, 106)
427 63d44c55 Michael Hanselmann
428 63d44c55 Michael Hanselmann
OPT_COMPL_ALL = frozenset([
429 63d44c55 Michael Hanselmann
  OPT_COMPL_MANY_NODES,
430 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_NODE,
431 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_INSTANCE,
432 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_OS,
433 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_IALLOCATOR,
434 2d3ed64b Michael Hanselmann
  OPT_COMPL_INST_ADD_NODES,
435 63d44c55 Michael Hanselmann
  ])
436 63d44c55 Michael Hanselmann
437 63d44c55 Michael Hanselmann
438 552c8dff Michael Hanselmann
class CliOption(Option):
439 552c8dff Michael Hanselmann
  """Custom option class for optparse.
440 a8469393 Iustin Pop

441 a8469393 Iustin Pop
  """
442 863d7f46 Michael Hanselmann
  ATTRS = Option.ATTRS + [
443 863d7f46 Michael Hanselmann
    "completion_suggest",
444 863d7f46 Michael Hanselmann
    ]
445 552c8dff Michael Hanselmann
  TYPES = Option.TYPES + (
446 552c8dff Michael Hanselmann
    "identkeyval",
447 552c8dff Michael Hanselmann
    "keyval",
448 552c8dff Michael Hanselmann
    "unit",
449 552c8dff Michael Hanselmann
    )
450 552c8dff Michael Hanselmann
  TYPE_CHECKER = Option.TYPE_CHECKER.copy()
451 552c8dff Michael Hanselmann
  TYPE_CHECKER["identkeyval"] = check_ident_key_val
452 a8469393 Iustin Pop
  TYPE_CHECKER["keyval"] = check_key_val
453 552c8dff Michael Hanselmann
  TYPE_CHECKER["unit"] = check_unit
454 a8469393 Iustin Pop
455 a8469393 Iustin Pop
456 a8083063 Iustin Pop
# optparse.py sets make_option, so we do it for our own option class, too
457 a8083063 Iustin Pop
cli_option = CliOption
458 a8083063 Iustin Pop
459 a8083063 Iustin Pop
460 771734c9 Iustin Pop
_YESNO = ("yes", "no")
461 771734c9 Iustin Pop
_YORNO = "yes|no"
462 771734c9 Iustin Pop
463 c38c44ad Michael Hanselmann
DEBUG_OPT = cli_option("-d", "--debug", default=False,
464 c38c44ad Michael Hanselmann
                       action="store_true",
465 c38c44ad Michael Hanselmann
                       help="Turn debugging on")
466 c38c44ad Michael Hanselmann
467 c38c44ad Michael Hanselmann
NOHDR_OPT = cli_option("--no-headers", default=False,
468 c38c44ad Michael Hanselmann
                       action="store_true", dest="no_headers",
469 c38c44ad Michael Hanselmann
                       help="Don't display column headers")
470 c38c44ad Michael Hanselmann
471 c38c44ad Michael Hanselmann
SEP_OPT = cli_option("--separator", default=None,
472 c38c44ad Michael Hanselmann
                     action="store", dest="separator",
473 c38c44ad Michael Hanselmann
                     help=("Separator between output fields"
474 c38c44ad Michael Hanselmann
                           " (defaults to one space)"))
475 c38c44ad Michael Hanselmann
476 c38c44ad Michael Hanselmann
USEUNITS_OPT = cli_option("--units", default=None,
477 c38c44ad Michael Hanselmann
                          dest="units", choices=('h', 'm', 'g', 't'),
478 c38c44ad Michael Hanselmann
                          help="Specify units for output (one of hmgt)")
479 c38c44ad Michael Hanselmann
480 c38c44ad Michael Hanselmann
FIELDS_OPT = cli_option("-o", "--output", dest="output", action="store",
481 c38c44ad Michael Hanselmann
                        type="string", metavar="FIELDS",
482 c38c44ad Michael Hanselmann
                        help="Comma separated list of output fields")
483 c38c44ad Michael Hanselmann
484 c38c44ad Michael Hanselmann
FORCE_OPT = cli_option("-f", "--force", dest="force", action="store_true",
485 c38c44ad Michael Hanselmann
                       default=False, help="Force the operation")
486 c38c44ad Michael Hanselmann
487 c38c44ad Michael Hanselmann
CONFIRM_OPT = cli_option("--yes", dest="confirm", action="store_true",
488 c38c44ad Michael Hanselmann
                         default=False, help="Do not require confirmation")
489 c38c44ad Michael Hanselmann
490 c38c44ad Michael Hanselmann
TAG_SRC_OPT = cli_option("--from", dest="tags_source",
491 c38c44ad Michael Hanselmann
                         default=None, help="File with tag names")
492 c38c44ad Michael Hanselmann
493 c38c44ad Michael Hanselmann
SUBMIT_OPT = cli_option("--submit", dest="submit_only",
494 c38c44ad Michael Hanselmann
                        default=False, action="store_true",
495 c38c44ad Michael Hanselmann
                        help=("Submit the job and return the job ID, but"
496 c38c44ad Michael Hanselmann
                              " don't wait for the job to finish"))
497 c38c44ad Michael Hanselmann
498 c38c44ad Michael Hanselmann
SYNC_OPT = cli_option("--sync", dest="do_locking",
499 c38c44ad Michael Hanselmann
                      default=False, action="store_true",
500 c38c44ad Michael Hanselmann
                      help=("Grab locks while doing the queries"
501 c38c44ad Michael Hanselmann
                            " in order to ensure more consistent results"))
502 c38c44ad Michael Hanselmann
503 c38c44ad Michael Hanselmann
_DRY_RUN_OPT = cli_option("--dry-run", default=False,
504 c38c44ad Michael Hanselmann
                          action="store_true",
505 c38c44ad Michael Hanselmann
                          help=("Do not execute the operation, just run the"
506 c38c44ad Michael Hanselmann
                                " check steps and verify it it could be"
507 c38c44ad Michael Hanselmann
                                " executed"))
508 c38c44ad Michael Hanselmann
509 9cdb9578 Iustin Pop
VERBOSE_OPT = cli_option("-v", "--verbose", default=False,
510 9cdb9578 Iustin Pop
                         action="store_true",
511 9cdb9578 Iustin Pop
                         help="Increase the verbosity of the operation")
512 9cdb9578 Iustin Pop
513 a0c9776a Iustin Pop
DEBUG_SIMERR_OPT = cli_option("--debug-simulate-errors", default=False,
514 a0c9776a Iustin Pop
                              action="store_true", dest="simulate_errors",
515 a0c9776a Iustin Pop
                              help="Debugging option that makes the operation"
516 a0c9776a Iustin Pop
                              " treat most runtime checks as failed")
517 a0c9776a Iustin Pop
518 3f75b4f3 Iustin Pop
NWSYNC_OPT = cli_option("--no-wait-for-sync", dest="wait_for_sync",
519 3f75b4f3 Iustin Pop
                        default=True, action="store_false",
520 3f75b4f3 Iustin Pop
                        help="Don't wait for sync (DANGEROUS!)")
521 3f75b4f3 Iustin Pop
522 4f365444 Iustin Pop
DISK_TEMPLATE_OPT = cli_option("-t", "--disk-template", dest="disk_template",
523 4f365444 Iustin Pop
                               help="Custom disk setup (diskless, file,"
524 4f365444 Iustin Pop
                               " plain or drbd)",
525 4f365444 Iustin Pop
                               default=None, metavar="TEMPL",
526 4f365444 Iustin Pop
                               choices=list(constants.DISK_TEMPLATES))
527 4f365444 Iustin Pop
528 26023ecd Iustin Pop
NONICS_OPT = cli_option("--no-nics", default=False, action="store_true",
529 26023ecd Iustin Pop
                        help="Do not create any network cards for"
530 26023ecd Iustin Pop
                        " the instance")
531 26023ecd Iustin Pop
532 4a25828c Iustin Pop
FILESTORE_DIR_OPT = cli_option("--file-storage-dir", dest="file_storage_dir",
533 4a25828c Iustin Pop
                               help="Relative path under default cluster-wide"
534 4a25828c Iustin Pop
                               " file storage dir to store file-based disks",
535 4a25828c Iustin Pop
                               default=None, metavar="<DIR>")
536 4a25828c Iustin Pop
537 0f87c43e Iustin Pop
FILESTORE_DRIVER_OPT = cli_option("--file-driver", dest="file_driver",
538 0f87c43e Iustin Pop
                                  help="Driver to use for image files",
539 0f87c43e Iustin Pop
                                  default="loop", metavar="<DRIVER>",
540 0f87c43e Iustin Pop
                                  choices=list(constants.FILE_DRIVER))
541 0f87c43e Iustin Pop
542 4eb62659 Iustin Pop
IALLOCATOR_OPT = cli_option("-I", "--iallocator", metavar="<NAME>",
543 4eb62659 Iustin Pop
                            help="Select nodes for the instance automatically"
544 4eb62659 Iustin Pop
                            " using the <NAME> iallocator plugin",
545 4eb62659 Iustin Pop
                            default=None, type="string",
546 4eb62659 Iustin Pop
                            completion_suggest=OPT_COMPL_ONE_IALLOCATOR)
547 4eb62659 Iustin Pop
548 d3ed23ff Iustin Pop
OS_OPT = cli_option("-o", "--os-type", dest="os", help="What OS to run",
549 d3ed23ff Iustin Pop
                    metavar="<os>",
550 d3ed23ff Iustin Pop
                    completion_suggest=OPT_COMPL_ONE_OS)
551 d3ed23ff Iustin Pop
552 087ed2ed Iustin Pop
BACKEND_OPT = cli_option("-B", "--backend-parameters", dest="beparams",
553 087ed2ed Iustin Pop
                         type="keyval", default={},
554 087ed2ed Iustin Pop
                         help="Backend parameters")
555 48f212d7 Iustin Pop
556 48f212d7 Iustin Pop
HVOPTS_OPT =  cli_option("-H", "--hypervisor-parameters", type="keyval",
557 48f212d7 Iustin Pop
                         default={}, dest="hvparams",
558 48f212d7 Iustin Pop
                         help="Hypervisor parameters")
559 087ed2ed Iustin Pop
560 236fd9c4 Iustin Pop
HYPERVISOR_OPT = cli_option("-H", "--hypervisor-parameters", dest="hypervisor",
561 236fd9c4 Iustin Pop
                            help="Hypervisor and hypervisor options, in the"
562 236fd9c4 Iustin Pop
                            " format hypervisor:option=value,option=value,...",
563 236fd9c4 Iustin Pop
                            default=None, type="identkeyval")
564 073271f6 Iustin Pop
565 073271f6 Iustin Pop
HVLIST_OPT = cli_option("-H", "--hypervisor-parameters", dest="hvparams",
566 073271f6 Iustin Pop
                        help="Hypervisor and hypervisor options, in the"
567 073271f6 Iustin Pop
                        " format hypervisor:option=value,option=value,...",
568 073271f6 Iustin Pop
                        default=[], action="append", type="identkeyval")
569 236fd9c4 Iustin Pop
570 91e0748c Iustin Pop
NOIPCHECK_OPT = cli_option("--no-ip-check", dest="ip_check", default=True,
571 91e0748c Iustin Pop
                           action="store_false",
572 91e0748c Iustin Pop
                           help="Don't check that the instance's IP"
573 91e0748c Iustin Pop
                           " is alive")
574 91e0748c Iustin Pop
575 7d3a9fab Iustin Pop
NET_OPT = cli_option("--net",
576 7d3a9fab Iustin Pop
                     help="NIC parameters", default=[],
577 7d3a9fab Iustin Pop
                     dest="nics", action="append", type="identkeyval")
578 e3876ccb Iustin Pop
579 e3876ccb Iustin Pop
DISK_OPT = cli_option("--disk", help="Disk parameters", default=[],
580 e3876ccb Iustin Pop
                      dest="disks", action="append", type="identkeyval")
581 91e0748c Iustin Pop
582 4b038a1e Iustin Pop
DISKIDX_OPT = cli_option("--disks", dest="disks", default=None,
583 4b038a1e Iustin Pop
                         help="Comma-separated list of disks"
584 4b038a1e Iustin Pop
                         " indices to act on (e.g. 0,2) (optional,"
585 4b038a1e Iustin Pop
                         " defaults to all disks)")
586 4b038a1e Iustin Pop
587 ff00c1a7 Iustin Pop
OS_SIZE_OPT = cli_option("-s", "--os-size", dest="sd_size",
588 ff00c1a7 Iustin Pop
                         help="Enforces a single-disk configuration using the"
589 ff00c1a7 Iustin Pop
                         " given disk size, in MiB unless a suffix is used",
590 ff00c1a7 Iustin Pop
                         default=None, type="unit", metavar="<size>")
591 ff00c1a7 Iustin Pop
592 82a786d5 Iustin Pop
IGNORE_CONSIST_OPT = cli_option("--ignore-consistency",
593 82a786d5 Iustin Pop
                                dest="ignore_consistency",
594 82a786d5 Iustin Pop
                                action="store_true", default=False,
595 82a786d5 Iustin Pop
                                help="Ignore the consistency of the disks on"
596 82a786d5 Iustin Pop
                                " the secondary")
597 82a786d5 Iustin Pop
598 f2a0828c Iustin Pop
NONLIVE_OPT = cli_option("--non-live", dest="live",
599 f2a0828c Iustin Pop
                         default=True, action="store_false",
600 f2a0828c Iustin Pop
                         help="Do a non-live migration (this usually means"
601 f2a0828c Iustin Pop
                         " freeze the instance, save the state, transfer and"
602 f2a0828c Iustin Pop
                         " only then resume running on the secondary node)")
603 f2a0828c Iustin Pop
604 990b7886 Iustin Pop
NODE_PLACEMENT_OPT = cli_option("-n", "--node", dest="node",
605 990b7886 Iustin Pop
                                help="Target node and optional secondary node",
606 990b7886 Iustin Pop
                                metavar="<pnode>[:<snode>]",
607 990b7886 Iustin Pop
                                completion_suggest=OPT_COMPL_INST_ADD_NODES)
608 990b7886 Iustin Pop
609 7edc4637 Iustin Pop
NODE_LIST_OPT = cli_option("-n", "--node", dest="nodes", default=[],
610 7edc4637 Iustin Pop
                           action="append", metavar="<node>",
611 7edc4637 Iustin Pop
                           help="Use only this node (can be used multiple"
612 7edc4637 Iustin Pop
                           " times, if not given defaults to all nodes)",
613 7edc4637 Iustin Pop
                           completion_suggest=OPT_COMPL_ONE_NODE)
614 f36d7d81 Iustin Pop
615 f36d7d81 Iustin Pop
SINGLE_NODE_OPT = cli_option("-n", "--node", dest="node", help="Target node",
616 f36d7d81 Iustin Pop
                             metavar="<node>",
617 f36d7d81 Iustin Pop
                             completion_suggest=OPT_COMPL_ONE_NODE)
618 7edc4637 Iustin Pop
619 edeb878a Iustin Pop
NOSTART_OPT = cli_option("--no-start", dest="start", default=True,
620 edeb878a Iustin Pop
                         action="store_false",
621 edeb878a Iustin Pop
                         help="Don't start the instance after creation")
622 edeb878a Iustin Pop
623 fdcf4d84 Iustin Pop
SHOWCMD_OPT = cli_option("--show-cmd", dest="show_command",
624 fdcf4d84 Iustin Pop
                         action="store_true", default=False,
625 fdcf4d84 Iustin Pop
                         help="Show command instead of executing it")
626 fdcf4d84 Iustin Pop
627 baef337d Iustin Pop
CLEANUP_OPT = cli_option("--cleanup", dest="cleanup",
628 baef337d Iustin Pop
                         default=False, action="store_true",
629 baef337d Iustin Pop
                         help="Instead of performing the migration, try to"
630 baef337d Iustin Pop
                         " recover from a failed cleanup. This is safe"
631 baef337d Iustin Pop
                         " to run even if the instance is healthy, but it"
632 baef337d Iustin Pop
                         " will create extra replication traffic and "
633 baef337d Iustin Pop
                         " disrupt briefly the replication (like during the"
634 baef337d Iustin Pop
                         " migration")
635 baef337d Iustin Pop
636 99a8c799 Iustin Pop
STATIC_OPT = cli_option("-s", "--static", dest="static",
637 99a8c799 Iustin Pop
                        action="store_true", default=False,
638 99a8c799 Iustin Pop
                        help="Only show configuration data, not runtime data")
639 99a8c799 Iustin Pop
640 2d5e7ae1 Iustin Pop
ALL_OPT = cli_option("--all", dest="show_all",
641 2d5e7ae1 Iustin Pop
                     default=False, action="store_true",
642 2d5e7ae1 Iustin Pop
                     help="Show info on all instances on the cluster."
643 2d5e7ae1 Iustin Pop
                     " This can take a long time to run, use wisely")
644 2d5e7ae1 Iustin Pop
645 67840b40 Iustin Pop
SELECT_OS_OPT = cli_option("--select-os", dest="select_os",
646 67840b40 Iustin Pop
                           action="store_true", default=False,
647 67840b40 Iustin Pop
                           help="Interactive OS reinstall, lists available"
648 67840b40 Iustin Pop
                           " OS templates for selection")
649 2d5e7ae1 Iustin Pop
650 b6e841a8 Iustin Pop
IGNORE_FAILURES_OPT = cli_option("--ignore-failures", dest="ignore_failures",
651 b6e841a8 Iustin Pop
                                 action="store_true", default=False,
652 b6e841a8 Iustin Pop
                                 help="Remove the instance from the cluster"
653 b6e841a8 Iustin Pop
                                 " configuration even if there are failures"
654 b6e841a8 Iustin Pop
                                 " during the removal process")
655 b6e841a8 Iustin Pop
656 a14db5ff Iustin Pop
NEW_SECONDARY_OPT = cli_option("-n", "--new-secondary", dest="dst_node",
657 a14db5ff Iustin Pop
                               help="Specifies the new secondary node",
658 a14db5ff Iustin Pop
                               metavar="NODE", default=None,
659 a14db5ff Iustin Pop
                               completion_suggest=OPT_COMPL_ONE_NODE)
660 a14db5ff Iustin Pop
661 a72d0a79 Iustin Pop
ON_PRIMARY_OPT = cli_option("-p", "--on-primary", dest="on_primary",
662 a72d0a79 Iustin Pop
                            default=False, action="store_true",
663 a72d0a79 Iustin Pop
                            help="Replace the disk(s) on the primary"
664 a72d0a79 Iustin Pop
                            " node (only for the drbd template)")
665 feb09e6a Iustin Pop
666 feb09e6a Iustin Pop
ON_SECONDARY_OPT = cli_option("-s", "--on-secondary", dest="on_secondary",
667 feb09e6a Iustin Pop
                              default=False, action="store_true",
668 feb09e6a Iustin Pop
                              help="Replace the disk(s) on the secondary"
669 feb09e6a Iustin Pop
                              " node (only for the drbd template)")
670 e00f7a05 Iustin Pop
671 e00f7a05 Iustin Pop
AUTO_REPLACE_OPT = cli_option("-a", "--auto", dest="auto",
672 e00f7a05 Iustin Pop
                              default=False, action="store_true",
673 e00f7a05 Iustin Pop
                              help="Automatically replace faulty disks"
674 e00f7a05 Iustin Pop
                              " (only for the drbd template)")
675 a72d0a79 Iustin Pop
676 05586c90 Iustin Pop
IGNORE_SIZE_OPT = cli_option("--ignore-size", dest="ignore_size",
677 05586c90 Iustin Pop
                             default=False, action="store_true",
678 05586c90 Iustin Pop
                             help="Ignore current recorded size"
679 05586c90 Iustin Pop
                             " (useful for forcing activation when"
680 05586c90 Iustin Pop
                             " the recorded size is wrong)")
681 05586c90 Iustin Pop
682 df62e5db Iustin Pop
SRC_NODE_OPT = cli_option("--src-node", dest="src_node", help="Source node",
683 df62e5db Iustin Pop
                          metavar="<node>",
684 df62e5db Iustin Pop
                          completion_suggest=OPT_COMPL_ONE_NODE)
685 df62e5db Iustin Pop
686 df62e5db Iustin Pop
SRC_DIR_OPT = cli_option("--src-dir", dest="src_dir", help="Source directory",
687 df62e5db Iustin Pop
                         metavar="<dir>")
688 df62e5db Iustin Pop
689 8d823629 Iustin Pop
SECONDARY_IP_OPT = cli_option("-s", "--secondary-ip", dest="secondary_ip",
690 8d823629 Iustin Pop
                              help="Specify the secondary ip for the node",
691 8d823629 Iustin Pop
                              metavar="ADDRESS", default=None)
692 8d823629 Iustin Pop
693 b8d0f938 Iustin Pop
READD_OPT = cli_option("--readd", dest="readd",
694 b8d0f938 Iustin Pop
                       default=False, action="store_true",
695 b8d0f938 Iustin Pop
                       help="Readd old node after replacing it")
696 b8d0f938 Iustin Pop
697 fcdde7f2 Iustin Pop
NOSSH_KEYCHECK_OPT = cli_option("--no-ssh-key-check", dest="ssh_key_check",
698 fcdde7f2 Iustin Pop
                                default=True, action="store_false",
699 fcdde7f2 Iustin Pop
                                help="Disable SSH key fingerprint checking")
700 fcdde7f2 Iustin Pop
701 c38c44ad Michael Hanselmann
702 771734c9 Iustin Pop
MC_OPT = cli_option("-C", "--master-candidate", dest="master_candidate",
703 771734c9 Iustin Pop
                    choices=_YESNO, default=None, metavar=_YORNO,
704 771734c9 Iustin Pop
                    help="Set the master_candidate flag on the node")
705 771734c9 Iustin Pop
706 771734c9 Iustin Pop
OFFLINE_OPT = cli_option("-O", "--offline", dest="offline", metavar=_YORNO,
707 771734c9 Iustin Pop
                         choices=_YESNO, default=None,
708 771734c9 Iustin Pop
                         help="Set the offline flag on the node")
709 771734c9 Iustin Pop
710 771734c9 Iustin Pop
DRAINED_OPT = cli_option("-D", "--drained", dest="drained", metavar=_YORNO,
711 771734c9 Iustin Pop
                         choices=_YESNO, default=None,
712 771734c9 Iustin Pop
                         help="Set the drained flag on the node")
713 771734c9 Iustin Pop
714 e7e09483 Iustin Pop
ALLOCATABLE_OPT = cli_option("--allocatable", dest="allocatable",
715 e7e09483 Iustin Pop
                             choices=_YESNO, default=None, metavar=_YORNO,
716 e7e09483 Iustin Pop
                             help="Set the allocatable flag on a volume")
717 e7e09483 Iustin Pop
718 771734c9 Iustin Pop
719 de47cf8f Guido Trotter
def _ParseArgs(argv, commands, aliases):
720 c41eea6e Iustin Pop
  """Parser for the command line arguments.
721 a8083063 Iustin Pop

722 5bbd3f7f Michael Hanselmann
  This function parses the arguments and returns the function which
723 c41eea6e Iustin Pop
  must be executed together with its (modified) arguments.
724 a8083063 Iustin Pop

725 c41eea6e Iustin Pop
  @param argv: the command line
726 c41eea6e Iustin Pop
  @param commands: dictionary with special contents, see the design
727 c41eea6e Iustin Pop
      doc for cmdline handling
728 c41eea6e Iustin Pop
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
729 098c0958 Michael Hanselmann

730 a8083063 Iustin Pop
  """
731 a8083063 Iustin Pop
  if len(argv) == 0:
732 a8083063 Iustin Pop
    binary = "<command>"
733 a8083063 Iustin Pop
  else:
734 a8083063 Iustin Pop
    binary = argv[0].split("/")[-1]
735 a8083063 Iustin Pop
736 a8083063 Iustin Pop
  if len(argv) > 1 and argv[1] == "--version":
737 03298ebe Michael Hanselmann
    ToStdout("%s (ganeti) %s", binary, constants.RELEASE_VERSION)
738 a8083063 Iustin Pop
    # Quit right away. That way we don't have to care about this special
739 a8083063 Iustin Pop
    # argument. optparse.py does it the same.
740 a8083063 Iustin Pop
    sys.exit(0)
741 a8083063 Iustin Pop
742 de47cf8f Guido Trotter
  if len(argv) < 2 or not (argv[1] in commands or
743 70a35b6f Guido Trotter
                           argv[1] in aliases):
744 a8083063 Iustin Pop
    # let's do a nice thing
745 a8083063 Iustin Pop
    sortedcmds = commands.keys()
746 a8083063 Iustin Pop
    sortedcmds.sort()
747 03298ebe Michael Hanselmann
748 03298ebe Michael Hanselmann
    ToStdout("Usage: %s {command} [options...] [argument...]", binary)
749 03298ebe Michael Hanselmann
    ToStdout("%s <command> --help to see details, or man %s", binary, binary)
750 03298ebe Michael Hanselmann
    ToStdout("")
751 03298ebe Michael Hanselmann
752 a8083063 Iustin Pop
    # compute the max line length for cmd + usage
753 4e713df6 Iustin Pop
    mlen = max([len(" %s" % cmd) for cmd in commands])
754 a8083063 Iustin Pop
    mlen = min(60, mlen) # should not get here...
755 03298ebe Michael Hanselmann
756 a8083063 Iustin Pop
    # and format a nice command list
757 03298ebe Michael Hanselmann
    ToStdout("Commands:")
758 a8083063 Iustin Pop
    for cmd in sortedcmds:
759 4e713df6 Iustin Pop
      cmdstr = " %s" % (cmd,)
760 9a033156 Iustin Pop
      help_text = commands[cmd][4]
761 03298ebe Michael Hanselmann
      help_lines = textwrap.wrap(help_text, 79 - 3 - mlen)
762 03298ebe Michael Hanselmann
      ToStdout("%-*s - %s", mlen, cmdstr, help_lines.pop(0))
763 a8083063 Iustin Pop
      for line in help_lines:
764 03298ebe Michael Hanselmann
        ToStdout("%-*s   %s", mlen, "", line)
765 03298ebe Michael Hanselmann
766 03298ebe Michael Hanselmann
    ToStdout("")
767 03298ebe Michael Hanselmann
768 a8083063 Iustin Pop
    return None, None, None
769 de47cf8f Guido Trotter
770 de47cf8f Guido Trotter
  # get command, unalias it, and look it up in commands
771 a8083063 Iustin Pop
  cmd = argv.pop(1)
772 de47cf8f Guido Trotter
  if cmd in aliases:
773 de47cf8f Guido Trotter
    if cmd in commands:
774 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' overrides an existing"
775 de47cf8f Guido Trotter
                                   " command" % cmd)
776 de47cf8f Guido Trotter
777 de47cf8f Guido Trotter
    if aliases[cmd] not in commands:
778 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' maps to non-existing"
779 de47cf8f Guido Trotter
                                   " command '%s'" % (cmd, aliases[cmd]))
780 de47cf8f Guido Trotter
781 de47cf8f Guido Trotter
    cmd = aliases[cmd]
782 de47cf8f Guido Trotter
783 a8005e17 Michael Hanselmann
  func, args_def, parser_opts, usage, description = commands[cmd]
784 64c65a2a Iustin Pop
  parser = OptionParser(option_list=parser_opts + [_DRY_RUN_OPT],
785 a8083063 Iustin Pop
                        description=description,
786 a8083063 Iustin Pop
                        formatter=TitledHelpFormatter(),
787 a8083063 Iustin Pop
                        usage="%%prog %s %s" % (cmd, usage))
788 a8083063 Iustin Pop
  parser.disable_interspersed_args()
789 a8083063 Iustin Pop
  options, args = parser.parse_args()
790 a8005e17 Michael Hanselmann
791 a8005e17 Michael Hanselmann
  if not _CheckArguments(cmd, args_def, args):
792 a8083063 Iustin Pop
    return None, None, None
793 a8083063 Iustin Pop
794 a8083063 Iustin Pop
  return func, options, args
795 a8083063 Iustin Pop
796 a8083063 Iustin Pop
797 a8005e17 Michael Hanselmann
def _CheckArguments(cmd, args_def, args):
798 a8005e17 Michael Hanselmann
  """Verifies the arguments using the argument definition.
799 a8005e17 Michael Hanselmann

800 a8005e17 Michael Hanselmann
  Algorithm:
801 a8005e17 Michael Hanselmann

802 a8005e17 Michael Hanselmann
    1. Abort with error if values specified by user but none expected.
803 a8005e17 Michael Hanselmann

804 a8005e17 Michael Hanselmann
    1. For each argument in definition
805 a8005e17 Michael Hanselmann

806 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
807 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
808 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
809 a8005e17 Michael Hanselmann

810 a8005e17 Michael Hanselmann
        1. Abort with error if it's not the last argument in the definition
811 a8005e17 Michael Hanselmann

812 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
813 a8005e17 Michael Hanselmann

814 a8005e17 Michael Hanselmann
      1. Abort with error if number of values doesn't match or is too large
815 a8005e17 Michael Hanselmann

816 a8005e17 Michael Hanselmann
    1. Abort with error if user didn't pass enough values (min_count)
817 a8005e17 Michael Hanselmann

818 a8005e17 Michael Hanselmann
  """
819 a8005e17 Michael Hanselmann
  if args and not args_def:
820 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects no arguments", cmd)
821 a8005e17 Michael Hanselmann
    return False
822 a8005e17 Michael Hanselmann
823 a8005e17 Michael Hanselmann
  min_count = None
824 a8005e17 Michael Hanselmann
  max_count = None
825 a8005e17 Michael Hanselmann
  check_max = None
826 a8005e17 Michael Hanselmann
827 a8005e17 Michael Hanselmann
  last_idx = len(args_def) - 1
828 a8005e17 Michael Hanselmann
829 a8005e17 Michael Hanselmann
  for idx, arg in enumerate(args_def):
830 a8005e17 Michael Hanselmann
    if min_count is None:
831 a8005e17 Michael Hanselmann
      min_count = arg.min
832 a8005e17 Michael Hanselmann
    elif arg.min is not None:
833 a8005e17 Michael Hanselmann
      min_count += arg.min
834 a8005e17 Michael Hanselmann
835 a8005e17 Michael Hanselmann
    if max_count is None:
836 a8005e17 Michael Hanselmann
      max_count = arg.max
837 a8005e17 Michael Hanselmann
    elif arg.max is not None:
838 a8005e17 Michael Hanselmann
      max_count += arg.max
839 a8005e17 Michael Hanselmann
840 a8005e17 Michael Hanselmann
    if idx == last_idx:
841 a8005e17 Michael Hanselmann
      check_max = (arg.max is not None)
842 a8005e17 Michael Hanselmann
843 a8005e17 Michael Hanselmann
    elif arg.max is None:
844 a8005e17 Michael Hanselmann
      raise errors.ProgrammerError("Only the last argument can have max=None")
845 a8005e17 Michael Hanselmann
846 a8005e17 Michael Hanselmann
  if check_max:
847 a8005e17 Michael Hanselmann
    # Command with exact number of arguments
848 a8005e17 Michael Hanselmann
    if (min_count is not None and max_count is not None and
849 a8005e17 Michael Hanselmann
        min_count == max_count and len(args) != min_count):
850 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects %d argument(s)", cmd, min_count)
851 a8005e17 Michael Hanselmann
      return False
852 a8005e17 Michael Hanselmann
853 a8005e17 Michael Hanselmann
    # Command with limited number of arguments
854 a8005e17 Michael Hanselmann
    if max_count is not None and len(args) > max_count:
855 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects only %d argument(s)",
856 a8005e17 Michael Hanselmann
               cmd, max_count)
857 a8005e17 Michael Hanselmann
      return False
858 a8005e17 Michael Hanselmann
859 a8005e17 Michael Hanselmann
  # Command with some required arguments
860 a8005e17 Michael Hanselmann
  if min_count is not None and len(args) < min_count:
861 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects at least %d argument(s)",
862 a8005e17 Michael Hanselmann
             cmd, min_count)
863 a8005e17 Michael Hanselmann
    return False
864 a8005e17 Michael Hanselmann
865 a8005e17 Michael Hanselmann
  return True
866 a8005e17 Michael Hanselmann
867 a8005e17 Michael Hanselmann
868 60d49723 Michael Hanselmann
def SplitNodeOption(value):
869 60d49723 Michael Hanselmann
  """Splits the value of a --node option.
870 60d49723 Michael Hanselmann

871 60d49723 Michael Hanselmann
  """
872 60d49723 Michael Hanselmann
  if value and ':' in value:
873 60d49723 Michael Hanselmann
    return value.split(':', 1)
874 60d49723 Michael Hanselmann
  else:
875 60d49723 Michael Hanselmann
    return (value, None)
876 60d49723 Michael Hanselmann
877 60d49723 Michael Hanselmann
878 4331f6cd Michael Hanselmann
def UsesRPC(fn):
879 4331f6cd Michael Hanselmann
  def wrapper(*args, **kwargs):
880 4331f6cd Michael Hanselmann
    rpc.Init()
881 4331f6cd Michael Hanselmann
    try:
882 4331f6cd Michael Hanselmann
      return fn(*args, **kwargs)
883 4331f6cd Michael Hanselmann
    finally:
884 4331f6cd Michael Hanselmann
      rpc.Shutdown()
885 4331f6cd Michael Hanselmann
  return wrapper
886 4331f6cd Michael Hanselmann
887 4331f6cd Michael Hanselmann
888 47988778 Iustin Pop
def AskUser(text, choices=None):
889 47988778 Iustin Pop
  """Ask the user a question.
890 a8083063 Iustin Pop

891 c41eea6e Iustin Pop
  @param text: the question to ask
892 a8083063 Iustin Pop

893 c41eea6e Iustin Pop
  @param choices: list with elements tuples (input_char, return_value,
894 c41eea6e Iustin Pop
      description); if not given, it will default to: [('y', True,
895 c41eea6e Iustin Pop
      'Perform the operation'), ('n', False, 'Do no do the operation')];
896 c41eea6e Iustin Pop
      note that the '?' char is reserved for help
897 47988778 Iustin Pop

898 c41eea6e Iustin Pop
  @return: one of the return values from the choices list; if input is
899 c41eea6e Iustin Pop
      not possible (i.e. not running with a tty, we return the last
900 c41eea6e Iustin Pop
      entry from the list
901 a8083063 Iustin Pop

902 a8083063 Iustin Pop
  """
903 47988778 Iustin Pop
  if choices is None:
904 47988778 Iustin Pop
    choices = [('y', True, 'Perform the operation'),
905 47988778 Iustin Pop
               ('n', False, 'Do not perform the operation')]
906 47988778 Iustin Pop
  if not choices or not isinstance(choices, list):
907 5bbd3f7f Michael Hanselmann
    raise errors.ProgrammerError("Invalid choices argument to AskUser")
908 47988778 Iustin Pop
  for entry in choices:
909 47988778 Iustin Pop
    if not isinstance(entry, tuple) or len(entry) < 3 or entry[0] == '?':
910 5bbd3f7f Michael Hanselmann
      raise errors.ProgrammerError("Invalid choices element to AskUser")
911 47988778 Iustin Pop
912 47988778 Iustin Pop
  answer = choices[-1][1]
913 47988778 Iustin Pop
  new_text = []
914 47988778 Iustin Pop
  for line in text.splitlines():
915 47988778 Iustin Pop
    new_text.append(textwrap.fill(line, 70, replace_whitespace=False))
916 47988778 Iustin Pop
  text = "\n".join(new_text)
917 a8083063 Iustin Pop
  try:
918 3023170f Iustin Pop
    f = file("/dev/tty", "a+")
919 a8083063 Iustin Pop
  except IOError:
920 47988778 Iustin Pop
    return answer
921 a8083063 Iustin Pop
  try:
922 47988778 Iustin Pop
    chars = [entry[0] for entry in choices]
923 47988778 Iustin Pop
    chars[-1] = "[%s]" % chars[-1]
924 47988778 Iustin Pop
    chars.append('?')
925 47988778 Iustin Pop
    maps = dict([(entry[0], entry[1]) for entry in choices])
926 47988778 Iustin Pop
    while True:
927 47988778 Iustin Pop
      f.write(text)
928 47988778 Iustin Pop
      f.write('\n')
929 47988778 Iustin Pop
      f.write("/".join(chars))
930 47988778 Iustin Pop
      f.write(": ")
931 47988778 Iustin Pop
      line = f.readline(2).strip().lower()
932 47988778 Iustin Pop
      if line in maps:
933 47988778 Iustin Pop
        answer = maps[line]
934 47988778 Iustin Pop
        break
935 47988778 Iustin Pop
      elif line == '?':
936 47988778 Iustin Pop
        for entry in choices:
937 47988778 Iustin Pop
          f.write(" %s - %s\n" % (entry[0], entry[2]))
938 47988778 Iustin Pop
        f.write("\n")
939 47988778 Iustin Pop
        continue
940 a8083063 Iustin Pop
  finally:
941 a8083063 Iustin Pop
    f.close()
942 a8083063 Iustin Pop
  return answer
943 a8083063 Iustin Pop
944 a8083063 Iustin Pop
945 e9d741b6 Iustin Pop
class JobSubmittedException(Exception):
946 e9d741b6 Iustin Pop
  """Job was submitted, client should exit.
947 e9d741b6 Iustin Pop

948 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
949 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
950 e9d741b6 Iustin Pop

951 e9d741b6 Iustin Pop
  This is not an error, just a structured way to exit from clients.
952 e9d741b6 Iustin Pop

953 e9d741b6 Iustin Pop
  """
954 e9d741b6 Iustin Pop
955 e9d741b6 Iustin Pop
956 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
957 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
958 a8083063 Iustin Pop

959 0a1e74d9 Iustin Pop
  @type ops: list
960 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
961 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
962 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
963 0a1e74d9 Iustin Pop
             if None, a new client will be created
964 a8083063 Iustin Pop

965 a8083063 Iustin Pop
  """
966 e2212007 Iustin Pop
  if cl is None:
967 b33e986b Iustin Pop
    cl = GetClient()
968 685ee993 Iustin Pop
969 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
970 0a1e74d9 Iustin Pop
971 0a1e74d9 Iustin Pop
  return job_id
972 0a1e74d9 Iustin Pop
973 0a1e74d9 Iustin Pop
974 281606c1 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None):
975 0a1e74d9 Iustin Pop
  """Function to poll for the result of a job.
976 0a1e74d9 Iustin Pop

977 0a1e74d9 Iustin Pop
  @type job_id: job identified
978 0a1e74d9 Iustin Pop
  @param job_id: the job to poll for results
979 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
980 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
981 0a1e74d9 Iustin Pop
             if None, a new client will be created
982 0a1e74d9 Iustin Pop

983 0a1e74d9 Iustin Pop
  """
984 0a1e74d9 Iustin Pop
  if cl is None:
985 0a1e74d9 Iustin Pop
    cl = GetClient()
986 685ee993 Iustin Pop
987 6c5a7090 Michael Hanselmann
  prev_job_info = None
988 6c5a7090 Michael Hanselmann
  prev_logmsg_serial = None
989 6c5a7090 Michael Hanselmann
990 685ee993 Iustin Pop
  while True:
991 6c5a7090 Michael Hanselmann
    result = cl.WaitForJobChange(job_id, ["status"], prev_job_info,
992 6c5a7090 Michael Hanselmann
                                 prev_logmsg_serial)
993 6c5a7090 Michael Hanselmann
    if not result:
994 685ee993 Iustin Pop
      # job not found, go away!
995 0bbe448c Michael Hanselmann
      raise errors.JobLost("Job with id %s lost" % job_id)
996 685ee993 Iustin Pop
997 6c5a7090 Michael Hanselmann
    # Split result, a tuple of (field values, log entries)
998 6c5a7090 Michael Hanselmann
    (job_info, log_entries) = result
999 6c5a7090 Michael Hanselmann
    (status, ) = job_info
1000 6c5a7090 Michael Hanselmann
1001 6c5a7090 Michael Hanselmann
    if log_entries:
1002 6c5a7090 Michael Hanselmann
      for log_entry in log_entries:
1003 6c5a7090 Michael Hanselmann
        (serial, timestamp, _, message) = log_entry
1004 6c5a7090 Michael Hanselmann
        if callable(feedback_fn):
1005 6c5a7090 Michael Hanselmann
          feedback_fn(log_entry[1:])
1006 6c5a7090 Michael Hanselmann
        else:
1007 26f15862 Iustin Pop
          encoded = utils.SafeEncode(message)
1008 03298ebe Michael Hanselmann
          ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)), encoded)
1009 6c5a7090 Michael Hanselmann
        prev_logmsg_serial = max(prev_logmsg_serial, serial)
1010 6c5a7090 Michael Hanselmann
1011 0bbe448c Michael Hanselmann
    # TODO: Handle canceled and archived jobs
1012 fbf0262f Michael Hanselmann
    elif status in (constants.JOB_STATUS_SUCCESS,
1013 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_ERROR,
1014 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELING,
1015 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELED):
1016 685ee993 Iustin Pop
      break
1017 6c5a7090 Michael Hanselmann
1018 6c5a7090 Michael Hanselmann
    prev_job_info = job_info
1019 685ee993 Iustin Pop
1020 0e050889 Iustin Pop
  jobs = cl.QueryJobs([job_id], ["status", "opstatus", "opresult"])
1021 0bbe448c Michael Hanselmann
  if not jobs:
1022 0bbe448c Michael Hanselmann
    raise errors.JobLost("Job with id %s lost" % job_id)
1023 685ee993 Iustin Pop
1024 0e050889 Iustin Pop
  status, opstatus, result = jobs[0]
1025 0bbe448c Michael Hanselmann
  if status == constants.JOB_STATUS_SUCCESS:
1026 53c04d04 Iustin Pop
    return result
1027 fbf0262f Michael Hanselmann
  elif status in (constants.JOB_STATUS_CANCELING,
1028 fbf0262f Michael Hanselmann
                  constants.JOB_STATUS_CANCELED):
1029 fbf0262f Michael Hanselmann
    raise errors.OpExecError("Job was canceled")
1030 0bbe448c Michael Hanselmann
  else:
1031 0e050889 Iustin Pop
    has_ok = False
1032 0e050889 Iustin Pop
    for idx, (status, msg) in enumerate(zip(opstatus, result)):
1033 0e050889 Iustin Pop
      if status == constants.OP_STATUS_SUCCESS:
1034 0e050889 Iustin Pop
        has_ok = True
1035 0e050889 Iustin Pop
      elif status == constants.OP_STATUS_ERROR:
1036 bcb66fca Iustin Pop
        errors.MaybeRaise(msg)
1037 0e050889 Iustin Pop
        if has_ok:
1038 0e050889 Iustin Pop
          raise errors.OpExecError("partial failure (opcode %d): %s" %
1039 0e050889 Iustin Pop
                                   (idx, msg))
1040 0e050889 Iustin Pop
        else:
1041 0e050889 Iustin Pop
          raise errors.OpExecError(str(msg))
1042 0e050889 Iustin Pop
    # default failure mode
1043 0bbe448c Michael Hanselmann
    raise errors.OpExecError(result)
1044 ceab32dd Iustin Pop
1045 ceab32dd Iustin Pop
1046 0a1e74d9 Iustin Pop
def SubmitOpCode(op, cl=None, feedback_fn=None):
1047 0a1e74d9 Iustin Pop
  """Legacy function to submit an opcode.
1048 0a1e74d9 Iustin Pop

1049 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1050 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1051 0a1e74d9 Iustin Pop
  interaction functions.
1052 0a1e74d9 Iustin Pop

1053 0a1e74d9 Iustin Pop
  """
1054 0a1e74d9 Iustin Pop
  if cl is None:
1055 0a1e74d9 Iustin Pop
    cl = GetClient()
1056 0a1e74d9 Iustin Pop
1057 0a1e74d9 Iustin Pop
  job_id = SendJob([op], cl)
1058 0a1e74d9 Iustin Pop
1059 53c04d04 Iustin Pop
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn)
1060 53c04d04 Iustin Pop
1061 53c04d04 Iustin Pop
  return op_results[0]
1062 0a1e74d9 Iustin Pop
1063 0a1e74d9 Iustin Pop
1064 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1065 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1066 94428652 Iustin Pop

1067 94428652 Iustin Pop
  This function will decide, based on the 'opts' parameter, whether to
1068 94428652 Iustin Pop
  submit and wait for the result of the opcode (and return it), or
1069 94428652 Iustin Pop
  whether to just send the job and print its identifier. It is used in
1070 94428652 Iustin Pop
  order to simplify the implementation of the '--submit' option.
1071 94428652 Iustin Pop

1072 64c65a2a Iustin Pop
  It will also add the dry-run parameter from the options passed, if true.
1073 64c65a2a Iustin Pop

1074 94428652 Iustin Pop
  """
1075 64c65a2a Iustin Pop
  if opts and opts.dry_run:
1076 64c65a2a Iustin Pop
    op.dry_run = opts.dry_run
1077 94428652 Iustin Pop
  if opts and opts.submit_only:
1078 e9d741b6 Iustin Pop
    job_id = SendJob([op], cl=cl)
1079 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
1080 94428652 Iustin Pop
  else:
1081 94428652 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn)
1082 94428652 Iustin Pop
1083 94428652 Iustin Pop
1084 af30b2fd Michael Hanselmann
def GetClient():
1085 af30b2fd Michael Hanselmann
  # TODO: Cache object?
1086 b33e986b Iustin Pop
  try:
1087 b33e986b Iustin Pop
    client = luxi.Client()
1088 b33e986b Iustin Pop
  except luxi.NoMasterError:
1089 b33e986b Iustin Pop
    master, myself = ssconf.GetMasterAndMyself()
1090 b33e986b Iustin Pop
    if master != myself:
1091 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
1092 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
1093 b33e986b Iustin Pop
                                 master)
1094 b33e986b Iustin Pop
    else:
1095 b33e986b Iustin Pop
      raise
1096 b33e986b Iustin Pop
  return client
1097 af30b2fd Michael Hanselmann
1098 af30b2fd Michael Hanselmann
1099 73702ee7 Iustin Pop
def FormatError(err):
1100 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
1101 73702ee7 Iustin Pop

1102 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
1103 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
1104 73702ee7 Iustin Pop
  second, a string describing the error message (not
1105 73702ee7 Iustin Pop
  newline-terminated).
1106 73702ee7 Iustin Pop

1107 73702ee7 Iustin Pop
  """
1108 73702ee7 Iustin Pop
  retcode = 1
1109 73702ee7 Iustin Pop
  obuf = StringIO()
1110 e2e521d0 Iustin Pop
  msg = str(err)
1111 73702ee7 Iustin Pop
  if isinstance(err, errors.ConfigurationError):
1112 e2e521d0 Iustin Pop
    txt = "Corrupt configuration file: %s" % msg
1113 46fbdd04 Iustin Pop
    logging.error(txt)
1114 e2e521d0 Iustin Pop
    obuf.write(txt + "\n")
1115 73702ee7 Iustin Pop
    obuf.write("Aborting.")
1116 73702ee7 Iustin Pop
    retcode = 2
1117 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksAbort):
1118 73702ee7 Iustin Pop
    obuf.write("Failure: hooks execution failed:\n")
1119 73702ee7 Iustin Pop
    for node, script, out in err.args[0]:
1120 73702ee7 Iustin Pop
      if out:
1121 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s, output: %s\n" %
1122 73702ee7 Iustin Pop
                   (node, script, out))
1123 73702ee7 Iustin Pop
      else:
1124 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s (no output)\n" %
1125 73702ee7 Iustin Pop
                   (node, script))
1126 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksFailure):
1127 e2e521d0 Iustin Pop
    obuf.write("Failure: hooks general failure: %s" % msg)
1128 73702ee7 Iustin Pop
  elif isinstance(err, errors.ResolverError):
1129 73702ee7 Iustin Pop
    this_host = utils.HostInfo.SysName()
1130 73702ee7 Iustin Pop
    if err.args[0] == this_host:
1131 73702ee7 Iustin Pop
      msg = "Failure: can't resolve my own hostname ('%s')"
1132 73702ee7 Iustin Pop
    else:
1133 73702ee7 Iustin Pop
      msg = "Failure: can't resolve hostname '%s'"
1134 73702ee7 Iustin Pop
    obuf.write(msg % err.args[0])
1135 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpPrereqError):
1136 73702ee7 Iustin Pop
    obuf.write("Failure: prerequisites not met for this"
1137 e2e521d0 Iustin Pop
               " operation:\n%s" % msg)
1138 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpExecError):
1139 e2e521d0 Iustin Pop
    obuf.write("Failure: command execution error:\n%s" % msg)
1140 73702ee7 Iustin Pop
  elif isinstance(err, errors.TagError):
1141 e2e521d0 Iustin Pop
    obuf.write("Failure: invalid tag(s) given:\n%s" % msg)
1142 686d7433 Iustin Pop
  elif isinstance(err, errors.JobQueueDrainError):
1143 686d7433 Iustin Pop
    obuf.write("Failure: the job queue is marked for drain and doesn't"
1144 686d7433 Iustin Pop
               " accept new requests\n")
1145 f87b405e Michael Hanselmann
  elif isinstance(err, errors.JobQueueFull):
1146 f87b405e Michael Hanselmann
    obuf.write("Failure: the job queue is full and doesn't accept new"
1147 f87b405e Michael Hanselmann
               " job submissions until old jobs are archived\n")
1148 a5728081 Guido Trotter
  elif isinstance(err, errors.TypeEnforcementError):
1149 a5728081 Guido Trotter
    obuf.write("Parameter Error: %s" % msg)
1150 c1ce76bb Iustin Pop
  elif isinstance(err, errors.ParameterError):
1151 c1ce76bb Iustin Pop
    obuf.write("Failure: unknown/wrong parameter name '%s'" % msg)
1152 73702ee7 Iustin Pop
  elif isinstance(err, errors.GenericError):
1153 e2e521d0 Iustin Pop
    obuf.write("Unhandled Ganeti error: %s" % msg)
1154 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.NoMasterError):
1155 03a8dbdc Iustin Pop
    obuf.write("Cannot communicate with the master daemon.\nIs it running"
1156 082c5adb Michael Hanselmann
               " and listening for connections?")
1157 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.TimeoutError):
1158 03a8dbdc Iustin Pop
    obuf.write("Timeout while talking to the master daemon. Error:\n"
1159 03a8dbdc Iustin Pop
               "%s" % msg)
1160 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.ProtocolError):
1161 03a8dbdc Iustin Pop
    obuf.write("Unhandled protocol error while talking to the master daemon:\n"
1162 03a8dbdc Iustin Pop
               "%s" % msg)
1163 e9d741b6 Iustin Pop
  elif isinstance(err, JobSubmittedException):
1164 e9d741b6 Iustin Pop
    obuf.write("JobID: %s\n" % err.args[0])
1165 e9d741b6 Iustin Pop
    retcode = 0
1166 73702ee7 Iustin Pop
  else:
1167 e2e521d0 Iustin Pop
    obuf.write("Unhandled exception: %s" % msg)
1168 73702ee7 Iustin Pop
  return retcode, obuf.getvalue().rstrip('\n')
1169 73702ee7 Iustin Pop
1170 73702ee7 Iustin Pop
1171 de47cf8f Guido Trotter
def GenericMain(commands, override=None, aliases=None):
1172 a8083063 Iustin Pop
  """Generic main function for all the gnt-* commands.
1173 a8083063 Iustin Pop

1174 334d1483 Iustin Pop
  Arguments:
1175 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
1176 334d1483 Iustin Pop
                for command line handling.
1177 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
1178 334d1483 Iustin Pop
                override command line options; this can be used to pass
1179 334d1483 Iustin Pop
                options from the scripts to generic functions
1180 de47cf8f Guido Trotter
    - aliases: dictionary with command aliases {'alias': 'target, ...}
1181 a8083063 Iustin Pop

1182 a8083063 Iustin Pop
  """
1183 a8083063 Iustin Pop
  # save the program name and the entire command line for later logging
1184 a8083063 Iustin Pop
  if sys.argv:
1185 a8083063 Iustin Pop
    binary = os.path.basename(sys.argv[0]) or sys.argv[0]
1186 a8083063 Iustin Pop
    if len(sys.argv) >= 2:
1187 a8083063 Iustin Pop
      binary += " " + sys.argv[1]
1188 a8083063 Iustin Pop
      old_cmdline = " ".join(sys.argv[2:])
1189 a8083063 Iustin Pop
    else:
1190 a8083063 Iustin Pop
      old_cmdline = ""
1191 a8083063 Iustin Pop
  else:
1192 a8083063 Iustin Pop
    binary = "<unknown program>"
1193 a8083063 Iustin Pop
    old_cmdline = ""
1194 a8083063 Iustin Pop
1195 de47cf8f Guido Trotter
  if aliases is None:
1196 de47cf8f Guido Trotter
    aliases = {}
1197 de47cf8f Guido Trotter
1198 3126878d Guido Trotter
  try:
1199 3126878d Guido Trotter
    func, options, args = _ParseArgs(sys.argv, commands, aliases)
1200 3126878d Guido Trotter
  except errors.ParameterError, err:
1201 3126878d Guido Trotter
    result, err_msg = FormatError(err)
1202 3126878d Guido Trotter
    ToStderr(err_msg)
1203 3126878d Guido Trotter
    return 1
1204 3126878d Guido Trotter
1205 a8083063 Iustin Pop
  if func is None: # parse error
1206 a8083063 Iustin Pop
    return 1
1207 a8083063 Iustin Pop
1208 334d1483 Iustin Pop
  if override is not None:
1209 334d1483 Iustin Pop
    for key, val in override.iteritems():
1210 334d1483 Iustin Pop
      setattr(options, key, val)
1211 334d1483 Iustin Pop
1212 82d9caef Iustin Pop
  utils.SetupLogging(constants.LOG_COMMANDS, debug=options.debug,
1213 82d9caef Iustin Pop
                     stderr_logging=True, program=binary)
1214 a8083063 Iustin Pop
1215 a8083063 Iustin Pop
  if old_cmdline:
1216 46fbdd04 Iustin Pop
    logging.info("run with arguments '%s'", old_cmdline)
1217 a8083063 Iustin Pop
  else:
1218 46fbdd04 Iustin Pop
    logging.info("run with no arguments")
1219 a8083063 Iustin Pop
1220 a8083063 Iustin Pop
  try:
1221 a4af651e Iustin Pop
    result = func(options, args)
1222 d8353c3a Iustin Pop
  except (errors.GenericError, luxi.ProtocolError,
1223 d8353c3a Iustin Pop
          JobSubmittedException), err:
1224 a4af651e Iustin Pop
    result, err_msg = FormatError(err)
1225 5bbd3f7f Michael Hanselmann
    logging.exception("Error during command processing")
1226 46fbdd04 Iustin Pop
    ToStderr(err_msg)
1227 a8083063 Iustin Pop
1228 a8083063 Iustin Pop
  return result
1229 137161c9 Michael Hanselmann
1230 137161c9 Michael Hanselmann
1231 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
1232 9fbfbb7b Iustin Pop
                  numfields=None, unitfields=None,
1233 9fbfbb7b Iustin Pop
                  units=None):
1234 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
1235 137161c9 Michael Hanselmann

1236 9fbfbb7b Iustin Pop
  @type headers: dict
1237 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
1238 9fbfbb7b Iustin Pop
      the table
1239 9fbfbb7b Iustin Pop
  @type fields: list
1240 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
1241 9fbfbb7b Iustin Pop
      the data field
1242 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
1243 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
1244 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
1245 9fbfbb7b Iustin Pop
      each field
1246 9fbfbb7b Iustin Pop
  @type data: list
1247 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
1248 9fbfbb7b Iustin Pop
  @type numfields: list
1249 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
1250 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
1251 9fbfbb7b Iustin Pop
  @type unitfields: list
1252 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
1253 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
1254 9fbfbb7b Iustin Pop
  @type units: string or None
1255 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
1256 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
1257 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
1258 137161c9 Michael Hanselmann

1259 137161c9 Michael Hanselmann
  """
1260 9fbfbb7b Iustin Pop
  if units is None:
1261 9fbfbb7b Iustin Pop
    if separator:
1262 9fbfbb7b Iustin Pop
      units = "m"
1263 9fbfbb7b Iustin Pop
    else:
1264 9fbfbb7b Iustin Pop
      units = "h"
1265 9fbfbb7b Iustin Pop
1266 137161c9 Michael Hanselmann
  if numfields is None:
1267 137161c9 Michael Hanselmann
    numfields = []
1268 137161c9 Michael Hanselmann
  if unitfields is None:
1269 137161c9 Michael Hanselmann
    unitfields = []
1270 137161c9 Michael Hanselmann
1271 00430f8e Iustin Pop
  numfields = utils.FieldSet(*numfields)
1272 00430f8e Iustin Pop
  unitfields = utils.FieldSet(*unitfields)
1273 00430f8e Iustin Pop
1274 137161c9 Michael Hanselmann
  format_fields = []
1275 137161c9 Michael Hanselmann
  for field in fields:
1276 01ca31ae Iustin Pop
    if headers and field not in headers:
1277 ea5a5b74 Guido Trotter
      # TODO: handle better unknown fields (either revert to old
1278 71c1af58 Iustin Pop
      # style of raising exception, or deal more intelligently with
1279 71c1af58 Iustin Pop
      # variable fields)
1280 71c1af58 Iustin Pop
      headers[field] = field
1281 137161c9 Michael Hanselmann
    if separator is not None:
1282 137161c9 Michael Hanselmann
      format_fields.append("%s")
1283 00430f8e Iustin Pop
    elif numfields.Matches(field):
1284 137161c9 Michael Hanselmann
      format_fields.append("%*s")
1285 137161c9 Michael Hanselmann
    else:
1286 137161c9 Michael Hanselmann
      format_fields.append("%-*s")
1287 137161c9 Michael Hanselmann
1288 137161c9 Michael Hanselmann
  if separator is None:
1289 137161c9 Michael Hanselmann
    mlens = [0 for name in fields]
1290 137161c9 Michael Hanselmann
    format = ' '.join(format_fields)
1291 137161c9 Michael Hanselmann
  else:
1292 137161c9 Michael Hanselmann
    format = separator.replace("%", "%%").join(format_fields)
1293 137161c9 Michael Hanselmann
1294 137161c9 Michael Hanselmann
  for row in data:
1295 dcbd6288 Guido Trotter
    if row is None:
1296 dcbd6288 Guido Trotter
      continue
1297 137161c9 Michael Hanselmann
    for idx, val in enumerate(row):
1298 00430f8e Iustin Pop
      if unitfields.Matches(fields[idx]):
1299 137161c9 Michael Hanselmann
        try:
1300 137161c9 Michael Hanselmann
          val = int(val)
1301 137161c9 Michael Hanselmann
        except ValueError:
1302 137161c9 Michael Hanselmann
          pass
1303 137161c9 Michael Hanselmann
        else:
1304 9fbfbb7b Iustin Pop
          val = row[idx] = utils.FormatUnit(val, units)
1305 01ca31ae Iustin Pop
      val = row[idx] = str(val)
1306 137161c9 Michael Hanselmann
      if separator is None:
1307 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(val))
1308 137161c9 Michael Hanselmann
1309 16be8703 Iustin Pop
  result = []
1310 137161c9 Michael Hanselmann
  if headers:
1311 137161c9 Michael Hanselmann
    args = []
1312 137161c9 Michael Hanselmann
    for idx, name in enumerate(fields):
1313 137161c9 Michael Hanselmann
      hdr = headers[name]
1314 137161c9 Michael Hanselmann
      if separator is None:
1315 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(hdr))
1316 137161c9 Michael Hanselmann
        args.append(mlens[idx])
1317 137161c9 Michael Hanselmann
      args.append(hdr)
1318 16be8703 Iustin Pop
    result.append(format % tuple(args))
1319 137161c9 Michael Hanselmann
1320 137161c9 Michael Hanselmann
  for line in data:
1321 137161c9 Michael Hanselmann
    args = []
1322 dcbd6288 Guido Trotter
    if line is None:
1323 dcbd6288 Guido Trotter
      line = ['-' for _ in fields]
1324 137161c9 Michael Hanselmann
    for idx in xrange(len(fields)):
1325 137161c9 Michael Hanselmann
      if separator is None:
1326 137161c9 Michael Hanselmann
        args.append(mlens[idx])
1327 137161c9 Michael Hanselmann
      args.append(line[idx])
1328 16be8703 Iustin Pop
    result.append(format % tuple(args))
1329 16be8703 Iustin Pop
1330 16be8703 Iustin Pop
  return result
1331 3386e7a9 Iustin Pop
1332 3386e7a9 Iustin Pop
1333 3386e7a9 Iustin Pop
def FormatTimestamp(ts):
1334 3386e7a9 Iustin Pop
  """Formats a given timestamp.
1335 3386e7a9 Iustin Pop

1336 3386e7a9 Iustin Pop
  @type ts: timestamp
1337 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
1338 3386e7a9 Iustin Pop

1339 3386e7a9 Iustin Pop
  @rtype: string
1340 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
1341 3386e7a9 Iustin Pop

1342 3386e7a9 Iustin Pop
  """
1343 e0ec0ff6 Iustin Pop
  if not isinstance (ts, (tuple, list)) or len(ts) != 2:
1344 e0ec0ff6 Iustin Pop
    return '?'
1345 3386e7a9 Iustin Pop
  sec, usec = ts
1346 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
1347 2241e2b9 Iustin Pop
1348 2241e2b9 Iustin Pop
1349 2241e2b9 Iustin Pop
def ParseTimespec(value):
1350 2241e2b9 Iustin Pop
  """Parse a time specification.
1351 2241e2b9 Iustin Pop

1352 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
1353 2241e2b9 Iustin Pop

1354 2241e2b9 Iustin Pop
    - s: seconds
1355 2241e2b9 Iustin Pop
    - m: minutes
1356 2241e2b9 Iustin Pop
    - h: hours
1357 2241e2b9 Iustin Pop
    - d: day
1358 2241e2b9 Iustin Pop
    - w: weeks
1359 2241e2b9 Iustin Pop

1360 2241e2b9 Iustin Pop
  Without any suffix, the value will be taken to be in seconds.
1361 2241e2b9 Iustin Pop

1362 2241e2b9 Iustin Pop
  """
1363 2241e2b9 Iustin Pop
  value = str(value)
1364 2241e2b9 Iustin Pop
  if not value:
1365 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
1366 2241e2b9 Iustin Pop
  suffix_map = {
1367 2241e2b9 Iustin Pop
    's': 1,
1368 2241e2b9 Iustin Pop
    'm': 60,
1369 2241e2b9 Iustin Pop
    'h': 3600,
1370 2241e2b9 Iustin Pop
    'd': 86400,
1371 2241e2b9 Iustin Pop
    'w': 604800,
1372 2241e2b9 Iustin Pop
    }
1373 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
1374 2241e2b9 Iustin Pop
    try:
1375 2241e2b9 Iustin Pop
      value = int(value)
1376 2241e2b9 Iustin Pop
    except ValueError:
1377 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
1378 2241e2b9 Iustin Pop
  else:
1379 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
1380 2241e2b9 Iustin Pop
    value = value[:-1]
1381 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
1382 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
1383 2241e2b9 Iustin Pop
                                 " suffix passed)")
1384 2241e2b9 Iustin Pop
    try:
1385 2241e2b9 Iustin Pop
      value = int(value) * multiplier
1386 2241e2b9 Iustin Pop
    except ValueError:
1387 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
1388 2241e2b9 Iustin Pop
  return value
1389 46fbdd04 Iustin Pop
1390 46fbdd04 Iustin Pop
1391 4040a784 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False):
1392 4040a784 Iustin Pop
  """Returns the names of online nodes.
1393 4040a784 Iustin Pop

1394 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
1395 4040a784 Iustin Pop
  the online nodes.
1396 4040a784 Iustin Pop

1397 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
1398 4040a784 Iustin Pop
      offline ones)
1399 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
1400 4040a784 Iustin Pop
  @type nowarn: boolean
1401 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
1402 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
1403 4040a784 Iustin Pop
      note is not displayed
1404 4040a784 Iustin Pop

1405 4040a784 Iustin Pop
  """
1406 4040a784 Iustin Pop
  if cl is None:
1407 4040a784 Iustin Pop
    cl = GetClient()
1408 4040a784 Iustin Pop
1409 2e7b8369 Iustin Pop
  result = cl.QueryNodes(names=nodes, fields=["name", "offline"],
1410 2e7b8369 Iustin Pop
                         use_locking=False)
1411 4040a784 Iustin Pop
  offline = [row[0] for row in result if row[1]]
1412 4040a784 Iustin Pop
  if offline and not nowarn:
1413 4040a784 Iustin Pop
    ToStderr("Note: skipping offline node(s): %s" % ", ".join(offline))
1414 4040a784 Iustin Pop
  return [row[0] for row in result if not row[1]]
1415 4040a784 Iustin Pop
1416 4040a784 Iustin Pop
1417 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
1418 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
1419 46fbdd04 Iustin Pop

1420 46fbdd04 Iustin Pop
  @type stream: file object
1421 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
1422 46fbdd04 Iustin Pop
  @type txt: str
1423 46fbdd04 Iustin Pop
  @param txt: the message
1424 46fbdd04 Iustin Pop

1425 46fbdd04 Iustin Pop
  """
1426 46fbdd04 Iustin Pop
  if args:
1427 46fbdd04 Iustin Pop
    args = tuple(args)
1428 46fbdd04 Iustin Pop
    stream.write(txt % args)
1429 46fbdd04 Iustin Pop
  else:
1430 46fbdd04 Iustin Pop
    stream.write(txt)
1431 46fbdd04 Iustin Pop
  stream.write('\n')
1432 46fbdd04 Iustin Pop
  stream.flush()
1433 46fbdd04 Iustin Pop
1434 46fbdd04 Iustin Pop
1435 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
1436 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
1437 46fbdd04 Iustin Pop

1438 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
1439 46fbdd04 Iustin Pop

1440 46fbdd04 Iustin Pop
  @type txt: str
1441 46fbdd04 Iustin Pop
  @param txt: the message
1442 46fbdd04 Iustin Pop

1443 46fbdd04 Iustin Pop
  """
1444 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
1445 46fbdd04 Iustin Pop
1446 46fbdd04 Iustin Pop
1447 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
1448 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
1449 46fbdd04 Iustin Pop

1450 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
1451 46fbdd04 Iustin Pop

1452 46fbdd04 Iustin Pop
  @type txt: str
1453 46fbdd04 Iustin Pop
  @param txt: the message
1454 46fbdd04 Iustin Pop

1455 46fbdd04 Iustin Pop
  """
1456 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
1457 479636a3 Iustin Pop
1458 479636a3 Iustin Pop
1459 479636a3 Iustin Pop
class JobExecutor(object):
1460 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
1461 479636a3 Iustin Pop

1462 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
1463 479636a3 Iustin Pop
  GetResults() calls.
1464 479636a3 Iustin Pop

1465 479636a3 Iustin Pop
  """
1466 479636a3 Iustin Pop
  def __init__(self, cl=None, verbose=True):
1467 479636a3 Iustin Pop
    self.queue = []
1468 479636a3 Iustin Pop
    if cl is None:
1469 479636a3 Iustin Pop
      cl = GetClient()
1470 479636a3 Iustin Pop
    self.cl = cl
1471 479636a3 Iustin Pop
    self.verbose = verbose
1472 23b4b983 Iustin Pop
    self.jobs = []
1473 479636a3 Iustin Pop
1474 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
1475 23b4b983 Iustin Pop
    """Record a job for later submit.
1476 479636a3 Iustin Pop

1477 479636a3 Iustin Pop
    @type name: string
1478 479636a3 Iustin Pop
    @param name: a description of the job, will be used in WaitJobSet
1479 479636a3 Iustin Pop
    """
1480 23b4b983 Iustin Pop
    self.queue.append((name, ops))
1481 23b4b983 Iustin Pop
1482 23b4b983 Iustin Pop
  def SubmitPending(self):
1483 23b4b983 Iustin Pop
    """Submit all pending jobs.
1484 23b4b983 Iustin Pop

1485 23b4b983 Iustin Pop
    """
1486 23b4b983 Iustin Pop
    results = self.cl.SubmitManyJobs([row[1] for row in self.queue])
1487 23b4b983 Iustin Pop
    for ((status, data), (name, _)) in zip(results, self.queue):
1488 23b4b983 Iustin Pop
      self.jobs.append((status, data, name))
1489 479636a3 Iustin Pop
1490 479636a3 Iustin Pop
  def GetResults(self):
1491 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
1492 479636a3 Iustin Pop

1493 479636a3 Iustin Pop
    @rtype: list
1494 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
1495 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
1496 479636a3 Iustin Pop
        there will be the error message
1497 479636a3 Iustin Pop

1498 479636a3 Iustin Pop
    """
1499 23b4b983 Iustin Pop
    if not self.jobs:
1500 23b4b983 Iustin Pop
      self.SubmitPending()
1501 479636a3 Iustin Pop
    results = []
1502 479636a3 Iustin Pop
    if self.verbose:
1503 23b4b983 Iustin Pop
      ok_jobs = [row[1] for row in self.jobs if row[0]]
1504 23b4b983 Iustin Pop
      if ok_jobs:
1505 23b4b983 Iustin Pop
        ToStdout("Submitted jobs %s", ", ".join(ok_jobs))
1506 23b4b983 Iustin Pop
    for submit_status, jid, name in self.jobs:
1507 23b4b983 Iustin Pop
      if not submit_status:
1508 23b4b983 Iustin Pop
        ToStderr("Failed to submit job for %s: %s", name, jid)
1509 23b4b983 Iustin Pop
        results.append((False, jid))
1510 23b4b983 Iustin Pop
        continue
1511 479636a3 Iustin Pop
      if self.verbose:
1512 479636a3 Iustin Pop
        ToStdout("Waiting for job %s for %s...", jid, name)
1513 479636a3 Iustin Pop
      try:
1514 479636a3 Iustin Pop
        job_result = PollJob(jid, cl=self.cl)
1515 479636a3 Iustin Pop
        success = True
1516 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
1517 479636a3 Iustin Pop
        _, job_result = FormatError(err)
1518 479636a3 Iustin Pop
        success = False
1519 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
1520 479636a3 Iustin Pop
        ToStderr("Job %s for %s has failed: %s", jid, name, job_result)
1521 479636a3 Iustin Pop
1522 479636a3 Iustin Pop
      results.append((success, job_result))
1523 479636a3 Iustin Pop
    return results
1524 479636a3 Iustin Pop
1525 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
1526 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
1527 479636a3 Iustin Pop

1528 479636a3 Iustin Pop
    @type wait: boolean
1529 479636a3 Iustin Pop
    @param wait: whether to wait or not
1530 479636a3 Iustin Pop

1531 479636a3 Iustin Pop
    """
1532 479636a3 Iustin Pop
    if wait:
1533 479636a3 Iustin Pop
      return self.GetResults()
1534 479636a3 Iustin Pop
    else:
1535 23b4b983 Iustin Pop
      if not self.jobs:
1536 23b4b983 Iustin Pop
        self.SubmitPending()
1537 23b4b983 Iustin Pop
      for status, result, name in self.jobs:
1538 23b4b983 Iustin Pop
        if status:
1539 23b4b983 Iustin Pop
          ToStdout("%s: %s", result, name)
1540 23b4b983 Iustin Pop
        else:
1541 23b4b983 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)