Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ 07150497

History | View | Annotate | Download (56 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 e32df528 Iustin Pop
  "CP_SIZE_OPT",
54 4abc4f1e Iustin Pop
  "DEBUG_OPT",
55 a0c9776a Iustin Pop
  "DEBUG_SIMERR_OPT",
56 4b038a1e Iustin Pop
  "DISKIDX_OPT",
57 e3876ccb Iustin Pop
  "DISK_OPT",
58 4b038a1e Iustin Pop
  "DISK_TEMPLATE_OPT",
59 771734c9 Iustin Pop
  "DRAINED_OPT",
60 383a3591 Iustin Pop
  "ENABLED_HV_OPT",
61 14e9e7f3 Iustin Pop
  "ERROR_CODES_OPT",
62 4abc4f1e Iustin Pop
  "FIELDS_OPT",
63 4a25828c Iustin Pop
  "FILESTORE_DIR_OPT",
64 0f87c43e Iustin Pop
  "FILESTORE_DRIVER_OPT",
65 29392516 Iustin Pop
  "GLOBAL_FILEDIR_OPT",
66 073271f6 Iustin Pop
  "HVLIST_OPT",
67 48f212d7 Iustin Pop
  "HVOPTS_OPT",
68 236fd9c4 Iustin Pop
  "HYPERVISOR_OPT",
69 4eb62659 Iustin Pop
  "IALLOCATOR_OPT",
70 82a786d5 Iustin Pop
  "IGNORE_CONSIST_OPT",
71 b6e841a8 Iustin Pop
  "IGNORE_FAILURES_OPT",
72 ee3f9578 Iustin Pop
  "IGNORE_SECONDARIES_OPT",
73 05586c90 Iustin Pop
  "IGNORE_SIZE_OPT",
74 4abc4f1e Iustin Pop
  "FORCE_OPT",
75 e3646f22 Iustin Pop
  "MAC_PREFIX_OPT",
76 29392516 Iustin Pop
  "MASTER_NETDEV_OPT",
77 771734c9 Iustin Pop
  "MC_OPT",
78 7d3a9fab Iustin Pop
  "NET_OPT",
79 a14db5ff Iustin Pop
  "NEW_SECONDARY_OPT",
80 4fbc93dd Iustin Pop
  "NIC_PARAMS_OPT",
81 7edc4637 Iustin Pop
  "NODE_LIST_OPT",
82 990b7886 Iustin Pop
  "NODE_PLACEMENT_OPT",
83 4abc4f1e Iustin Pop
  "NOHDR_OPT",
84 91e0748c Iustin Pop
  "NOIPCHECK_OPT",
85 831040bf Iustin Pop
  "NOLVM_STORAGE_OPT",
86 29392516 Iustin Pop
  "NOMODIFY_ETCHOSTS_OPT",
87 26023ecd Iustin Pop
  "NONICS_OPT",
88 f2a0828c Iustin Pop
  "NONLIVE_OPT",
89 14e9e7f3 Iustin Pop
  "NONPLUS1_OPT",
90 44c44832 Iustin Pop
  "NOSHUTDOWN_OPT",
91 edeb878a Iustin Pop
  "NOSTART_OPT",
92 fcdde7f2 Iustin Pop
  "NOSSH_KEYCHECK_OPT",
93 58371861 Iustin Pop
  "NOVOTING_OPT",
94 3f75b4f3 Iustin Pop
  "NWSYNC_OPT",
95 a72d0a79 Iustin Pop
  "ON_PRIMARY_OPT",
96 feb09e6a Iustin Pop
  "ON_SECONDARY_OPT",
97 771734c9 Iustin Pop
  "OFFLINE_OPT",
98 d3ed23ff Iustin Pop
  "OS_OPT",
99 ff00c1a7 Iustin Pop
  "OS_SIZE_OPT",
100 b8d0f938 Iustin Pop
  "READD_OPT",
101 12054861 Iustin Pop
  "REBOOT_TYPE_OPT",
102 8d823629 Iustin Pop
  "SECONDARY_IP_OPT",
103 67840b40 Iustin Pop
  "SELECT_OS_OPT",
104 4abc4f1e Iustin Pop
  "SEP_OPT",
105 fdcf4d84 Iustin Pop
  "SHOWCMD_OPT",
106 f36d7d81 Iustin Pop
  "SINGLE_NODE_OPT",
107 df62e5db Iustin Pop
  "SRC_DIR_OPT",
108 df62e5db Iustin Pop
  "SRC_NODE_OPT",
109 4abc4f1e Iustin Pop
  "SUBMIT_OPT",
110 99a8c799 Iustin Pop
  "STATIC_OPT",
111 4abc4f1e Iustin Pop
  "SYNC_OPT",
112 4abc4f1e Iustin Pop
  "TAG_SRC_OPT",
113 4abc4f1e Iustin Pop
  "USEUNITS_OPT",
114 9cdb9578 Iustin Pop
  "VERBOSE_OPT",
115 b58726e8 Iustin Pop
  "VG_NAME_OPT",
116 1f587d3d Iustin Pop
  "YES_DOIT_OPT",
117 4abc4f1e Iustin Pop
  # Generic functions for CLI programs
118 4abc4f1e Iustin Pop
  "GenericMain",
119 d77490c5 Iustin Pop
  "GenericInstanceCreate",
120 4abc4f1e Iustin Pop
  "GetClient",
121 4abc4f1e Iustin Pop
  "GetOnlineNodes",
122 4abc4f1e Iustin Pop
  "JobExecutor",
123 4abc4f1e Iustin Pop
  "JobSubmittedException",
124 4abc4f1e Iustin Pop
  "ParseTimespec",
125 4abc4f1e Iustin Pop
  "SubmitOpCode",
126 4abc4f1e Iustin Pop
  "SubmitOrSend",
127 4abc4f1e Iustin Pop
  "UsesRPC",
128 4abc4f1e Iustin Pop
  # Formatting functions
129 4abc4f1e Iustin Pop
  "ToStderr", "ToStdout",
130 4abc4f1e Iustin Pop
  "FormatError",
131 4abc4f1e Iustin Pop
  "GenerateTable",
132 4abc4f1e Iustin Pop
  "AskUser",
133 4abc4f1e Iustin Pop
  "FormatTimestamp",
134 4abc4f1e Iustin Pop
  # Tags functions
135 4abc4f1e Iustin Pop
  "ListTags",
136 4abc4f1e Iustin Pop
  "AddTags",
137 4abc4f1e Iustin Pop
  "RemoveTags",
138 4abc4f1e Iustin Pop
  # command line options support infrastructure
139 4abc4f1e Iustin Pop
  "ARGS_MANY_INSTANCES",
140 4abc4f1e Iustin Pop
  "ARGS_MANY_NODES",
141 4abc4f1e Iustin Pop
  "ARGS_NONE",
142 4abc4f1e Iustin Pop
  "ARGS_ONE_INSTANCE",
143 4abc4f1e Iustin Pop
  "ARGS_ONE_NODE",
144 4abc4f1e Iustin Pop
  "ArgChoice",
145 4abc4f1e Iustin Pop
  "ArgCommand",
146 4abc4f1e Iustin Pop
  "ArgFile",
147 4abc4f1e Iustin Pop
  "ArgHost",
148 4abc4f1e Iustin Pop
  "ArgInstance",
149 4abc4f1e Iustin Pop
  "ArgJobId",
150 4abc4f1e Iustin Pop
  "ArgNode",
151 4abc4f1e Iustin Pop
  "ArgSuggest",
152 4abc4f1e Iustin Pop
  "ArgUnknown",
153 4abc4f1e Iustin Pop
  "OPT_COMPL_INST_ADD_NODES",
154 4abc4f1e Iustin Pop
  "OPT_COMPL_MANY_NODES",
155 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_IALLOCATOR",
156 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_INSTANCE",
157 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_NODE",
158 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_OS",
159 4abc4f1e Iustin Pop
  "cli_option",
160 4abc4f1e Iustin Pop
  "SplitNodeOption",
161 07150497 Guido Trotter
  "CalculateOSNames",
162 4abc4f1e Iustin Pop
  ]
163 846baef9 Iustin Pop
164 8b46606c Guido Trotter
NO_PREFIX = "no_"
165 8b46606c Guido Trotter
UN_PREFIX = "-"
166 846baef9 Iustin Pop
167 03298ebe Michael Hanselmann
168 863d7f46 Michael Hanselmann
class _Argument:
169 dff85078 Michael Hanselmann
  def __init__(self, min=0, max=None):
170 863d7f46 Michael Hanselmann
    self.min = min
171 863d7f46 Michael Hanselmann
    self.max = max
172 863d7f46 Michael Hanselmann
173 863d7f46 Michael Hanselmann
  def __repr__(self):
174 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s>" %
175 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max))
176 863d7f46 Michael Hanselmann
177 863d7f46 Michael Hanselmann
178 863d7f46 Michael Hanselmann
class ArgSuggest(_Argument):
179 863d7f46 Michael Hanselmann
  """Suggesting argument.
180 863d7f46 Michael Hanselmann

181 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor.
182 863d7f46 Michael Hanselmann

183 863d7f46 Michael Hanselmann
  """
184 863d7f46 Michael Hanselmann
  def __init__(self, min=0, max=None, choices=None):
185 863d7f46 Michael Hanselmann
    _Argument.__init__(self, min=min, max=max)
186 863d7f46 Michael Hanselmann
    self.choices = choices
187 863d7f46 Michael Hanselmann
188 863d7f46 Michael Hanselmann
  def __repr__(self):
189 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s choices=%r>" %
190 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max, self.choices))
191 863d7f46 Michael Hanselmann
192 863d7f46 Michael Hanselmann
193 863d7f46 Michael Hanselmann
class ArgChoice(ArgSuggest):
194 863d7f46 Michael Hanselmann
  """Choice argument.
195 863d7f46 Michael Hanselmann

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

199 863d7f46 Michael Hanselmann
  """
200 863d7f46 Michael Hanselmann
201 863d7f46 Michael Hanselmann
202 863d7f46 Michael Hanselmann
class ArgUnknown(_Argument):
203 863d7f46 Michael Hanselmann
  """Unknown argument to program (e.g. determined at runtime).
204 863d7f46 Michael Hanselmann

205 863d7f46 Michael Hanselmann
  """
206 863d7f46 Michael Hanselmann
207 863d7f46 Michael Hanselmann
208 863d7f46 Michael Hanselmann
class ArgInstance(_Argument):
209 863d7f46 Michael Hanselmann
  """Instances argument.
210 863d7f46 Michael Hanselmann

211 863d7f46 Michael Hanselmann
  """
212 863d7f46 Michael Hanselmann
213 863d7f46 Michael Hanselmann
214 863d7f46 Michael Hanselmann
class ArgNode(_Argument):
215 863d7f46 Michael Hanselmann
  """Node argument.
216 863d7f46 Michael Hanselmann

217 863d7f46 Michael Hanselmann
  """
218 863d7f46 Michael Hanselmann
219 863d7f46 Michael Hanselmann
class ArgJobId(_Argument):
220 863d7f46 Michael Hanselmann
  """Job ID argument.
221 863d7f46 Michael Hanselmann

222 863d7f46 Michael Hanselmann
  """
223 863d7f46 Michael Hanselmann
224 863d7f46 Michael Hanselmann
225 863d7f46 Michael Hanselmann
class ArgFile(_Argument):
226 863d7f46 Michael Hanselmann
  """File path argument.
227 863d7f46 Michael Hanselmann

228 863d7f46 Michael Hanselmann
  """
229 863d7f46 Michael Hanselmann
230 863d7f46 Michael Hanselmann
231 863d7f46 Michael Hanselmann
class ArgCommand(_Argument):
232 863d7f46 Michael Hanselmann
  """Command argument.
233 863d7f46 Michael Hanselmann

234 863d7f46 Michael Hanselmann
  """
235 863d7f46 Michael Hanselmann
236 863d7f46 Michael Hanselmann
237 83ec7961 Michael Hanselmann
class ArgHost(_Argument):
238 83ec7961 Michael Hanselmann
  """Host argument.
239 83ec7961 Michael Hanselmann

240 83ec7961 Michael Hanselmann
  """
241 83ec7961 Michael Hanselmann
242 83ec7961 Michael Hanselmann
243 4a265c08 Michael Hanselmann
ARGS_NONE = []
244 4a265c08 Michael Hanselmann
ARGS_MANY_INSTANCES = [ArgInstance()]
245 4a265c08 Michael Hanselmann
ARGS_MANY_NODES = [ArgNode()]
246 4a265c08 Michael Hanselmann
ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
247 4a265c08 Michael Hanselmann
ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
248 4a265c08 Michael Hanselmann
249 4a265c08 Michael Hanselmann
250 73b90123 Michael Hanselmann
251 846baef9 Iustin Pop
def _ExtractTagsObject(opts, args):
252 846baef9 Iustin Pop
  """Extract the tag type object.
253 846baef9 Iustin Pop

254 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
255 846baef9 Iustin Pop

256 846baef9 Iustin Pop
  """
257 846baef9 Iustin Pop
  if not hasattr(opts, "tag_type"):
258 846baef9 Iustin Pop
    raise errors.ProgrammerError("tag_type not passed to _ExtractTagsObject")
259 846baef9 Iustin Pop
  kind = opts.tag_type
260 846baef9 Iustin Pop
  if kind == constants.TAG_CLUSTER:
261 846baef9 Iustin Pop
    retval = kind, kind
262 846baef9 Iustin Pop
  elif kind == constants.TAG_NODE or kind == constants.TAG_INSTANCE:
263 846baef9 Iustin Pop
    if not args:
264 0c434948 Iustin Pop
      raise errors.OpPrereqError("no arguments passed to the command")
265 846baef9 Iustin Pop
    name = args.pop(0)
266 846baef9 Iustin Pop
    retval = kind, name
267 846baef9 Iustin Pop
  else:
268 846baef9 Iustin Pop
    raise errors.ProgrammerError("Unhandled tag type '%s'" % kind)
269 846baef9 Iustin Pop
  return retval
270 846baef9 Iustin Pop
271 846baef9 Iustin Pop
272 810c50b7 Iustin Pop
def _ExtendTags(opts, args):
273 810c50b7 Iustin Pop
  """Extend the args if a source file has been given.
274 810c50b7 Iustin Pop

275 810c50b7 Iustin Pop
  This function will extend the tags with the contents of the file
276 810c50b7 Iustin Pop
  passed in the 'tags_source' attribute of the opts parameter. A file
277 810c50b7 Iustin Pop
  named '-' will be replaced by stdin.
278 810c50b7 Iustin Pop

279 810c50b7 Iustin Pop
  """
280 810c50b7 Iustin Pop
  fname = opts.tags_source
281 810c50b7 Iustin Pop
  if fname is None:
282 810c50b7 Iustin Pop
    return
283 810c50b7 Iustin Pop
  if fname == "-":
284 810c50b7 Iustin Pop
    new_fh = sys.stdin
285 810c50b7 Iustin Pop
  else:
286 810c50b7 Iustin Pop
    new_fh = open(fname, "r")
287 810c50b7 Iustin Pop
  new_data = []
288 810c50b7 Iustin Pop
  try:
289 810c50b7 Iustin Pop
    # we don't use the nice 'new_data = [line.strip() for line in fh]'
290 810c50b7 Iustin Pop
    # because of python bug 1633941
291 810c50b7 Iustin Pop
    while True:
292 810c50b7 Iustin Pop
      line = new_fh.readline()
293 810c50b7 Iustin Pop
      if not line:
294 810c50b7 Iustin Pop
        break
295 810c50b7 Iustin Pop
      new_data.append(line.strip())
296 810c50b7 Iustin Pop
  finally:
297 810c50b7 Iustin Pop
    new_fh.close()
298 810c50b7 Iustin Pop
  args.extend(new_data)
299 810c50b7 Iustin Pop
300 810c50b7 Iustin Pop
301 846baef9 Iustin Pop
def ListTags(opts, args):
302 846baef9 Iustin Pop
  """List the 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 846baef9 Iustin Pop
  op = opcodes.OpGetTags(kind=kind, name=name)
312 846baef9 Iustin Pop
  result = SubmitOpCode(op)
313 846baef9 Iustin Pop
  result = list(result)
314 846baef9 Iustin Pop
  result.sort()
315 846baef9 Iustin Pop
  for tag in result:
316 03298ebe Michael Hanselmann
    ToStdout(tag)
317 846baef9 Iustin Pop
318 846baef9 Iustin Pop
319 846baef9 Iustin Pop
def AddTags(opts, args):
320 846baef9 Iustin Pop
  """Add tags on a given object.
321 846baef9 Iustin Pop

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

327 846baef9 Iustin Pop
  """
328 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
329 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
330 846baef9 Iustin Pop
  if not args:
331 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be added")
332 846baef9 Iustin Pop
  op = opcodes.OpAddTags(kind=kind, name=name, tags=args)
333 846baef9 Iustin Pop
  SubmitOpCode(op)
334 846baef9 Iustin Pop
335 846baef9 Iustin Pop
336 846baef9 Iustin Pop
def RemoveTags(opts, args):
337 846baef9 Iustin Pop
  """Remove tags from a given object.
338 846baef9 Iustin Pop

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

344 846baef9 Iustin Pop
  """
345 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
346 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
347 846baef9 Iustin Pop
  if not args:
348 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be removed")
349 846baef9 Iustin Pop
  op = opcodes.OpDelTags(kind=kind, name=name, tags=args)
350 846baef9 Iustin Pop
  SubmitOpCode(op)
351 846baef9 Iustin Pop
352 a8083063 Iustin Pop
353 a8083063 Iustin Pop
def check_unit(option, opt, value):
354 65fe4693 Iustin Pop
  """OptParsers custom converter for units.
355 65fe4693 Iustin Pop

356 65fe4693 Iustin Pop
  """
357 a8083063 Iustin Pop
  try:
358 a8083063 Iustin Pop
    return utils.ParseUnit(value)
359 a8083063 Iustin Pop
  except errors.UnitParseError, err:
360 3ecf6786 Iustin Pop
    raise OptionValueError("option %s: %s" % (opt, err))
361 a8083063 Iustin Pop
362 a8083063 Iustin Pop
363 a8469393 Iustin Pop
def _SplitKeyVal(opt, data):
364 a8469393 Iustin Pop
  """Convert a KeyVal string into a dict.
365 a8469393 Iustin Pop

366 a8469393 Iustin Pop
  This function will convert a key=val[,...] string into a dict. Empty
367 a8469393 Iustin Pop
  values will be converted specially: keys which have the prefix 'no_'
368 a8469393 Iustin Pop
  will have the value=False and the prefix stripped, the others will
369 a8469393 Iustin Pop
  have value=True.
370 a8469393 Iustin Pop

371 a8469393 Iustin Pop
  @type opt: string
372 a8469393 Iustin Pop
  @param opt: a string holding the option name for which we process the
373 a8469393 Iustin Pop
      data, used in building error messages
374 a8469393 Iustin Pop
  @type data: string
375 a8469393 Iustin Pop
  @param data: a string of the format key=val,key=val,...
376 a8469393 Iustin Pop
  @rtype: dict
377 a8469393 Iustin Pop
  @return: {key=val, key=val}
378 a8469393 Iustin Pop
  @raises errors.ParameterError: if there are duplicate keys
379 a8469393 Iustin Pop

380 a8469393 Iustin Pop
  """
381 a8469393 Iustin Pop
  kv_dict = {}
382 4f31882e Guido Trotter
  if data:
383 4f31882e Guido Trotter
    for elem in data.split(","):
384 4f31882e Guido Trotter
      if "=" in elem:
385 4f31882e Guido Trotter
        key, val = elem.split("=", 1)
386 a8469393 Iustin Pop
      else:
387 4f31882e Guido Trotter
        if elem.startswith(NO_PREFIX):
388 4f31882e Guido Trotter
          key, val = elem[len(NO_PREFIX):], False
389 4f31882e Guido Trotter
        elif elem.startswith(UN_PREFIX):
390 4f31882e Guido Trotter
          key, val = elem[len(UN_PREFIX):], None
391 4f31882e Guido Trotter
        else:
392 4f31882e Guido Trotter
          key, val = elem, True
393 4f31882e Guido Trotter
      if key in kv_dict:
394 4f31882e Guido Trotter
        raise errors.ParameterError("Duplicate key '%s' in option %s" %
395 4f31882e Guido Trotter
                                    (key, opt))
396 4f31882e Guido Trotter
      kv_dict[key] = val
397 a8469393 Iustin Pop
  return kv_dict
398 a8469393 Iustin Pop
399 a8469393 Iustin Pop
400 a8469393 Iustin Pop
def check_ident_key_val(option, opt, value):
401 552c8dff Michael Hanselmann
  """Custom parser for ident:key=val,key=val options.
402 552c8dff Michael Hanselmann

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

406 a8469393 Iustin Pop
  """
407 a8469393 Iustin Pop
  if ":" not in value:
408 8b46606c Guido Trotter
    ident, rest = value, ''
409 a8469393 Iustin Pop
  else:
410 a8469393 Iustin Pop
    ident, rest = value.split(":", 1)
411 8b46606c Guido Trotter
412 8b46606c Guido Trotter
  if ident.startswith(NO_PREFIX):
413 8b46606c Guido Trotter
    if rest:
414 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
415 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
416 8b46606c Guido Trotter
    retval = (ident[len(NO_PREFIX):], False)
417 8b46606c Guido Trotter
  elif ident.startswith(UN_PREFIX):
418 8b46606c Guido Trotter
    if rest:
419 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
420 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
421 8b46606c Guido Trotter
    retval = (ident[len(UN_PREFIX):], None)
422 8b46606c Guido Trotter
  else:
423 a8469393 Iustin Pop
    kv_dict = _SplitKeyVal(opt, rest)
424 a8469393 Iustin Pop
    retval = (ident, kv_dict)
425 a8469393 Iustin Pop
  return retval
426 a8469393 Iustin Pop
427 a8469393 Iustin Pop
428 a8469393 Iustin Pop
def check_key_val(option, opt, value):
429 552c8dff Michael Hanselmann
  """Custom parser class for key=val,key=val options.
430 552c8dff Michael Hanselmann

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

433 a8469393 Iustin Pop
  """
434 a8469393 Iustin Pop
  return _SplitKeyVal(opt, value)
435 a8469393 Iustin Pop
436 a8469393 Iustin Pop
437 63d44c55 Michael Hanselmann
# completion_suggestion is normally a list. Using numeric values not evaluating
438 63d44c55 Michael Hanselmann
# to False for dynamic completion.
439 63d44c55 Michael Hanselmann
(OPT_COMPL_MANY_NODES,
440 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_NODE,
441 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_INSTANCE,
442 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_OS,
443 2d3ed64b Michael Hanselmann
 OPT_COMPL_ONE_IALLOCATOR,
444 2d3ed64b Michael Hanselmann
 OPT_COMPL_INST_ADD_NODES) = range(100, 106)
445 63d44c55 Michael Hanselmann
446 63d44c55 Michael Hanselmann
OPT_COMPL_ALL = frozenset([
447 63d44c55 Michael Hanselmann
  OPT_COMPL_MANY_NODES,
448 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_NODE,
449 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_INSTANCE,
450 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_OS,
451 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_IALLOCATOR,
452 2d3ed64b Michael Hanselmann
  OPT_COMPL_INST_ADD_NODES,
453 63d44c55 Michael Hanselmann
  ])
454 63d44c55 Michael Hanselmann
455 63d44c55 Michael Hanselmann
456 552c8dff Michael Hanselmann
class CliOption(Option):
457 552c8dff Michael Hanselmann
  """Custom option class for optparse.
458 a8469393 Iustin Pop

459 a8469393 Iustin Pop
  """
460 863d7f46 Michael Hanselmann
  ATTRS = Option.ATTRS + [
461 863d7f46 Michael Hanselmann
    "completion_suggest",
462 863d7f46 Michael Hanselmann
    ]
463 552c8dff Michael Hanselmann
  TYPES = Option.TYPES + (
464 552c8dff Michael Hanselmann
    "identkeyval",
465 552c8dff Michael Hanselmann
    "keyval",
466 552c8dff Michael Hanselmann
    "unit",
467 552c8dff Michael Hanselmann
    )
468 552c8dff Michael Hanselmann
  TYPE_CHECKER = Option.TYPE_CHECKER.copy()
469 552c8dff Michael Hanselmann
  TYPE_CHECKER["identkeyval"] = check_ident_key_val
470 a8469393 Iustin Pop
  TYPE_CHECKER["keyval"] = check_key_val
471 552c8dff Michael Hanselmann
  TYPE_CHECKER["unit"] = check_unit
472 a8469393 Iustin Pop
473 a8469393 Iustin Pop
474 a8083063 Iustin Pop
# optparse.py sets make_option, so we do it for our own option class, too
475 a8083063 Iustin Pop
cli_option = CliOption
476 a8083063 Iustin Pop
477 a8083063 Iustin Pop
478 771734c9 Iustin Pop
_YESNO = ("yes", "no")
479 771734c9 Iustin Pop
_YORNO = "yes|no"
480 771734c9 Iustin Pop
481 c38c44ad Michael Hanselmann
DEBUG_OPT = cli_option("-d", "--debug", default=False,
482 c38c44ad Michael Hanselmann
                       action="store_true",
483 c38c44ad Michael Hanselmann
                       help="Turn debugging on")
484 c38c44ad Michael Hanselmann
485 c38c44ad Michael Hanselmann
NOHDR_OPT = cli_option("--no-headers", default=False,
486 c38c44ad Michael Hanselmann
                       action="store_true", dest="no_headers",
487 c38c44ad Michael Hanselmann
                       help="Don't display column headers")
488 c38c44ad Michael Hanselmann
489 c38c44ad Michael Hanselmann
SEP_OPT = cli_option("--separator", default=None,
490 c38c44ad Michael Hanselmann
                     action="store", dest="separator",
491 c38c44ad Michael Hanselmann
                     help=("Separator between output fields"
492 c38c44ad Michael Hanselmann
                           " (defaults to one space)"))
493 c38c44ad Michael Hanselmann
494 c38c44ad Michael Hanselmann
USEUNITS_OPT = cli_option("--units", default=None,
495 c38c44ad Michael Hanselmann
                          dest="units", choices=('h', 'm', 'g', 't'),
496 c38c44ad Michael Hanselmann
                          help="Specify units for output (one of hmgt)")
497 c38c44ad Michael Hanselmann
498 c38c44ad Michael Hanselmann
FIELDS_OPT = cli_option("-o", "--output", dest="output", action="store",
499 c38c44ad Michael Hanselmann
                        type="string", metavar="FIELDS",
500 c38c44ad Michael Hanselmann
                        help="Comma separated list of output fields")
501 c38c44ad Michael Hanselmann
502 c38c44ad Michael Hanselmann
FORCE_OPT = cli_option("-f", "--force", dest="force", action="store_true",
503 c38c44ad Michael Hanselmann
                       default=False, help="Force the operation")
504 c38c44ad Michael Hanselmann
505 c38c44ad Michael Hanselmann
CONFIRM_OPT = cli_option("--yes", dest="confirm", action="store_true",
506 c38c44ad Michael Hanselmann
                         default=False, help="Do not require confirmation")
507 c38c44ad Michael Hanselmann
508 c38c44ad Michael Hanselmann
TAG_SRC_OPT = cli_option("--from", dest="tags_source",
509 c38c44ad Michael Hanselmann
                         default=None, help="File with tag names")
510 c38c44ad Michael Hanselmann
511 c38c44ad Michael Hanselmann
SUBMIT_OPT = cli_option("--submit", dest="submit_only",
512 c38c44ad Michael Hanselmann
                        default=False, action="store_true",
513 c38c44ad Michael Hanselmann
                        help=("Submit the job and return the job ID, but"
514 c38c44ad Michael Hanselmann
                              " don't wait for the job to finish"))
515 c38c44ad Michael Hanselmann
516 c38c44ad Michael Hanselmann
SYNC_OPT = cli_option("--sync", dest="do_locking",
517 c38c44ad Michael Hanselmann
                      default=False, action="store_true",
518 c38c44ad Michael Hanselmann
                      help=("Grab locks while doing the queries"
519 c38c44ad Michael Hanselmann
                            " in order to ensure more consistent results"))
520 c38c44ad Michael Hanselmann
521 c38c44ad Michael Hanselmann
_DRY_RUN_OPT = cli_option("--dry-run", default=False,
522 c38c44ad Michael Hanselmann
                          action="store_true",
523 c38c44ad Michael Hanselmann
                          help=("Do not execute the operation, just run the"
524 c38c44ad Michael Hanselmann
                                " check steps and verify it it could be"
525 c38c44ad Michael Hanselmann
                                " executed"))
526 c38c44ad Michael Hanselmann
527 9cdb9578 Iustin Pop
VERBOSE_OPT = cli_option("-v", "--verbose", default=False,
528 9cdb9578 Iustin Pop
                         action="store_true",
529 9cdb9578 Iustin Pop
                         help="Increase the verbosity of the operation")
530 9cdb9578 Iustin Pop
531 a0c9776a Iustin Pop
DEBUG_SIMERR_OPT = cli_option("--debug-simulate-errors", default=False,
532 a0c9776a Iustin Pop
                              action="store_true", dest="simulate_errors",
533 a0c9776a Iustin Pop
                              help="Debugging option that makes the operation"
534 a0c9776a Iustin Pop
                              " treat most runtime checks as failed")
535 a0c9776a Iustin Pop
536 3f75b4f3 Iustin Pop
NWSYNC_OPT = cli_option("--no-wait-for-sync", dest="wait_for_sync",
537 3f75b4f3 Iustin Pop
                        default=True, action="store_false",
538 3f75b4f3 Iustin Pop
                        help="Don't wait for sync (DANGEROUS!)")
539 3f75b4f3 Iustin Pop
540 4f365444 Iustin Pop
DISK_TEMPLATE_OPT = cli_option("-t", "--disk-template", dest="disk_template",
541 4f365444 Iustin Pop
                               help="Custom disk setup (diskless, file,"
542 4f365444 Iustin Pop
                               " plain or drbd)",
543 4f365444 Iustin Pop
                               default=None, metavar="TEMPL",
544 4f365444 Iustin Pop
                               choices=list(constants.DISK_TEMPLATES))
545 4f365444 Iustin Pop
546 26023ecd Iustin Pop
NONICS_OPT = cli_option("--no-nics", default=False, action="store_true",
547 26023ecd Iustin Pop
                        help="Do not create any network cards for"
548 26023ecd Iustin Pop
                        " the instance")
549 26023ecd Iustin Pop
550 4a25828c Iustin Pop
FILESTORE_DIR_OPT = cli_option("--file-storage-dir", dest="file_storage_dir",
551 4a25828c Iustin Pop
                               help="Relative path under default cluster-wide"
552 4a25828c Iustin Pop
                               " file storage dir to store file-based disks",
553 4a25828c Iustin Pop
                               default=None, metavar="<DIR>")
554 4a25828c Iustin Pop
555 0f87c43e Iustin Pop
FILESTORE_DRIVER_OPT = cli_option("--file-driver", dest="file_driver",
556 0f87c43e Iustin Pop
                                  help="Driver to use for image files",
557 0f87c43e Iustin Pop
                                  default="loop", metavar="<DRIVER>",
558 0f87c43e Iustin Pop
                                  choices=list(constants.FILE_DRIVER))
559 0f87c43e Iustin Pop
560 4eb62659 Iustin Pop
IALLOCATOR_OPT = cli_option("-I", "--iallocator", metavar="<NAME>",
561 4eb62659 Iustin Pop
                            help="Select nodes for the instance automatically"
562 4eb62659 Iustin Pop
                            " using the <NAME> iallocator plugin",
563 4eb62659 Iustin Pop
                            default=None, type="string",
564 4eb62659 Iustin Pop
                            completion_suggest=OPT_COMPL_ONE_IALLOCATOR)
565 4eb62659 Iustin Pop
566 d3ed23ff Iustin Pop
OS_OPT = cli_option("-o", "--os-type", dest="os", help="What OS to run",
567 d3ed23ff Iustin Pop
                    metavar="<os>",
568 d3ed23ff Iustin Pop
                    completion_suggest=OPT_COMPL_ONE_OS)
569 d3ed23ff Iustin Pop
570 087ed2ed Iustin Pop
BACKEND_OPT = cli_option("-B", "--backend-parameters", dest="beparams",
571 087ed2ed Iustin Pop
                         type="keyval", default={},
572 087ed2ed Iustin Pop
                         help="Backend parameters")
573 48f212d7 Iustin Pop
574 48f212d7 Iustin Pop
HVOPTS_OPT =  cli_option("-H", "--hypervisor-parameters", type="keyval",
575 48f212d7 Iustin Pop
                         default={}, dest="hvparams",
576 48f212d7 Iustin Pop
                         help="Hypervisor parameters")
577 087ed2ed Iustin Pop
578 236fd9c4 Iustin Pop
HYPERVISOR_OPT = cli_option("-H", "--hypervisor-parameters", dest="hypervisor",
579 236fd9c4 Iustin Pop
                            help="Hypervisor and hypervisor options, in the"
580 236fd9c4 Iustin Pop
                            " format hypervisor:option=value,option=value,...",
581 236fd9c4 Iustin Pop
                            default=None, type="identkeyval")
582 073271f6 Iustin Pop
583 073271f6 Iustin Pop
HVLIST_OPT = cli_option("-H", "--hypervisor-parameters", dest="hvparams",
584 073271f6 Iustin Pop
                        help="Hypervisor and hypervisor options, in the"
585 073271f6 Iustin Pop
                        " format hypervisor:option=value,option=value,...",
586 073271f6 Iustin Pop
                        default=[], action="append", type="identkeyval")
587 236fd9c4 Iustin Pop
588 91e0748c Iustin Pop
NOIPCHECK_OPT = cli_option("--no-ip-check", dest="ip_check", default=True,
589 91e0748c Iustin Pop
                           action="store_false",
590 91e0748c Iustin Pop
                           help="Don't check that the instance's IP"
591 91e0748c Iustin Pop
                           " is alive")
592 91e0748c Iustin Pop
593 7d3a9fab Iustin Pop
NET_OPT = cli_option("--net",
594 7d3a9fab Iustin Pop
                     help="NIC parameters", default=[],
595 7d3a9fab Iustin Pop
                     dest="nics", action="append", type="identkeyval")
596 e3876ccb Iustin Pop
597 e3876ccb Iustin Pop
DISK_OPT = cli_option("--disk", help="Disk parameters", default=[],
598 e3876ccb Iustin Pop
                      dest="disks", action="append", type="identkeyval")
599 91e0748c Iustin Pop
600 4b038a1e Iustin Pop
DISKIDX_OPT = cli_option("--disks", dest="disks", default=None,
601 4b038a1e Iustin Pop
                         help="Comma-separated list of disks"
602 4b038a1e Iustin Pop
                         " indices to act on (e.g. 0,2) (optional,"
603 4b038a1e Iustin Pop
                         " defaults to all disks)")
604 4b038a1e Iustin Pop
605 ff00c1a7 Iustin Pop
OS_SIZE_OPT = cli_option("-s", "--os-size", dest="sd_size",
606 ff00c1a7 Iustin Pop
                         help="Enforces a single-disk configuration using the"
607 ff00c1a7 Iustin Pop
                         " given disk size, in MiB unless a suffix is used",
608 ff00c1a7 Iustin Pop
                         default=None, type="unit", metavar="<size>")
609 ff00c1a7 Iustin Pop
610 82a786d5 Iustin Pop
IGNORE_CONSIST_OPT = cli_option("--ignore-consistency",
611 82a786d5 Iustin Pop
                                dest="ignore_consistency",
612 82a786d5 Iustin Pop
                                action="store_true", default=False,
613 82a786d5 Iustin Pop
                                help="Ignore the consistency of the disks on"
614 82a786d5 Iustin Pop
                                " the secondary")
615 82a786d5 Iustin Pop
616 f2a0828c Iustin Pop
NONLIVE_OPT = cli_option("--non-live", dest="live",
617 f2a0828c Iustin Pop
                         default=True, action="store_false",
618 f2a0828c Iustin Pop
                         help="Do a non-live migration (this usually means"
619 f2a0828c Iustin Pop
                         " freeze the instance, save the state, transfer and"
620 f2a0828c Iustin Pop
                         " only then resume running on the secondary node)")
621 f2a0828c Iustin Pop
622 990b7886 Iustin Pop
NODE_PLACEMENT_OPT = cli_option("-n", "--node", dest="node",
623 990b7886 Iustin Pop
                                help="Target node and optional secondary node",
624 990b7886 Iustin Pop
                                metavar="<pnode>[:<snode>]",
625 990b7886 Iustin Pop
                                completion_suggest=OPT_COMPL_INST_ADD_NODES)
626 990b7886 Iustin Pop
627 7edc4637 Iustin Pop
NODE_LIST_OPT = cli_option("-n", "--node", dest="nodes", default=[],
628 7edc4637 Iustin Pop
                           action="append", metavar="<node>",
629 7edc4637 Iustin Pop
                           help="Use only this node (can be used multiple"
630 7edc4637 Iustin Pop
                           " times, if not given defaults to all nodes)",
631 7edc4637 Iustin Pop
                           completion_suggest=OPT_COMPL_ONE_NODE)
632 f36d7d81 Iustin Pop
633 f36d7d81 Iustin Pop
SINGLE_NODE_OPT = cli_option("-n", "--node", dest="node", help="Target node",
634 f36d7d81 Iustin Pop
                             metavar="<node>",
635 f36d7d81 Iustin Pop
                             completion_suggest=OPT_COMPL_ONE_NODE)
636 7edc4637 Iustin Pop
637 edeb878a Iustin Pop
NOSTART_OPT = cli_option("--no-start", dest="start", default=True,
638 edeb878a Iustin Pop
                         action="store_false",
639 edeb878a Iustin Pop
                         help="Don't start the instance after creation")
640 edeb878a Iustin Pop
641 fdcf4d84 Iustin Pop
SHOWCMD_OPT = cli_option("--show-cmd", dest="show_command",
642 fdcf4d84 Iustin Pop
                         action="store_true", default=False,
643 fdcf4d84 Iustin Pop
                         help="Show command instead of executing it")
644 fdcf4d84 Iustin Pop
645 baef337d Iustin Pop
CLEANUP_OPT = cli_option("--cleanup", dest="cleanup",
646 baef337d Iustin Pop
                         default=False, action="store_true",
647 baef337d Iustin Pop
                         help="Instead of performing the migration, try to"
648 baef337d Iustin Pop
                         " recover from a failed cleanup. This is safe"
649 baef337d Iustin Pop
                         " to run even if the instance is healthy, but it"
650 baef337d Iustin Pop
                         " will create extra replication traffic and "
651 baef337d Iustin Pop
                         " disrupt briefly the replication (like during the"
652 baef337d Iustin Pop
                         " migration")
653 baef337d Iustin Pop
654 99a8c799 Iustin Pop
STATIC_OPT = cli_option("-s", "--static", dest="static",
655 99a8c799 Iustin Pop
                        action="store_true", default=False,
656 99a8c799 Iustin Pop
                        help="Only show configuration data, not runtime data")
657 99a8c799 Iustin Pop
658 2d5e7ae1 Iustin Pop
ALL_OPT = cli_option("--all", dest="show_all",
659 2d5e7ae1 Iustin Pop
                     default=False, action="store_true",
660 2d5e7ae1 Iustin Pop
                     help="Show info on all instances on the cluster."
661 2d5e7ae1 Iustin Pop
                     " This can take a long time to run, use wisely")
662 2d5e7ae1 Iustin Pop
663 67840b40 Iustin Pop
SELECT_OS_OPT = cli_option("--select-os", dest="select_os",
664 67840b40 Iustin Pop
                           action="store_true", default=False,
665 67840b40 Iustin Pop
                           help="Interactive OS reinstall, lists available"
666 67840b40 Iustin Pop
                           " OS templates for selection")
667 2d5e7ae1 Iustin Pop
668 b6e841a8 Iustin Pop
IGNORE_FAILURES_OPT = cli_option("--ignore-failures", dest="ignore_failures",
669 b6e841a8 Iustin Pop
                                 action="store_true", default=False,
670 b6e841a8 Iustin Pop
                                 help="Remove the instance from the cluster"
671 b6e841a8 Iustin Pop
                                 " configuration even if there are failures"
672 b6e841a8 Iustin Pop
                                 " during the removal process")
673 b6e841a8 Iustin Pop
674 a14db5ff Iustin Pop
NEW_SECONDARY_OPT = cli_option("-n", "--new-secondary", dest="dst_node",
675 a14db5ff Iustin Pop
                               help="Specifies the new secondary node",
676 a14db5ff Iustin Pop
                               metavar="NODE", default=None,
677 a14db5ff Iustin Pop
                               completion_suggest=OPT_COMPL_ONE_NODE)
678 a14db5ff Iustin Pop
679 a72d0a79 Iustin Pop
ON_PRIMARY_OPT = cli_option("-p", "--on-primary", dest="on_primary",
680 a72d0a79 Iustin Pop
                            default=False, action="store_true",
681 a72d0a79 Iustin Pop
                            help="Replace the disk(s) on the primary"
682 a72d0a79 Iustin Pop
                            " node (only for the drbd template)")
683 feb09e6a Iustin Pop
684 feb09e6a Iustin Pop
ON_SECONDARY_OPT = cli_option("-s", "--on-secondary", dest="on_secondary",
685 feb09e6a Iustin Pop
                              default=False, action="store_true",
686 feb09e6a Iustin Pop
                              help="Replace the disk(s) on the secondary"
687 feb09e6a Iustin Pop
                              " node (only for the drbd template)")
688 e00f7a05 Iustin Pop
689 e00f7a05 Iustin Pop
AUTO_REPLACE_OPT = cli_option("-a", "--auto", dest="auto",
690 e00f7a05 Iustin Pop
                              default=False, action="store_true",
691 e00f7a05 Iustin Pop
                              help="Automatically replace faulty disks"
692 e00f7a05 Iustin Pop
                              " (only for the drbd template)")
693 a72d0a79 Iustin Pop
694 05586c90 Iustin Pop
IGNORE_SIZE_OPT = cli_option("--ignore-size", dest="ignore_size",
695 05586c90 Iustin Pop
                             default=False, action="store_true",
696 05586c90 Iustin Pop
                             help="Ignore current recorded size"
697 05586c90 Iustin Pop
                             " (useful for forcing activation when"
698 05586c90 Iustin Pop
                             " the recorded size is wrong)")
699 05586c90 Iustin Pop
700 df62e5db Iustin Pop
SRC_NODE_OPT = cli_option("--src-node", dest="src_node", help="Source node",
701 df62e5db Iustin Pop
                          metavar="<node>",
702 df62e5db Iustin Pop
                          completion_suggest=OPT_COMPL_ONE_NODE)
703 df62e5db Iustin Pop
704 df62e5db Iustin Pop
SRC_DIR_OPT = cli_option("--src-dir", dest="src_dir", help="Source directory",
705 df62e5db Iustin Pop
                         metavar="<dir>")
706 df62e5db Iustin Pop
707 8d823629 Iustin Pop
SECONDARY_IP_OPT = cli_option("-s", "--secondary-ip", dest="secondary_ip",
708 8d823629 Iustin Pop
                              help="Specify the secondary ip for the node",
709 8d823629 Iustin Pop
                              metavar="ADDRESS", default=None)
710 8d823629 Iustin Pop
711 b8d0f938 Iustin Pop
READD_OPT = cli_option("--readd", dest="readd",
712 b8d0f938 Iustin Pop
                       default=False, action="store_true",
713 b8d0f938 Iustin Pop
                       help="Readd old node after replacing it")
714 b8d0f938 Iustin Pop
715 fcdde7f2 Iustin Pop
NOSSH_KEYCHECK_OPT = cli_option("--no-ssh-key-check", dest="ssh_key_check",
716 fcdde7f2 Iustin Pop
                                default=True, action="store_false",
717 fcdde7f2 Iustin Pop
                                help="Disable SSH key fingerprint checking")
718 fcdde7f2 Iustin Pop
719 c38c44ad Michael Hanselmann
720 771734c9 Iustin Pop
MC_OPT = cli_option("-C", "--master-candidate", dest="master_candidate",
721 771734c9 Iustin Pop
                    choices=_YESNO, default=None, metavar=_YORNO,
722 771734c9 Iustin Pop
                    help="Set the master_candidate flag on the node")
723 771734c9 Iustin Pop
724 771734c9 Iustin Pop
OFFLINE_OPT = cli_option("-O", "--offline", dest="offline", metavar=_YORNO,
725 771734c9 Iustin Pop
                         choices=_YESNO, default=None,
726 771734c9 Iustin Pop
                         help="Set the offline flag on the node")
727 771734c9 Iustin Pop
728 771734c9 Iustin Pop
DRAINED_OPT = cli_option("-D", "--drained", dest="drained", metavar=_YORNO,
729 771734c9 Iustin Pop
                         choices=_YESNO, default=None,
730 771734c9 Iustin Pop
                         help="Set the drained flag on the node")
731 771734c9 Iustin Pop
732 e7e09483 Iustin Pop
ALLOCATABLE_OPT = cli_option("--allocatable", dest="allocatable",
733 e7e09483 Iustin Pop
                             choices=_YESNO, default=None, metavar=_YORNO,
734 e7e09483 Iustin Pop
                             help="Set the allocatable flag on a volume")
735 e7e09483 Iustin Pop
736 831040bf Iustin Pop
NOLVM_STORAGE_OPT = cli_option("--no-lvm-storage", dest="lvm_storage",
737 831040bf Iustin Pop
                               help="Disable support for lvm based instances"
738 831040bf Iustin Pop
                               " (cluster-wide)",
739 831040bf Iustin Pop
                               action="store_false", default=True)
740 831040bf Iustin Pop
741 383a3591 Iustin Pop
ENABLED_HV_OPT = cli_option("--enabled-hypervisors",
742 383a3591 Iustin Pop
                            dest="enabled_hypervisors",
743 383a3591 Iustin Pop
                            help="Comma-separated list of hypervisors",
744 383a3591 Iustin Pop
                            type="string", default=None)
745 383a3591 Iustin Pop
746 4fbc93dd Iustin Pop
NIC_PARAMS_OPT = cli_option("-N", "--nic-parameters", dest="nicparams",
747 4fbc93dd Iustin Pop
                            type="keyval", default={},
748 4fbc93dd Iustin Pop
                            help="NIC parameters")
749 4fbc93dd Iustin Pop
750 e32df528 Iustin Pop
CP_SIZE_OPT = cli_option("-C", "--candidate-pool-size", default=None,
751 e32df528 Iustin Pop
                         dest="candidate_pool_size", type="int",
752 e32df528 Iustin Pop
                         help="Set the candidate pool size")
753 e32df528 Iustin Pop
754 b58726e8 Iustin Pop
VG_NAME_OPT = cli_option("-g", "--vg-name", dest="vg_name",
755 b58726e8 Iustin Pop
                         help="Enables LVM and specifies the volume group"
756 b58726e8 Iustin Pop
                         " name (cluster-wide) for disk allocation [xenvg]",
757 b58726e8 Iustin Pop
                         metavar="VG", default=None)
758 b58726e8 Iustin Pop
759 1f587d3d Iustin Pop
YES_DOIT_OPT = cli_option("--yes-do-it", dest="yes_do_it",
760 1f587d3d Iustin Pop
                          help="Destroy cluster", action="store_true")
761 b58726e8 Iustin Pop
762 58371861 Iustin Pop
NOVOTING_OPT = cli_option("--no-voting", dest="no_voting",
763 58371861 Iustin Pop
                          help="Skip node agreement check (dangerous)",
764 58371861 Iustin Pop
                          action="store_true", default=False)
765 58371861 Iustin Pop
766 e3646f22 Iustin Pop
MAC_PREFIX_OPT = cli_option("-m", "--mac-prefix", dest="mac_prefix",
767 e3646f22 Iustin Pop
                            help="Specify the mac prefix for the instance IP"
768 e3646f22 Iustin Pop
                            " addresses, in the format XX:XX:XX",
769 e3646f22 Iustin Pop
                            metavar="PREFIX",
770 e3646f22 Iustin Pop
                            default=None)
771 e3646f22 Iustin Pop
772 29392516 Iustin Pop
MASTER_NETDEV_OPT = cli_option("--master-netdev", dest="master_netdev",
773 29392516 Iustin Pop
                               help="Specify the node interface (cluster-wide)"
774 29392516 Iustin Pop
                               " on which the master IP address will be added "
775 29392516 Iustin Pop
                               " [%s]" % constants.DEFAULT_BRIDGE,
776 29392516 Iustin Pop
                               metavar="NETDEV",
777 29392516 Iustin Pop
                               default=constants.DEFAULT_BRIDGE)
778 29392516 Iustin Pop
779 29392516 Iustin Pop
780 29392516 Iustin Pop
GLOBAL_FILEDIR_OPT = cli_option("--file-storage-dir", dest="file_storage_dir",
781 29392516 Iustin Pop
                                help="Specify the default directory (cluster-"
782 29392516 Iustin Pop
                                "wide) for storing the file-based disks [%s]" %
783 29392516 Iustin Pop
                                constants.DEFAULT_FILE_STORAGE_DIR,
784 29392516 Iustin Pop
                                metavar="DIR",
785 29392516 Iustin Pop
                                default=constants.DEFAULT_FILE_STORAGE_DIR)
786 29392516 Iustin Pop
787 29392516 Iustin Pop
NOMODIFY_ETCHOSTS_OPT = cli_option("--no-etc-hosts", dest="modify_etc_hosts",
788 29392516 Iustin Pop
                                   help="Don't modify /etc/hosts",
789 29392516 Iustin Pop
                                   action="store_false", default=True)
790 29392516 Iustin Pop
791 14e9e7f3 Iustin Pop
ERROR_CODES_OPT = cli_option("--error-codes", dest="error_codes",
792 14e9e7f3 Iustin Pop
                             help="Enable parseable error messages",
793 14e9e7f3 Iustin Pop
                             action="store_true", default=False)
794 14e9e7f3 Iustin Pop
795 14e9e7f3 Iustin Pop
NONPLUS1_OPT = cli_option("--no-nplus1-mem", dest="skip_nplusone_mem",
796 14e9e7f3 Iustin Pop
                          help="Skip N+1 memory redundancy tests",
797 14e9e7f3 Iustin Pop
                          action="store_true", default=False)
798 14e9e7f3 Iustin Pop
799 12054861 Iustin Pop
REBOOT_TYPE_OPT = cli_option("-t", "--type", dest="reboot_type",
800 12054861 Iustin Pop
                             help="Type of reboot: soft/hard/full",
801 12054861 Iustin Pop
                             default=constants.INSTANCE_REBOOT_HARD,
802 12054861 Iustin Pop
                             metavar="<REBOOT>",
803 12054861 Iustin Pop
                             choices=list(constants.REBOOT_TYPES))
804 12054861 Iustin Pop
805 ee3f9578 Iustin Pop
IGNORE_SECONDARIES_OPT = cli_option("--ignore-secondaries",
806 ee3f9578 Iustin Pop
                                    dest="ignore_secondaries",
807 ee3f9578 Iustin Pop
                                    default=False, action="store_true",
808 ee3f9578 Iustin Pop
                                    help="Ignore errors from secondaries")
809 ee3f9578 Iustin Pop
810 44c44832 Iustin Pop
NOSHUTDOWN_OPT = cli_option("","--noshutdown", dest="shutdown",
811 44c44832 Iustin Pop
                            action="store_false", default=True,
812 44c44832 Iustin Pop
                            help="Don't shutdown the instance (unsafe)")
813 44c44832 Iustin Pop
814 44c44832 Iustin Pop
815 771734c9 Iustin Pop
816 de47cf8f Guido Trotter
def _ParseArgs(argv, commands, aliases):
817 c41eea6e Iustin Pop
  """Parser for the command line arguments.
818 a8083063 Iustin Pop

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

822 c41eea6e Iustin Pop
  @param argv: the command line
823 c41eea6e Iustin Pop
  @param commands: dictionary with special contents, see the design
824 c41eea6e Iustin Pop
      doc for cmdline handling
825 c41eea6e Iustin Pop
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
826 098c0958 Michael Hanselmann

827 a8083063 Iustin Pop
  """
828 a8083063 Iustin Pop
  if len(argv) == 0:
829 a8083063 Iustin Pop
    binary = "<command>"
830 a8083063 Iustin Pop
  else:
831 a8083063 Iustin Pop
    binary = argv[0].split("/")[-1]
832 a8083063 Iustin Pop
833 a8083063 Iustin Pop
  if len(argv) > 1 and argv[1] == "--version":
834 03298ebe Michael Hanselmann
    ToStdout("%s (ganeti) %s", binary, constants.RELEASE_VERSION)
835 a8083063 Iustin Pop
    # Quit right away. That way we don't have to care about this special
836 a8083063 Iustin Pop
    # argument. optparse.py does it the same.
837 a8083063 Iustin Pop
    sys.exit(0)
838 a8083063 Iustin Pop
839 de47cf8f Guido Trotter
  if len(argv) < 2 or not (argv[1] in commands or
840 70a35b6f Guido Trotter
                           argv[1] in aliases):
841 a8083063 Iustin Pop
    # let's do a nice thing
842 a8083063 Iustin Pop
    sortedcmds = commands.keys()
843 a8083063 Iustin Pop
    sortedcmds.sort()
844 03298ebe Michael Hanselmann
845 03298ebe Michael Hanselmann
    ToStdout("Usage: %s {command} [options...] [argument...]", binary)
846 03298ebe Michael Hanselmann
    ToStdout("%s <command> --help to see details, or man %s", binary, binary)
847 03298ebe Michael Hanselmann
    ToStdout("")
848 03298ebe Michael Hanselmann
849 a8083063 Iustin Pop
    # compute the max line length for cmd + usage
850 4e713df6 Iustin Pop
    mlen = max([len(" %s" % cmd) for cmd in commands])
851 a8083063 Iustin Pop
    mlen = min(60, mlen) # should not get here...
852 03298ebe Michael Hanselmann
853 a8083063 Iustin Pop
    # and format a nice command list
854 03298ebe Michael Hanselmann
    ToStdout("Commands:")
855 a8083063 Iustin Pop
    for cmd in sortedcmds:
856 4e713df6 Iustin Pop
      cmdstr = " %s" % (cmd,)
857 9a033156 Iustin Pop
      help_text = commands[cmd][4]
858 03298ebe Michael Hanselmann
      help_lines = textwrap.wrap(help_text, 79 - 3 - mlen)
859 03298ebe Michael Hanselmann
      ToStdout("%-*s - %s", mlen, cmdstr, help_lines.pop(0))
860 a8083063 Iustin Pop
      for line in help_lines:
861 03298ebe Michael Hanselmann
        ToStdout("%-*s   %s", mlen, "", line)
862 03298ebe Michael Hanselmann
863 03298ebe Michael Hanselmann
    ToStdout("")
864 03298ebe Michael Hanselmann
865 a8083063 Iustin Pop
    return None, None, None
866 de47cf8f Guido Trotter
867 de47cf8f Guido Trotter
  # get command, unalias it, and look it up in commands
868 a8083063 Iustin Pop
  cmd = argv.pop(1)
869 de47cf8f Guido Trotter
  if cmd in aliases:
870 de47cf8f Guido Trotter
    if cmd in commands:
871 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' overrides an existing"
872 de47cf8f Guido Trotter
                                   " command" % cmd)
873 de47cf8f Guido Trotter
874 de47cf8f Guido Trotter
    if aliases[cmd] not in commands:
875 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' maps to non-existing"
876 de47cf8f Guido Trotter
                                   " command '%s'" % (cmd, aliases[cmd]))
877 de47cf8f Guido Trotter
878 de47cf8f Guido Trotter
    cmd = aliases[cmd]
879 de47cf8f Guido Trotter
880 a8005e17 Michael Hanselmann
  func, args_def, parser_opts, usage, description = commands[cmd]
881 064c21f8 Iustin Pop
  parser = OptionParser(option_list=parser_opts + [_DRY_RUN_OPT, DEBUG_OPT],
882 a8083063 Iustin Pop
                        description=description,
883 a8083063 Iustin Pop
                        formatter=TitledHelpFormatter(),
884 a8083063 Iustin Pop
                        usage="%%prog %s %s" % (cmd, usage))
885 a8083063 Iustin Pop
  parser.disable_interspersed_args()
886 a8083063 Iustin Pop
  options, args = parser.parse_args()
887 a8005e17 Michael Hanselmann
888 a8005e17 Michael Hanselmann
  if not _CheckArguments(cmd, args_def, args):
889 a8083063 Iustin Pop
    return None, None, None
890 a8083063 Iustin Pop
891 a8083063 Iustin Pop
  return func, options, args
892 a8083063 Iustin Pop
893 a8083063 Iustin Pop
894 a8005e17 Michael Hanselmann
def _CheckArguments(cmd, args_def, args):
895 a8005e17 Michael Hanselmann
  """Verifies the arguments using the argument definition.
896 a8005e17 Michael Hanselmann

897 a8005e17 Michael Hanselmann
  Algorithm:
898 a8005e17 Michael Hanselmann

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

901 a8005e17 Michael Hanselmann
    1. For each argument in definition
902 a8005e17 Michael Hanselmann

903 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
904 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
905 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
906 a8005e17 Michael Hanselmann

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

909 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
910 a8005e17 Michael Hanselmann

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

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

915 a8005e17 Michael Hanselmann
  """
916 a8005e17 Michael Hanselmann
  if args and not args_def:
917 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects no arguments", cmd)
918 a8005e17 Michael Hanselmann
    return False
919 a8005e17 Michael Hanselmann
920 a8005e17 Michael Hanselmann
  min_count = None
921 a8005e17 Michael Hanselmann
  max_count = None
922 a8005e17 Michael Hanselmann
  check_max = None
923 a8005e17 Michael Hanselmann
924 a8005e17 Michael Hanselmann
  last_idx = len(args_def) - 1
925 a8005e17 Michael Hanselmann
926 a8005e17 Michael Hanselmann
  for idx, arg in enumerate(args_def):
927 a8005e17 Michael Hanselmann
    if min_count is None:
928 a8005e17 Michael Hanselmann
      min_count = arg.min
929 a8005e17 Michael Hanselmann
    elif arg.min is not None:
930 a8005e17 Michael Hanselmann
      min_count += arg.min
931 a8005e17 Michael Hanselmann
932 a8005e17 Michael Hanselmann
    if max_count is None:
933 a8005e17 Michael Hanselmann
      max_count = arg.max
934 a8005e17 Michael Hanselmann
    elif arg.max is not None:
935 a8005e17 Michael Hanselmann
      max_count += arg.max
936 a8005e17 Michael Hanselmann
937 a8005e17 Michael Hanselmann
    if idx == last_idx:
938 a8005e17 Michael Hanselmann
      check_max = (arg.max is not None)
939 a8005e17 Michael Hanselmann
940 a8005e17 Michael Hanselmann
    elif arg.max is None:
941 a8005e17 Michael Hanselmann
      raise errors.ProgrammerError("Only the last argument can have max=None")
942 a8005e17 Michael Hanselmann
943 a8005e17 Michael Hanselmann
  if check_max:
944 a8005e17 Michael Hanselmann
    # Command with exact number of arguments
945 a8005e17 Michael Hanselmann
    if (min_count is not None and max_count is not None and
946 a8005e17 Michael Hanselmann
        min_count == max_count and len(args) != min_count):
947 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects %d argument(s)", cmd, min_count)
948 a8005e17 Michael Hanselmann
      return False
949 a8005e17 Michael Hanselmann
950 a8005e17 Michael Hanselmann
    # Command with limited number of arguments
951 a8005e17 Michael Hanselmann
    if max_count is not None and len(args) > max_count:
952 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects only %d argument(s)",
953 a8005e17 Michael Hanselmann
               cmd, max_count)
954 a8005e17 Michael Hanselmann
      return False
955 a8005e17 Michael Hanselmann
956 a8005e17 Michael Hanselmann
  # Command with some required arguments
957 a8005e17 Michael Hanselmann
  if min_count is not None and len(args) < min_count:
958 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects at least %d argument(s)",
959 a8005e17 Michael Hanselmann
             cmd, min_count)
960 a8005e17 Michael Hanselmann
    return False
961 a8005e17 Michael Hanselmann
962 a8005e17 Michael Hanselmann
  return True
963 a8005e17 Michael Hanselmann
964 a8005e17 Michael Hanselmann
965 60d49723 Michael Hanselmann
def SplitNodeOption(value):
966 60d49723 Michael Hanselmann
  """Splits the value of a --node option.
967 60d49723 Michael Hanselmann

968 60d49723 Michael Hanselmann
  """
969 60d49723 Michael Hanselmann
  if value and ':' in value:
970 60d49723 Michael Hanselmann
    return value.split(':', 1)
971 60d49723 Michael Hanselmann
  else:
972 60d49723 Michael Hanselmann
    return (value, None)
973 60d49723 Michael Hanselmann
974 60d49723 Michael Hanselmann
975 07150497 Guido Trotter
def CalculateOSNames(os_name, os_variants):
976 07150497 Guido Trotter
  """Calculates all the names an OS can be called, according to its variants.
977 07150497 Guido Trotter

978 07150497 Guido Trotter
  @type os_name: string
979 07150497 Guido Trotter
  @param os_name: base name of the os
980 07150497 Guido Trotter
  @type os_variants: list or None
981 07150497 Guido Trotter
  @param os_variants: list of supported variants
982 07150497 Guido Trotter
  @rtype: list
983 07150497 Guido Trotter
  @return: list of valid names
984 07150497 Guido Trotter

985 07150497 Guido Trotter
  """
986 07150497 Guido Trotter
  if os_variants:
987 07150497 Guido Trotter
    return ['%s+%s' % (os_name, v) for v in os_variants]
988 07150497 Guido Trotter
  else:
989 07150497 Guido Trotter
    return [os_name]
990 07150497 Guido Trotter
991 07150497 Guido Trotter
992 4331f6cd Michael Hanselmann
def UsesRPC(fn):
993 4331f6cd Michael Hanselmann
  def wrapper(*args, **kwargs):
994 4331f6cd Michael Hanselmann
    rpc.Init()
995 4331f6cd Michael Hanselmann
    try:
996 4331f6cd Michael Hanselmann
      return fn(*args, **kwargs)
997 4331f6cd Michael Hanselmann
    finally:
998 4331f6cd Michael Hanselmann
      rpc.Shutdown()
999 4331f6cd Michael Hanselmann
  return wrapper
1000 4331f6cd Michael Hanselmann
1001 4331f6cd Michael Hanselmann
1002 47988778 Iustin Pop
def AskUser(text, choices=None):
1003 47988778 Iustin Pop
  """Ask the user a question.
1004 a8083063 Iustin Pop

1005 c41eea6e Iustin Pop
  @param text: the question to ask
1006 a8083063 Iustin Pop

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

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

1016 a8083063 Iustin Pop
  """
1017 47988778 Iustin Pop
  if choices is None:
1018 47988778 Iustin Pop
    choices = [('y', True, 'Perform the operation'),
1019 47988778 Iustin Pop
               ('n', False, 'Do not perform the operation')]
1020 47988778 Iustin Pop
  if not choices or not isinstance(choices, list):
1021 5bbd3f7f Michael Hanselmann
    raise errors.ProgrammerError("Invalid choices argument to AskUser")
1022 47988778 Iustin Pop
  for entry in choices:
1023 47988778 Iustin Pop
    if not isinstance(entry, tuple) or len(entry) < 3 or entry[0] == '?':
1024 5bbd3f7f Michael Hanselmann
      raise errors.ProgrammerError("Invalid choices element to AskUser")
1025 47988778 Iustin Pop
1026 47988778 Iustin Pop
  answer = choices[-1][1]
1027 47988778 Iustin Pop
  new_text = []
1028 47988778 Iustin Pop
  for line in text.splitlines():
1029 47988778 Iustin Pop
    new_text.append(textwrap.fill(line, 70, replace_whitespace=False))
1030 47988778 Iustin Pop
  text = "\n".join(new_text)
1031 a8083063 Iustin Pop
  try:
1032 3023170f Iustin Pop
    f = file("/dev/tty", "a+")
1033 a8083063 Iustin Pop
  except IOError:
1034 47988778 Iustin Pop
    return answer
1035 a8083063 Iustin Pop
  try:
1036 47988778 Iustin Pop
    chars = [entry[0] for entry in choices]
1037 47988778 Iustin Pop
    chars[-1] = "[%s]" % chars[-1]
1038 47988778 Iustin Pop
    chars.append('?')
1039 47988778 Iustin Pop
    maps = dict([(entry[0], entry[1]) for entry in choices])
1040 47988778 Iustin Pop
    while True:
1041 47988778 Iustin Pop
      f.write(text)
1042 47988778 Iustin Pop
      f.write('\n')
1043 47988778 Iustin Pop
      f.write("/".join(chars))
1044 47988778 Iustin Pop
      f.write(": ")
1045 47988778 Iustin Pop
      line = f.readline(2).strip().lower()
1046 47988778 Iustin Pop
      if line in maps:
1047 47988778 Iustin Pop
        answer = maps[line]
1048 47988778 Iustin Pop
        break
1049 47988778 Iustin Pop
      elif line == '?':
1050 47988778 Iustin Pop
        for entry in choices:
1051 47988778 Iustin Pop
          f.write(" %s - %s\n" % (entry[0], entry[2]))
1052 47988778 Iustin Pop
        f.write("\n")
1053 47988778 Iustin Pop
        continue
1054 a8083063 Iustin Pop
  finally:
1055 a8083063 Iustin Pop
    f.close()
1056 a8083063 Iustin Pop
  return answer
1057 a8083063 Iustin Pop
1058 a8083063 Iustin Pop
1059 e9d741b6 Iustin Pop
class JobSubmittedException(Exception):
1060 e9d741b6 Iustin Pop
  """Job was submitted, client should exit.
1061 e9d741b6 Iustin Pop

1062 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1063 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1064 e9d741b6 Iustin Pop

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

1067 e9d741b6 Iustin Pop
  """
1068 e9d741b6 Iustin Pop
1069 e9d741b6 Iustin Pop
1070 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1071 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1072 a8083063 Iustin Pop

1073 0a1e74d9 Iustin Pop
  @type ops: list
1074 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1075 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1076 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1077 0a1e74d9 Iustin Pop
             if None, a new client will be created
1078 a8083063 Iustin Pop

1079 a8083063 Iustin Pop
  """
1080 e2212007 Iustin Pop
  if cl is None:
1081 b33e986b Iustin Pop
    cl = GetClient()
1082 685ee993 Iustin Pop
1083 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1084 0a1e74d9 Iustin Pop
1085 0a1e74d9 Iustin Pop
  return job_id
1086 0a1e74d9 Iustin Pop
1087 0a1e74d9 Iustin Pop
1088 281606c1 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None):
1089 0a1e74d9 Iustin Pop
  """Function to poll for the result of a job.
1090 0a1e74d9 Iustin Pop

1091 0a1e74d9 Iustin Pop
  @type job_id: job identified
1092 0a1e74d9 Iustin Pop
  @param job_id: the job to poll for results
1093 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1094 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1095 0a1e74d9 Iustin Pop
             if None, a new client will be created
1096 0a1e74d9 Iustin Pop

1097 0a1e74d9 Iustin Pop
  """
1098 0a1e74d9 Iustin Pop
  if cl is None:
1099 0a1e74d9 Iustin Pop
    cl = GetClient()
1100 685ee993 Iustin Pop
1101 6c5a7090 Michael Hanselmann
  prev_job_info = None
1102 6c5a7090 Michael Hanselmann
  prev_logmsg_serial = None
1103 6c5a7090 Michael Hanselmann
1104 685ee993 Iustin Pop
  while True:
1105 6c5a7090 Michael Hanselmann
    result = cl.WaitForJobChange(job_id, ["status"], prev_job_info,
1106 6c5a7090 Michael Hanselmann
                                 prev_logmsg_serial)
1107 6c5a7090 Michael Hanselmann
    if not result:
1108 685ee993 Iustin Pop
      # job not found, go away!
1109 0bbe448c Michael Hanselmann
      raise errors.JobLost("Job with id %s lost" % job_id)
1110 685ee993 Iustin Pop
1111 6c5a7090 Michael Hanselmann
    # Split result, a tuple of (field values, log entries)
1112 6c5a7090 Michael Hanselmann
    (job_info, log_entries) = result
1113 6c5a7090 Michael Hanselmann
    (status, ) = job_info
1114 6c5a7090 Michael Hanselmann
1115 6c5a7090 Michael Hanselmann
    if log_entries:
1116 6c5a7090 Michael Hanselmann
      for log_entry in log_entries:
1117 6c5a7090 Michael Hanselmann
        (serial, timestamp, _, message) = log_entry
1118 6c5a7090 Michael Hanselmann
        if callable(feedback_fn):
1119 6c5a7090 Michael Hanselmann
          feedback_fn(log_entry[1:])
1120 6c5a7090 Michael Hanselmann
        else:
1121 26f15862 Iustin Pop
          encoded = utils.SafeEncode(message)
1122 03298ebe Michael Hanselmann
          ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)), encoded)
1123 6c5a7090 Michael Hanselmann
        prev_logmsg_serial = max(prev_logmsg_serial, serial)
1124 6c5a7090 Michael Hanselmann
1125 0bbe448c Michael Hanselmann
    # TODO: Handle canceled and archived jobs
1126 fbf0262f Michael Hanselmann
    elif status in (constants.JOB_STATUS_SUCCESS,
1127 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_ERROR,
1128 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELING,
1129 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELED):
1130 685ee993 Iustin Pop
      break
1131 6c5a7090 Michael Hanselmann
1132 6c5a7090 Michael Hanselmann
    prev_job_info = job_info
1133 685ee993 Iustin Pop
1134 0e050889 Iustin Pop
  jobs = cl.QueryJobs([job_id], ["status", "opstatus", "opresult"])
1135 0bbe448c Michael Hanselmann
  if not jobs:
1136 0bbe448c Michael Hanselmann
    raise errors.JobLost("Job with id %s lost" % job_id)
1137 685ee993 Iustin Pop
1138 0e050889 Iustin Pop
  status, opstatus, result = jobs[0]
1139 0bbe448c Michael Hanselmann
  if status == constants.JOB_STATUS_SUCCESS:
1140 53c04d04 Iustin Pop
    return result
1141 fbf0262f Michael Hanselmann
  elif status in (constants.JOB_STATUS_CANCELING,
1142 fbf0262f Michael Hanselmann
                  constants.JOB_STATUS_CANCELED):
1143 fbf0262f Michael Hanselmann
    raise errors.OpExecError("Job was canceled")
1144 0bbe448c Michael Hanselmann
  else:
1145 0e050889 Iustin Pop
    has_ok = False
1146 0e050889 Iustin Pop
    for idx, (status, msg) in enumerate(zip(opstatus, result)):
1147 0e050889 Iustin Pop
      if status == constants.OP_STATUS_SUCCESS:
1148 0e050889 Iustin Pop
        has_ok = True
1149 0e050889 Iustin Pop
      elif status == constants.OP_STATUS_ERROR:
1150 bcb66fca Iustin Pop
        errors.MaybeRaise(msg)
1151 0e050889 Iustin Pop
        if has_ok:
1152 0e050889 Iustin Pop
          raise errors.OpExecError("partial failure (opcode %d): %s" %
1153 0e050889 Iustin Pop
                                   (idx, msg))
1154 0e050889 Iustin Pop
        else:
1155 0e050889 Iustin Pop
          raise errors.OpExecError(str(msg))
1156 0e050889 Iustin Pop
    # default failure mode
1157 0bbe448c Michael Hanselmann
    raise errors.OpExecError(result)
1158 ceab32dd Iustin Pop
1159 ceab32dd Iustin Pop
1160 0a1e74d9 Iustin Pop
def SubmitOpCode(op, cl=None, feedback_fn=None):
1161 0a1e74d9 Iustin Pop
  """Legacy function to submit an opcode.
1162 0a1e74d9 Iustin Pop

1163 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1164 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1165 0a1e74d9 Iustin Pop
  interaction functions.
1166 0a1e74d9 Iustin Pop

1167 0a1e74d9 Iustin Pop
  """
1168 0a1e74d9 Iustin Pop
  if cl is None:
1169 0a1e74d9 Iustin Pop
    cl = GetClient()
1170 0a1e74d9 Iustin Pop
1171 0a1e74d9 Iustin Pop
  job_id = SendJob([op], cl)
1172 0a1e74d9 Iustin Pop
1173 53c04d04 Iustin Pop
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn)
1174 53c04d04 Iustin Pop
1175 53c04d04 Iustin Pop
  return op_results[0]
1176 0a1e74d9 Iustin Pop
1177 0a1e74d9 Iustin Pop
1178 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1179 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1180 94428652 Iustin Pop

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

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

1188 94428652 Iustin Pop
  """
1189 64c65a2a Iustin Pop
  if opts and opts.dry_run:
1190 64c65a2a Iustin Pop
    op.dry_run = opts.dry_run
1191 94428652 Iustin Pop
  if opts and opts.submit_only:
1192 e9d741b6 Iustin Pop
    job_id = SendJob([op], cl=cl)
1193 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
1194 94428652 Iustin Pop
  else:
1195 94428652 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn)
1196 94428652 Iustin Pop
1197 94428652 Iustin Pop
1198 af30b2fd Michael Hanselmann
def GetClient():
1199 af30b2fd Michael Hanselmann
  # TODO: Cache object?
1200 b33e986b Iustin Pop
  try:
1201 b33e986b Iustin Pop
    client = luxi.Client()
1202 b33e986b Iustin Pop
  except luxi.NoMasterError:
1203 b33e986b Iustin Pop
    master, myself = ssconf.GetMasterAndMyself()
1204 b33e986b Iustin Pop
    if master != myself:
1205 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
1206 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
1207 b33e986b Iustin Pop
                                 master)
1208 b33e986b Iustin Pop
    else:
1209 b33e986b Iustin Pop
      raise
1210 b33e986b Iustin Pop
  return client
1211 af30b2fd Michael Hanselmann
1212 af30b2fd Michael Hanselmann
1213 73702ee7 Iustin Pop
def FormatError(err):
1214 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
1215 73702ee7 Iustin Pop

1216 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
1217 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
1218 73702ee7 Iustin Pop
  second, a string describing the error message (not
1219 73702ee7 Iustin Pop
  newline-terminated).
1220 73702ee7 Iustin Pop

1221 73702ee7 Iustin Pop
  """
1222 73702ee7 Iustin Pop
  retcode = 1
1223 73702ee7 Iustin Pop
  obuf = StringIO()
1224 e2e521d0 Iustin Pop
  msg = str(err)
1225 73702ee7 Iustin Pop
  if isinstance(err, errors.ConfigurationError):
1226 e2e521d0 Iustin Pop
    txt = "Corrupt configuration file: %s" % msg
1227 46fbdd04 Iustin Pop
    logging.error(txt)
1228 e2e521d0 Iustin Pop
    obuf.write(txt + "\n")
1229 73702ee7 Iustin Pop
    obuf.write("Aborting.")
1230 73702ee7 Iustin Pop
    retcode = 2
1231 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksAbort):
1232 73702ee7 Iustin Pop
    obuf.write("Failure: hooks execution failed:\n")
1233 73702ee7 Iustin Pop
    for node, script, out in err.args[0]:
1234 73702ee7 Iustin Pop
      if out:
1235 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s, output: %s\n" %
1236 73702ee7 Iustin Pop
                   (node, script, out))
1237 73702ee7 Iustin Pop
      else:
1238 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s (no output)\n" %
1239 73702ee7 Iustin Pop
                   (node, script))
1240 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksFailure):
1241 e2e521d0 Iustin Pop
    obuf.write("Failure: hooks general failure: %s" % msg)
1242 73702ee7 Iustin Pop
  elif isinstance(err, errors.ResolverError):
1243 73702ee7 Iustin Pop
    this_host = utils.HostInfo.SysName()
1244 73702ee7 Iustin Pop
    if err.args[0] == this_host:
1245 73702ee7 Iustin Pop
      msg = "Failure: can't resolve my own hostname ('%s')"
1246 73702ee7 Iustin Pop
    else:
1247 73702ee7 Iustin Pop
      msg = "Failure: can't resolve hostname '%s'"
1248 73702ee7 Iustin Pop
    obuf.write(msg % err.args[0])
1249 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpPrereqError):
1250 73702ee7 Iustin Pop
    obuf.write("Failure: prerequisites not met for this"
1251 e2e521d0 Iustin Pop
               " operation:\n%s" % msg)
1252 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpExecError):
1253 e2e521d0 Iustin Pop
    obuf.write("Failure: command execution error:\n%s" % msg)
1254 73702ee7 Iustin Pop
  elif isinstance(err, errors.TagError):
1255 e2e521d0 Iustin Pop
    obuf.write("Failure: invalid tag(s) given:\n%s" % msg)
1256 686d7433 Iustin Pop
  elif isinstance(err, errors.JobQueueDrainError):
1257 686d7433 Iustin Pop
    obuf.write("Failure: the job queue is marked for drain and doesn't"
1258 686d7433 Iustin Pop
               " accept new requests\n")
1259 f87b405e Michael Hanselmann
  elif isinstance(err, errors.JobQueueFull):
1260 f87b405e Michael Hanselmann
    obuf.write("Failure: the job queue is full and doesn't accept new"
1261 f87b405e Michael Hanselmann
               " job submissions until old jobs are archived\n")
1262 a5728081 Guido Trotter
  elif isinstance(err, errors.TypeEnforcementError):
1263 a5728081 Guido Trotter
    obuf.write("Parameter Error: %s" % msg)
1264 c1ce76bb Iustin Pop
  elif isinstance(err, errors.ParameterError):
1265 c1ce76bb Iustin Pop
    obuf.write("Failure: unknown/wrong parameter name '%s'" % msg)
1266 73702ee7 Iustin Pop
  elif isinstance(err, errors.GenericError):
1267 e2e521d0 Iustin Pop
    obuf.write("Unhandled Ganeti error: %s" % msg)
1268 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.NoMasterError):
1269 03a8dbdc Iustin Pop
    obuf.write("Cannot communicate with the master daemon.\nIs it running"
1270 082c5adb Michael Hanselmann
               " and listening for connections?")
1271 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.TimeoutError):
1272 03a8dbdc Iustin Pop
    obuf.write("Timeout while talking to the master daemon. Error:\n"
1273 03a8dbdc Iustin Pop
               "%s" % msg)
1274 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.ProtocolError):
1275 03a8dbdc Iustin Pop
    obuf.write("Unhandled protocol error while talking to the master daemon:\n"
1276 03a8dbdc Iustin Pop
               "%s" % msg)
1277 e9d741b6 Iustin Pop
  elif isinstance(err, JobSubmittedException):
1278 e9d741b6 Iustin Pop
    obuf.write("JobID: %s\n" % err.args[0])
1279 e9d741b6 Iustin Pop
    retcode = 0
1280 73702ee7 Iustin Pop
  else:
1281 e2e521d0 Iustin Pop
    obuf.write("Unhandled exception: %s" % msg)
1282 73702ee7 Iustin Pop
  return retcode, obuf.getvalue().rstrip('\n')
1283 73702ee7 Iustin Pop
1284 73702ee7 Iustin Pop
1285 de47cf8f Guido Trotter
def GenericMain(commands, override=None, aliases=None):
1286 a8083063 Iustin Pop
  """Generic main function for all the gnt-* commands.
1287 a8083063 Iustin Pop

1288 334d1483 Iustin Pop
  Arguments:
1289 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
1290 334d1483 Iustin Pop
                for command line handling.
1291 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
1292 334d1483 Iustin Pop
                override command line options; this can be used to pass
1293 334d1483 Iustin Pop
                options from the scripts to generic functions
1294 de47cf8f Guido Trotter
    - aliases: dictionary with command aliases {'alias': 'target, ...}
1295 a8083063 Iustin Pop

1296 a8083063 Iustin Pop
  """
1297 a8083063 Iustin Pop
  # save the program name and the entire command line for later logging
1298 a8083063 Iustin Pop
  if sys.argv:
1299 a8083063 Iustin Pop
    binary = os.path.basename(sys.argv[0]) or sys.argv[0]
1300 a8083063 Iustin Pop
    if len(sys.argv) >= 2:
1301 a8083063 Iustin Pop
      binary += " " + sys.argv[1]
1302 a8083063 Iustin Pop
      old_cmdline = " ".join(sys.argv[2:])
1303 a8083063 Iustin Pop
    else:
1304 a8083063 Iustin Pop
      old_cmdline = ""
1305 a8083063 Iustin Pop
  else:
1306 a8083063 Iustin Pop
    binary = "<unknown program>"
1307 a8083063 Iustin Pop
    old_cmdline = ""
1308 a8083063 Iustin Pop
1309 de47cf8f Guido Trotter
  if aliases is None:
1310 de47cf8f Guido Trotter
    aliases = {}
1311 de47cf8f Guido Trotter
1312 3126878d Guido Trotter
  try:
1313 3126878d Guido Trotter
    func, options, args = _ParseArgs(sys.argv, commands, aliases)
1314 3126878d Guido Trotter
  except errors.ParameterError, err:
1315 3126878d Guido Trotter
    result, err_msg = FormatError(err)
1316 3126878d Guido Trotter
    ToStderr(err_msg)
1317 3126878d Guido Trotter
    return 1
1318 3126878d Guido Trotter
1319 a8083063 Iustin Pop
  if func is None: # parse error
1320 a8083063 Iustin Pop
    return 1
1321 a8083063 Iustin Pop
1322 334d1483 Iustin Pop
  if override is not None:
1323 334d1483 Iustin Pop
    for key, val in override.iteritems():
1324 334d1483 Iustin Pop
      setattr(options, key, val)
1325 334d1483 Iustin Pop
1326 82d9caef Iustin Pop
  utils.SetupLogging(constants.LOG_COMMANDS, debug=options.debug,
1327 82d9caef Iustin Pop
                     stderr_logging=True, program=binary)
1328 a8083063 Iustin Pop
1329 a8083063 Iustin Pop
  if old_cmdline:
1330 46fbdd04 Iustin Pop
    logging.info("run with arguments '%s'", old_cmdline)
1331 a8083063 Iustin Pop
  else:
1332 46fbdd04 Iustin Pop
    logging.info("run with no arguments")
1333 a8083063 Iustin Pop
1334 a8083063 Iustin Pop
  try:
1335 a4af651e Iustin Pop
    result = func(options, args)
1336 d8353c3a Iustin Pop
  except (errors.GenericError, luxi.ProtocolError,
1337 d8353c3a Iustin Pop
          JobSubmittedException), err:
1338 a4af651e Iustin Pop
    result, err_msg = FormatError(err)
1339 5bbd3f7f Michael Hanselmann
    logging.exception("Error during command processing")
1340 46fbdd04 Iustin Pop
    ToStderr(err_msg)
1341 a8083063 Iustin Pop
1342 a8083063 Iustin Pop
  return result
1343 137161c9 Michael Hanselmann
1344 137161c9 Michael Hanselmann
1345 d77490c5 Iustin Pop
def GenericInstanceCreate(mode, opts, args):
1346 d77490c5 Iustin Pop
  """Add an instance to the cluster via either creation or import.
1347 d77490c5 Iustin Pop

1348 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
1349 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
1350 d77490c5 Iustin Pop
  @type args: list
1351 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
1352 d77490c5 Iustin Pop
  @rtype: int
1353 d77490c5 Iustin Pop
  @return: the desired exit code
1354 d77490c5 Iustin Pop

1355 d77490c5 Iustin Pop
  """
1356 d77490c5 Iustin Pop
  instance = args[0]
1357 d77490c5 Iustin Pop
1358 d77490c5 Iustin Pop
  (pnode, snode) = SplitNodeOption(opts.node)
1359 d77490c5 Iustin Pop
1360 d77490c5 Iustin Pop
  hypervisor = None
1361 d77490c5 Iustin Pop
  hvparams = {}
1362 d77490c5 Iustin Pop
  if opts.hypervisor:
1363 d77490c5 Iustin Pop
    hypervisor, hvparams = opts.hypervisor
1364 d77490c5 Iustin Pop
1365 d77490c5 Iustin Pop
  if opts.nics:
1366 d77490c5 Iustin Pop
    try:
1367 d77490c5 Iustin Pop
      nic_max = max(int(nidx[0])+1 for nidx in opts.nics)
1368 d77490c5 Iustin Pop
    except ValueError, err:
1369 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Invalid NIC index passed: %s" % str(err))
1370 d77490c5 Iustin Pop
    nics = [{}] * nic_max
1371 d77490c5 Iustin Pop
    for nidx, ndict in opts.nics:
1372 d77490c5 Iustin Pop
      nidx = int(nidx)
1373 d77490c5 Iustin Pop
      if not isinstance(ndict, dict):
1374 d77490c5 Iustin Pop
        msg = "Invalid nic/%d value: expected dict, got %s" % (nidx, ndict)
1375 d77490c5 Iustin Pop
        raise errors.OpPrereqError(msg)
1376 d77490c5 Iustin Pop
      nics[nidx] = ndict
1377 d77490c5 Iustin Pop
  elif opts.no_nics:
1378 d77490c5 Iustin Pop
    # no nics
1379 d77490c5 Iustin Pop
    nics = []
1380 d77490c5 Iustin Pop
  else:
1381 d77490c5 Iustin Pop
    # default of one nic, all auto
1382 d77490c5 Iustin Pop
    nics = [{}]
1383 d77490c5 Iustin Pop
1384 d77490c5 Iustin Pop
  if opts.disk_template == constants.DT_DISKLESS:
1385 d77490c5 Iustin Pop
    if opts.disks or opts.sd_size is not None:
1386 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Diskless instance but disk"
1387 d77490c5 Iustin Pop
                                 " information passed")
1388 d77490c5 Iustin Pop
    disks = []
1389 d77490c5 Iustin Pop
  else:
1390 d77490c5 Iustin Pop
    if not opts.disks and not opts.sd_size:
1391 d77490c5 Iustin Pop
      raise errors.OpPrereqError("No disk information specified")
1392 d77490c5 Iustin Pop
    if opts.disks and opts.sd_size is not None:
1393 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Please use either the '--disk' or"
1394 d77490c5 Iustin Pop
                                 " '-s' option")
1395 d77490c5 Iustin Pop
    if opts.sd_size is not None:
1396 d77490c5 Iustin Pop
      opts.disks = [(0, {"size": opts.sd_size})]
1397 d77490c5 Iustin Pop
    try:
1398 d77490c5 Iustin Pop
      disk_max = max(int(didx[0])+1 for didx in opts.disks)
1399 d77490c5 Iustin Pop
    except ValueError, err:
1400 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err))
1401 d77490c5 Iustin Pop
    disks = [{}] * disk_max
1402 d77490c5 Iustin Pop
    for didx, ddict in opts.disks:
1403 d77490c5 Iustin Pop
      didx = int(didx)
1404 d77490c5 Iustin Pop
      if not isinstance(ddict, dict):
1405 d77490c5 Iustin Pop
        msg = "Invalid disk/%d value: expected dict, got %s" % (didx, ddict)
1406 d77490c5 Iustin Pop
        raise errors.OpPrereqError(msg)
1407 d77490c5 Iustin Pop
      elif "size" not in ddict:
1408 d77490c5 Iustin Pop
        raise errors.OpPrereqError("Missing size for disk %d" % didx)
1409 d77490c5 Iustin Pop
      try:
1410 d77490c5 Iustin Pop
        ddict["size"] = utils.ParseUnit(ddict["size"])
1411 d77490c5 Iustin Pop
      except ValueError, err:
1412 d77490c5 Iustin Pop
        raise errors.OpPrereqError("Invalid disk size for disk %d: %s" %
1413 d77490c5 Iustin Pop
                                   (didx, err))
1414 d77490c5 Iustin Pop
      disks[didx] = ddict
1415 d77490c5 Iustin Pop
1416 d77490c5 Iustin Pop
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_TYPES)
1417 d77490c5 Iustin Pop
  utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
1418 d77490c5 Iustin Pop
1419 d77490c5 Iustin Pop
  if mode == constants.INSTANCE_CREATE:
1420 d77490c5 Iustin Pop
    start = opts.start
1421 d77490c5 Iustin Pop
    os_type = opts.os
1422 d77490c5 Iustin Pop
    src_node = None
1423 d77490c5 Iustin Pop
    src_path = None
1424 d77490c5 Iustin Pop
  elif mode == constants.INSTANCE_IMPORT:
1425 d77490c5 Iustin Pop
    start = False
1426 d77490c5 Iustin Pop
    os_type = None
1427 d77490c5 Iustin Pop
    src_node = opts.src_node
1428 d77490c5 Iustin Pop
    src_path = opts.src_dir
1429 d77490c5 Iustin Pop
  else:
1430 d77490c5 Iustin Pop
    raise errors.ProgrammerError("Invalid creation mode %s" % mode)
1431 d77490c5 Iustin Pop
1432 d77490c5 Iustin Pop
  op = opcodes.OpCreateInstance(instance_name=instance,
1433 d77490c5 Iustin Pop
                                disks=disks,
1434 d77490c5 Iustin Pop
                                disk_template=opts.disk_template,
1435 d77490c5 Iustin Pop
                                nics=nics,
1436 d77490c5 Iustin Pop
                                pnode=pnode, snode=snode,
1437 d77490c5 Iustin Pop
                                ip_check=opts.ip_check,
1438 d77490c5 Iustin Pop
                                wait_for_sync=opts.wait_for_sync,
1439 d77490c5 Iustin Pop
                                file_storage_dir=opts.file_storage_dir,
1440 d77490c5 Iustin Pop
                                file_driver=opts.file_driver,
1441 d77490c5 Iustin Pop
                                iallocator=opts.iallocator,
1442 d77490c5 Iustin Pop
                                hypervisor=hypervisor,
1443 d77490c5 Iustin Pop
                                hvparams=hvparams,
1444 d77490c5 Iustin Pop
                                beparams=opts.beparams,
1445 d77490c5 Iustin Pop
                                mode=mode,
1446 d77490c5 Iustin Pop
                                start=start,
1447 d77490c5 Iustin Pop
                                os_type=os_type,
1448 d77490c5 Iustin Pop
                                src_node=src_node,
1449 d77490c5 Iustin Pop
                                src_path=src_path)
1450 d77490c5 Iustin Pop
1451 d77490c5 Iustin Pop
  SubmitOrSend(op, opts)
1452 d77490c5 Iustin Pop
  return 0
1453 d77490c5 Iustin Pop
1454 d77490c5 Iustin Pop
1455 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
1456 9fbfbb7b Iustin Pop
                  numfields=None, unitfields=None,
1457 9fbfbb7b Iustin Pop
                  units=None):
1458 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
1459 137161c9 Michael Hanselmann

1460 9fbfbb7b Iustin Pop
  @type headers: dict
1461 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
1462 9fbfbb7b Iustin Pop
      the table
1463 9fbfbb7b Iustin Pop
  @type fields: list
1464 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
1465 9fbfbb7b Iustin Pop
      the data field
1466 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
1467 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
1468 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
1469 9fbfbb7b Iustin Pop
      each field
1470 9fbfbb7b Iustin Pop
  @type data: list
1471 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
1472 9fbfbb7b Iustin Pop
  @type numfields: list
1473 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
1474 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
1475 9fbfbb7b Iustin Pop
  @type unitfields: list
1476 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
1477 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
1478 9fbfbb7b Iustin Pop
  @type units: string or None
1479 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
1480 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
1481 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
1482 137161c9 Michael Hanselmann

1483 137161c9 Michael Hanselmann
  """
1484 9fbfbb7b Iustin Pop
  if units is None:
1485 9fbfbb7b Iustin Pop
    if separator:
1486 9fbfbb7b Iustin Pop
      units = "m"
1487 9fbfbb7b Iustin Pop
    else:
1488 9fbfbb7b Iustin Pop
      units = "h"
1489 9fbfbb7b Iustin Pop
1490 137161c9 Michael Hanselmann
  if numfields is None:
1491 137161c9 Michael Hanselmann
    numfields = []
1492 137161c9 Michael Hanselmann
  if unitfields is None:
1493 137161c9 Michael Hanselmann
    unitfields = []
1494 137161c9 Michael Hanselmann
1495 00430f8e Iustin Pop
  numfields = utils.FieldSet(*numfields)
1496 00430f8e Iustin Pop
  unitfields = utils.FieldSet(*unitfields)
1497 00430f8e Iustin Pop
1498 137161c9 Michael Hanselmann
  format_fields = []
1499 137161c9 Michael Hanselmann
  for field in fields:
1500 01ca31ae Iustin Pop
    if headers and field not in headers:
1501 ea5a5b74 Guido Trotter
      # TODO: handle better unknown fields (either revert to old
1502 71c1af58 Iustin Pop
      # style of raising exception, or deal more intelligently with
1503 71c1af58 Iustin Pop
      # variable fields)
1504 71c1af58 Iustin Pop
      headers[field] = field
1505 137161c9 Michael Hanselmann
    if separator is not None:
1506 137161c9 Michael Hanselmann
      format_fields.append("%s")
1507 00430f8e Iustin Pop
    elif numfields.Matches(field):
1508 137161c9 Michael Hanselmann
      format_fields.append("%*s")
1509 137161c9 Michael Hanselmann
    else:
1510 137161c9 Michael Hanselmann
      format_fields.append("%-*s")
1511 137161c9 Michael Hanselmann
1512 137161c9 Michael Hanselmann
  if separator is None:
1513 137161c9 Michael Hanselmann
    mlens = [0 for name in fields]
1514 137161c9 Michael Hanselmann
    format = ' '.join(format_fields)
1515 137161c9 Michael Hanselmann
  else:
1516 137161c9 Michael Hanselmann
    format = separator.replace("%", "%%").join(format_fields)
1517 137161c9 Michael Hanselmann
1518 137161c9 Michael Hanselmann
  for row in data:
1519 dcbd6288 Guido Trotter
    if row is None:
1520 dcbd6288 Guido Trotter
      continue
1521 137161c9 Michael Hanselmann
    for idx, val in enumerate(row):
1522 00430f8e Iustin Pop
      if unitfields.Matches(fields[idx]):
1523 137161c9 Michael Hanselmann
        try:
1524 137161c9 Michael Hanselmann
          val = int(val)
1525 137161c9 Michael Hanselmann
        except ValueError:
1526 137161c9 Michael Hanselmann
          pass
1527 137161c9 Michael Hanselmann
        else:
1528 9fbfbb7b Iustin Pop
          val = row[idx] = utils.FormatUnit(val, units)
1529 01ca31ae Iustin Pop
      val = row[idx] = str(val)
1530 137161c9 Michael Hanselmann
      if separator is None:
1531 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(val))
1532 137161c9 Michael Hanselmann
1533 16be8703 Iustin Pop
  result = []
1534 137161c9 Michael Hanselmann
  if headers:
1535 137161c9 Michael Hanselmann
    args = []
1536 137161c9 Michael Hanselmann
    for idx, name in enumerate(fields):
1537 137161c9 Michael Hanselmann
      hdr = headers[name]
1538 137161c9 Michael Hanselmann
      if separator is None:
1539 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(hdr))
1540 137161c9 Michael Hanselmann
        args.append(mlens[idx])
1541 137161c9 Michael Hanselmann
      args.append(hdr)
1542 16be8703 Iustin Pop
    result.append(format % tuple(args))
1543 137161c9 Michael Hanselmann
1544 137161c9 Michael Hanselmann
  for line in data:
1545 137161c9 Michael Hanselmann
    args = []
1546 dcbd6288 Guido Trotter
    if line is None:
1547 dcbd6288 Guido Trotter
      line = ['-' for _ in fields]
1548 f1501b3f Michael Hanselmann
    for idx in range(len(fields)):
1549 137161c9 Michael Hanselmann
      if separator is None:
1550 137161c9 Michael Hanselmann
        args.append(mlens[idx])
1551 137161c9 Michael Hanselmann
      args.append(line[idx])
1552 16be8703 Iustin Pop
    result.append(format % tuple(args))
1553 16be8703 Iustin Pop
1554 16be8703 Iustin Pop
  return result
1555 3386e7a9 Iustin Pop
1556 3386e7a9 Iustin Pop
1557 3386e7a9 Iustin Pop
def FormatTimestamp(ts):
1558 3386e7a9 Iustin Pop
  """Formats a given timestamp.
1559 3386e7a9 Iustin Pop

1560 3386e7a9 Iustin Pop
  @type ts: timestamp
1561 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
1562 3386e7a9 Iustin Pop

1563 3386e7a9 Iustin Pop
  @rtype: string
1564 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
1565 3386e7a9 Iustin Pop

1566 3386e7a9 Iustin Pop
  """
1567 e0ec0ff6 Iustin Pop
  if not isinstance (ts, (tuple, list)) or len(ts) != 2:
1568 e0ec0ff6 Iustin Pop
    return '?'
1569 3386e7a9 Iustin Pop
  sec, usec = ts
1570 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
1571 2241e2b9 Iustin Pop
1572 2241e2b9 Iustin Pop
1573 2241e2b9 Iustin Pop
def ParseTimespec(value):
1574 2241e2b9 Iustin Pop
  """Parse a time specification.
1575 2241e2b9 Iustin Pop

1576 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
1577 2241e2b9 Iustin Pop

1578 2241e2b9 Iustin Pop
    - s: seconds
1579 2241e2b9 Iustin Pop
    - m: minutes
1580 2241e2b9 Iustin Pop
    - h: hours
1581 2241e2b9 Iustin Pop
    - d: day
1582 2241e2b9 Iustin Pop
    - w: weeks
1583 2241e2b9 Iustin Pop

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

1586 2241e2b9 Iustin Pop
  """
1587 2241e2b9 Iustin Pop
  value = str(value)
1588 2241e2b9 Iustin Pop
  if not value:
1589 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
1590 2241e2b9 Iustin Pop
  suffix_map = {
1591 2241e2b9 Iustin Pop
    's': 1,
1592 2241e2b9 Iustin Pop
    'm': 60,
1593 2241e2b9 Iustin Pop
    'h': 3600,
1594 2241e2b9 Iustin Pop
    'd': 86400,
1595 2241e2b9 Iustin Pop
    'w': 604800,
1596 2241e2b9 Iustin Pop
    }
1597 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
1598 2241e2b9 Iustin Pop
    try:
1599 2241e2b9 Iustin Pop
      value = int(value)
1600 2241e2b9 Iustin Pop
    except ValueError:
1601 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
1602 2241e2b9 Iustin Pop
  else:
1603 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
1604 2241e2b9 Iustin Pop
    value = value[:-1]
1605 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
1606 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
1607 2241e2b9 Iustin Pop
                                 " suffix passed)")
1608 2241e2b9 Iustin Pop
    try:
1609 2241e2b9 Iustin Pop
      value = int(value) * multiplier
1610 2241e2b9 Iustin Pop
    except ValueError:
1611 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
1612 2241e2b9 Iustin Pop
  return value
1613 46fbdd04 Iustin Pop
1614 46fbdd04 Iustin Pop
1615 4040a784 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False):
1616 4040a784 Iustin Pop
  """Returns the names of online nodes.
1617 4040a784 Iustin Pop

1618 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
1619 4040a784 Iustin Pop
  the online nodes.
1620 4040a784 Iustin Pop

1621 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
1622 4040a784 Iustin Pop
      offline ones)
1623 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
1624 4040a784 Iustin Pop
  @type nowarn: boolean
1625 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
1626 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
1627 4040a784 Iustin Pop
      note is not displayed
1628 4040a784 Iustin Pop

1629 4040a784 Iustin Pop
  """
1630 4040a784 Iustin Pop
  if cl is None:
1631 4040a784 Iustin Pop
    cl = GetClient()
1632 4040a784 Iustin Pop
1633 2e7b8369 Iustin Pop
  result = cl.QueryNodes(names=nodes, fields=["name", "offline"],
1634 2e7b8369 Iustin Pop
                         use_locking=False)
1635 4040a784 Iustin Pop
  offline = [row[0] for row in result if row[1]]
1636 4040a784 Iustin Pop
  if offline and not nowarn:
1637 4040a784 Iustin Pop
    ToStderr("Note: skipping offline node(s): %s" % ", ".join(offline))
1638 4040a784 Iustin Pop
  return [row[0] for row in result if not row[1]]
1639 4040a784 Iustin Pop
1640 4040a784 Iustin Pop
1641 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
1642 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
1643 46fbdd04 Iustin Pop

1644 46fbdd04 Iustin Pop
  @type stream: file object
1645 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
1646 46fbdd04 Iustin Pop
  @type txt: str
1647 46fbdd04 Iustin Pop
  @param txt: the message
1648 46fbdd04 Iustin Pop

1649 46fbdd04 Iustin Pop
  """
1650 46fbdd04 Iustin Pop
  if args:
1651 46fbdd04 Iustin Pop
    args = tuple(args)
1652 46fbdd04 Iustin Pop
    stream.write(txt % args)
1653 46fbdd04 Iustin Pop
  else:
1654 46fbdd04 Iustin Pop
    stream.write(txt)
1655 46fbdd04 Iustin Pop
  stream.write('\n')
1656 46fbdd04 Iustin Pop
  stream.flush()
1657 46fbdd04 Iustin Pop
1658 46fbdd04 Iustin Pop
1659 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
1660 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
1661 46fbdd04 Iustin Pop

1662 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
1663 46fbdd04 Iustin Pop

1664 46fbdd04 Iustin Pop
  @type txt: str
1665 46fbdd04 Iustin Pop
  @param txt: the message
1666 46fbdd04 Iustin Pop

1667 46fbdd04 Iustin Pop
  """
1668 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
1669 46fbdd04 Iustin Pop
1670 46fbdd04 Iustin Pop
1671 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
1672 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
1673 46fbdd04 Iustin Pop

1674 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
1675 46fbdd04 Iustin Pop

1676 46fbdd04 Iustin Pop
  @type txt: str
1677 46fbdd04 Iustin Pop
  @param txt: the message
1678 46fbdd04 Iustin Pop

1679 46fbdd04 Iustin Pop
  """
1680 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
1681 479636a3 Iustin Pop
1682 479636a3 Iustin Pop
1683 479636a3 Iustin Pop
class JobExecutor(object):
1684 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
1685 479636a3 Iustin Pop

1686 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
1687 479636a3 Iustin Pop
  GetResults() calls.
1688 479636a3 Iustin Pop

1689 479636a3 Iustin Pop
  """
1690 479636a3 Iustin Pop
  def __init__(self, cl=None, verbose=True):
1691 479636a3 Iustin Pop
    self.queue = []
1692 479636a3 Iustin Pop
    if cl is None:
1693 479636a3 Iustin Pop
      cl = GetClient()
1694 479636a3 Iustin Pop
    self.cl = cl
1695 479636a3 Iustin Pop
    self.verbose = verbose
1696 23b4b983 Iustin Pop
    self.jobs = []
1697 479636a3 Iustin Pop
1698 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
1699 23b4b983 Iustin Pop
    """Record a job for later submit.
1700 479636a3 Iustin Pop

1701 479636a3 Iustin Pop
    @type name: string
1702 479636a3 Iustin Pop
    @param name: a description of the job, will be used in WaitJobSet
1703 479636a3 Iustin Pop
    """
1704 23b4b983 Iustin Pop
    self.queue.append((name, ops))
1705 23b4b983 Iustin Pop
1706 23b4b983 Iustin Pop
  def SubmitPending(self):
1707 23b4b983 Iustin Pop
    """Submit all pending jobs.
1708 23b4b983 Iustin Pop

1709 23b4b983 Iustin Pop
    """
1710 23b4b983 Iustin Pop
    results = self.cl.SubmitManyJobs([row[1] for row in self.queue])
1711 23b4b983 Iustin Pop
    for ((status, data), (name, _)) in zip(results, self.queue):
1712 23b4b983 Iustin Pop
      self.jobs.append((status, data, name))
1713 479636a3 Iustin Pop
1714 479636a3 Iustin Pop
  def GetResults(self):
1715 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
1716 479636a3 Iustin Pop

1717 479636a3 Iustin Pop
    @rtype: list
1718 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
1719 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
1720 479636a3 Iustin Pop
        there will be the error message
1721 479636a3 Iustin Pop

1722 479636a3 Iustin Pop
    """
1723 23b4b983 Iustin Pop
    if not self.jobs:
1724 23b4b983 Iustin Pop
      self.SubmitPending()
1725 479636a3 Iustin Pop
    results = []
1726 479636a3 Iustin Pop
    if self.verbose:
1727 23b4b983 Iustin Pop
      ok_jobs = [row[1] for row in self.jobs if row[0]]
1728 23b4b983 Iustin Pop
      if ok_jobs:
1729 23b4b983 Iustin Pop
        ToStdout("Submitted jobs %s", ", ".join(ok_jobs))
1730 23b4b983 Iustin Pop
    for submit_status, jid, name in self.jobs:
1731 23b4b983 Iustin Pop
      if not submit_status:
1732 23b4b983 Iustin Pop
        ToStderr("Failed to submit job for %s: %s", name, jid)
1733 23b4b983 Iustin Pop
        results.append((False, jid))
1734 23b4b983 Iustin Pop
        continue
1735 479636a3 Iustin Pop
      if self.verbose:
1736 479636a3 Iustin Pop
        ToStdout("Waiting for job %s for %s...", jid, name)
1737 479636a3 Iustin Pop
      try:
1738 479636a3 Iustin Pop
        job_result = PollJob(jid, cl=self.cl)
1739 479636a3 Iustin Pop
        success = True
1740 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
1741 479636a3 Iustin Pop
        _, job_result = FormatError(err)
1742 479636a3 Iustin Pop
        success = False
1743 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
1744 479636a3 Iustin Pop
        ToStderr("Job %s for %s has failed: %s", jid, name, job_result)
1745 479636a3 Iustin Pop
1746 479636a3 Iustin Pop
      results.append((success, job_result))
1747 479636a3 Iustin Pop
    return results
1748 479636a3 Iustin Pop
1749 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
1750 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
1751 479636a3 Iustin Pop

1752 479636a3 Iustin Pop
    @type wait: boolean
1753 479636a3 Iustin Pop
    @param wait: whether to wait or not
1754 479636a3 Iustin Pop

1755 479636a3 Iustin Pop
    """
1756 479636a3 Iustin Pop
    if wait:
1757 479636a3 Iustin Pop
      return self.GetResults()
1758 479636a3 Iustin Pop
    else:
1759 23b4b983 Iustin Pop
      if not self.jobs:
1760 23b4b983 Iustin Pop
        self.SubmitPending()
1761 23b4b983 Iustin Pop
      for status, result, name in self.jobs:
1762 23b4b983 Iustin Pop
        if status:
1763 23b4b983 Iustin Pop
          ToStdout("%s: %s", result, name)
1764 23b4b983 Iustin Pop
        else:
1765 23b4b983 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)