Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ 6d79896b

History | View | Annotate | Download (55.5 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 4abc4f1e Iustin Pop
  ]
162 846baef9 Iustin Pop
163 8b46606c Guido Trotter
NO_PREFIX = "no_"
164 8b46606c Guido Trotter
UN_PREFIX = "-"
165 846baef9 Iustin Pop
166 03298ebe Michael Hanselmann
167 863d7f46 Michael Hanselmann
class _Argument:
168 dff85078 Michael Hanselmann
  def __init__(self, min=0, max=None):
169 863d7f46 Michael Hanselmann
    self.min = min
170 863d7f46 Michael Hanselmann
    self.max = max
171 863d7f46 Michael Hanselmann
172 863d7f46 Michael Hanselmann
  def __repr__(self):
173 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s>" %
174 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max))
175 863d7f46 Michael Hanselmann
176 863d7f46 Michael Hanselmann
177 863d7f46 Michael Hanselmann
class ArgSuggest(_Argument):
178 863d7f46 Michael Hanselmann
  """Suggesting argument.
179 863d7f46 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

278 810c50b7 Iustin Pop
  """
279 810c50b7 Iustin Pop
  fname = opts.tags_source
280 810c50b7 Iustin Pop
  if fname is None:
281 810c50b7 Iustin Pop
    return
282 810c50b7 Iustin Pop
  if fname == "-":
283 810c50b7 Iustin Pop
    new_fh = sys.stdin
284 810c50b7 Iustin Pop
  else:
285 810c50b7 Iustin Pop
    new_fh = open(fname, "r")
286 810c50b7 Iustin Pop
  new_data = []
287 810c50b7 Iustin Pop
  try:
288 810c50b7 Iustin Pop
    # we don't use the nice 'new_data = [line.strip() for line in fh]'
289 810c50b7 Iustin Pop
    # because of python bug 1633941
290 810c50b7 Iustin Pop
    while True:
291 810c50b7 Iustin Pop
      line = new_fh.readline()
292 810c50b7 Iustin Pop
      if not line:
293 810c50b7 Iustin Pop
        break
294 810c50b7 Iustin Pop
      new_data.append(line.strip())
295 810c50b7 Iustin Pop
  finally:
296 810c50b7 Iustin Pop
    new_fh.close()
297 810c50b7 Iustin Pop
  args.extend(new_data)
298 810c50b7 Iustin Pop
299 810c50b7 Iustin Pop
300 846baef9 Iustin Pop
def ListTags(opts, args):
301 846baef9 Iustin Pop
  """List the tags on a given object.
302 846baef9 Iustin Pop

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

308 846baef9 Iustin Pop
  """
309 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
310 846baef9 Iustin Pop
  op = opcodes.OpGetTags(kind=kind, name=name)
311 846baef9 Iustin Pop
  result = SubmitOpCode(op)
312 846baef9 Iustin Pop
  result = list(result)
313 846baef9 Iustin Pop
  result.sort()
314 846baef9 Iustin Pop
  for tag in result:
315 03298ebe Michael Hanselmann
    ToStdout(tag)
316 846baef9 Iustin Pop
317 846baef9 Iustin Pop
318 846baef9 Iustin Pop
def AddTags(opts, args):
319 846baef9 Iustin Pop
  """Add tags on a given object.
320 846baef9 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

896 a8005e17 Michael Hanselmann
  Algorithm:
897 a8005e17 Michael Hanselmann

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

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

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

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

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

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

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

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

967 60d49723 Michael Hanselmann
  """
968 60d49723 Michael Hanselmann
  if value and ':' in value:
969 60d49723 Michael Hanselmann
    return value.split(':', 1)
970 60d49723 Michael Hanselmann
  else:
971 60d49723 Michael Hanselmann
    return (value, None)
972 60d49723 Michael Hanselmann
973 60d49723 Michael Hanselmann
974 4331f6cd Michael Hanselmann
def UsesRPC(fn):
975 4331f6cd Michael Hanselmann
  def wrapper(*args, **kwargs):
976 4331f6cd Michael Hanselmann
    rpc.Init()
977 4331f6cd Michael Hanselmann
    try:
978 4331f6cd Michael Hanselmann
      return fn(*args, **kwargs)
979 4331f6cd Michael Hanselmann
    finally:
980 4331f6cd Michael Hanselmann
      rpc.Shutdown()
981 4331f6cd Michael Hanselmann
  return wrapper
982 4331f6cd Michael Hanselmann
983 4331f6cd Michael Hanselmann
984 47988778 Iustin Pop
def AskUser(text, choices=None):
985 47988778 Iustin Pop
  """Ask the user a question.
986 a8083063 Iustin Pop

987 c41eea6e Iustin Pop
  @param text: the question to ask
988 a8083063 Iustin Pop

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

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

998 a8083063 Iustin Pop
  """
999 47988778 Iustin Pop
  if choices is None:
1000 47988778 Iustin Pop
    choices = [('y', True, 'Perform the operation'),
1001 47988778 Iustin Pop
               ('n', False, 'Do not perform the operation')]
1002 47988778 Iustin Pop
  if not choices or not isinstance(choices, list):
1003 5bbd3f7f Michael Hanselmann
    raise errors.ProgrammerError("Invalid choices argument to AskUser")
1004 47988778 Iustin Pop
  for entry in choices:
1005 47988778 Iustin Pop
    if not isinstance(entry, tuple) or len(entry) < 3 or entry[0] == '?':
1006 5bbd3f7f Michael Hanselmann
      raise errors.ProgrammerError("Invalid choices element to AskUser")
1007 47988778 Iustin Pop
1008 47988778 Iustin Pop
  answer = choices[-1][1]
1009 47988778 Iustin Pop
  new_text = []
1010 47988778 Iustin Pop
  for line in text.splitlines():
1011 47988778 Iustin Pop
    new_text.append(textwrap.fill(line, 70, replace_whitespace=False))
1012 47988778 Iustin Pop
  text = "\n".join(new_text)
1013 a8083063 Iustin Pop
  try:
1014 3023170f Iustin Pop
    f = file("/dev/tty", "a+")
1015 a8083063 Iustin Pop
  except IOError:
1016 47988778 Iustin Pop
    return answer
1017 a8083063 Iustin Pop
  try:
1018 47988778 Iustin Pop
    chars = [entry[0] for entry in choices]
1019 47988778 Iustin Pop
    chars[-1] = "[%s]" % chars[-1]
1020 47988778 Iustin Pop
    chars.append('?')
1021 47988778 Iustin Pop
    maps = dict([(entry[0], entry[1]) for entry in choices])
1022 47988778 Iustin Pop
    while True:
1023 47988778 Iustin Pop
      f.write(text)
1024 47988778 Iustin Pop
      f.write('\n')
1025 47988778 Iustin Pop
      f.write("/".join(chars))
1026 47988778 Iustin Pop
      f.write(": ")
1027 47988778 Iustin Pop
      line = f.readline(2).strip().lower()
1028 47988778 Iustin Pop
      if line in maps:
1029 47988778 Iustin Pop
        answer = maps[line]
1030 47988778 Iustin Pop
        break
1031 47988778 Iustin Pop
      elif line == '?':
1032 47988778 Iustin Pop
        for entry in choices:
1033 47988778 Iustin Pop
          f.write(" %s - %s\n" % (entry[0], entry[2]))
1034 47988778 Iustin Pop
        f.write("\n")
1035 47988778 Iustin Pop
        continue
1036 a8083063 Iustin Pop
  finally:
1037 a8083063 Iustin Pop
    f.close()
1038 a8083063 Iustin Pop
  return answer
1039 a8083063 Iustin Pop
1040 a8083063 Iustin Pop
1041 e9d741b6 Iustin Pop
class JobSubmittedException(Exception):
1042 e9d741b6 Iustin Pop
  """Job was submitted, client should exit.
1043 e9d741b6 Iustin Pop

1044 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1045 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1046 e9d741b6 Iustin Pop

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

1049 e9d741b6 Iustin Pop
  """
1050 e9d741b6 Iustin Pop
1051 e9d741b6 Iustin Pop
1052 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1053 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1054 a8083063 Iustin Pop

1055 0a1e74d9 Iustin Pop
  @type ops: list
1056 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1057 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1058 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1059 0a1e74d9 Iustin Pop
             if None, a new client will be created
1060 a8083063 Iustin Pop

1061 a8083063 Iustin Pop
  """
1062 e2212007 Iustin Pop
  if cl is None:
1063 b33e986b Iustin Pop
    cl = GetClient()
1064 685ee993 Iustin Pop
1065 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1066 0a1e74d9 Iustin Pop
1067 0a1e74d9 Iustin Pop
  return job_id
1068 0a1e74d9 Iustin Pop
1069 0a1e74d9 Iustin Pop
1070 281606c1 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None):
1071 0a1e74d9 Iustin Pop
  """Function to poll for the result of a job.
1072 0a1e74d9 Iustin Pop

1073 0a1e74d9 Iustin Pop
  @type job_id: job identified
1074 0a1e74d9 Iustin Pop
  @param job_id: the job to poll for results
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 0a1e74d9 Iustin Pop

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

1145 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1146 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1147 0a1e74d9 Iustin Pop
  interaction functions.
1148 0a1e74d9 Iustin Pop

1149 0a1e74d9 Iustin Pop
  """
1150 0a1e74d9 Iustin Pop
  if cl is None:
1151 0a1e74d9 Iustin Pop
    cl = GetClient()
1152 0a1e74d9 Iustin Pop
1153 0a1e74d9 Iustin Pop
  job_id = SendJob([op], cl)
1154 0a1e74d9 Iustin Pop
1155 53c04d04 Iustin Pop
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn)
1156 53c04d04 Iustin Pop
1157 53c04d04 Iustin Pop
  return op_results[0]
1158 0a1e74d9 Iustin Pop
1159 0a1e74d9 Iustin Pop
1160 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1161 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1162 94428652 Iustin Pop

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

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

1170 94428652 Iustin Pop
  """
1171 64c65a2a Iustin Pop
  if opts and opts.dry_run:
1172 64c65a2a Iustin Pop
    op.dry_run = opts.dry_run
1173 94428652 Iustin Pop
  if opts and opts.submit_only:
1174 e9d741b6 Iustin Pop
    job_id = SendJob([op], cl=cl)
1175 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
1176 94428652 Iustin Pop
  else:
1177 94428652 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn)
1178 94428652 Iustin Pop
1179 94428652 Iustin Pop
1180 af30b2fd Michael Hanselmann
def GetClient():
1181 af30b2fd Michael Hanselmann
  # TODO: Cache object?
1182 b33e986b Iustin Pop
  try:
1183 b33e986b Iustin Pop
    client = luxi.Client()
1184 b33e986b Iustin Pop
  except luxi.NoMasterError:
1185 b33e986b Iustin Pop
    master, myself = ssconf.GetMasterAndMyself()
1186 b33e986b Iustin Pop
    if master != myself:
1187 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
1188 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
1189 b33e986b Iustin Pop
                                 master)
1190 b33e986b Iustin Pop
    else:
1191 b33e986b Iustin Pop
      raise
1192 b33e986b Iustin Pop
  return client
1193 af30b2fd Michael Hanselmann
1194 af30b2fd Michael Hanselmann
1195 73702ee7 Iustin Pop
def FormatError(err):
1196 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
1197 73702ee7 Iustin Pop

1198 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
1199 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
1200 73702ee7 Iustin Pop
  second, a string describing the error message (not
1201 73702ee7 Iustin Pop
  newline-terminated).
1202 73702ee7 Iustin Pop

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

1270 334d1483 Iustin Pop
  Arguments:
1271 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
1272 334d1483 Iustin Pop
                for command line handling.
1273 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
1274 334d1483 Iustin Pop
                override command line options; this can be used to pass
1275 334d1483 Iustin Pop
                options from the scripts to generic functions
1276 de47cf8f Guido Trotter
    - aliases: dictionary with command aliases {'alias': 'target, ...}
1277 a8083063 Iustin Pop

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

1330 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
1331 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
1332 d77490c5 Iustin Pop
  @type args: list
1333 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
1334 d77490c5 Iustin Pop
  @rtype: int
1335 d77490c5 Iustin Pop
  @return: the desired exit code
1336 d77490c5 Iustin Pop

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

1442 9fbfbb7b Iustin Pop
  @type headers: dict
1443 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
1444 9fbfbb7b Iustin Pop
      the table
1445 9fbfbb7b Iustin Pop
  @type fields: list
1446 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
1447 9fbfbb7b Iustin Pop
      the data field
1448 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
1449 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
1450 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
1451 9fbfbb7b Iustin Pop
      each field
1452 9fbfbb7b Iustin Pop
  @type data: list
1453 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
1454 9fbfbb7b Iustin Pop
  @type numfields: list
1455 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
1456 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
1457 9fbfbb7b Iustin Pop
  @type unitfields: list
1458 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
1459 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
1460 9fbfbb7b Iustin Pop
  @type units: string or None
1461 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
1462 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
1463 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
1464 137161c9 Michael Hanselmann

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

1542 3386e7a9 Iustin Pop
  @type ts: timestamp
1543 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
1544 3386e7a9 Iustin Pop

1545 3386e7a9 Iustin Pop
  @rtype: string
1546 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
1547 3386e7a9 Iustin Pop

1548 3386e7a9 Iustin Pop
  """
1549 e0ec0ff6 Iustin Pop
  if not isinstance (ts, (tuple, list)) or len(ts) != 2:
1550 e0ec0ff6 Iustin Pop
    return '?'
1551 3386e7a9 Iustin Pop
  sec, usec = ts
1552 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
1553 2241e2b9 Iustin Pop
1554 2241e2b9 Iustin Pop
1555 2241e2b9 Iustin Pop
def ParseTimespec(value):
1556 2241e2b9 Iustin Pop
  """Parse a time specification.
1557 2241e2b9 Iustin Pop

1558 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
1559 2241e2b9 Iustin Pop

1560 2241e2b9 Iustin Pop
    - s: seconds
1561 2241e2b9 Iustin Pop
    - m: minutes
1562 2241e2b9 Iustin Pop
    - h: hours
1563 2241e2b9 Iustin Pop
    - d: day
1564 2241e2b9 Iustin Pop
    - w: weeks
1565 2241e2b9 Iustin Pop

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

1568 2241e2b9 Iustin Pop
  """
1569 2241e2b9 Iustin Pop
  value = str(value)
1570 2241e2b9 Iustin Pop
  if not value:
1571 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
1572 2241e2b9 Iustin Pop
  suffix_map = {
1573 2241e2b9 Iustin Pop
    's': 1,
1574 2241e2b9 Iustin Pop
    'm': 60,
1575 2241e2b9 Iustin Pop
    'h': 3600,
1576 2241e2b9 Iustin Pop
    'd': 86400,
1577 2241e2b9 Iustin Pop
    'w': 604800,
1578 2241e2b9 Iustin Pop
    }
1579 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
1580 2241e2b9 Iustin Pop
    try:
1581 2241e2b9 Iustin Pop
      value = int(value)
1582 2241e2b9 Iustin Pop
    except ValueError:
1583 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
1584 2241e2b9 Iustin Pop
  else:
1585 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
1586 2241e2b9 Iustin Pop
    value = value[:-1]
1587 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
1588 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
1589 2241e2b9 Iustin Pop
                                 " suffix passed)")
1590 2241e2b9 Iustin Pop
    try:
1591 2241e2b9 Iustin Pop
      value = int(value) * multiplier
1592 2241e2b9 Iustin Pop
    except ValueError:
1593 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
1594 2241e2b9 Iustin Pop
  return value
1595 46fbdd04 Iustin Pop
1596 46fbdd04 Iustin Pop
1597 4040a784 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False):
1598 4040a784 Iustin Pop
  """Returns the names of online nodes.
1599 4040a784 Iustin Pop

1600 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
1601 4040a784 Iustin Pop
  the online nodes.
1602 4040a784 Iustin Pop

1603 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
1604 4040a784 Iustin Pop
      offline ones)
1605 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
1606 4040a784 Iustin Pop
  @type nowarn: boolean
1607 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
1608 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
1609 4040a784 Iustin Pop
      note is not displayed
1610 4040a784 Iustin Pop

1611 4040a784 Iustin Pop
  """
1612 4040a784 Iustin Pop
  if cl is None:
1613 4040a784 Iustin Pop
    cl = GetClient()
1614 4040a784 Iustin Pop
1615 2e7b8369 Iustin Pop
  result = cl.QueryNodes(names=nodes, fields=["name", "offline"],
1616 2e7b8369 Iustin Pop
                         use_locking=False)
1617 4040a784 Iustin Pop
  offline = [row[0] for row in result if row[1]]
1618 4040a784 Iustin Pop
  if offline and not nowarn:
1619 4040a784 Iustin Pop
    ToStderr("Note: skipping offline node(s): %s" % ", ".join(offline))
1620 4040a784 Iustin Pop
  return [row[0] for row in result if not row[1]]
1621 4040a784 Iustin Pop
1622 4040a784 Iustin Pop
1623 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
1624 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
1625 46fbdd04 Iustin Pop

1626 46fbdd04 Iustin Pop
  @type stream: file object
1627 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
1628 46fbdd04 Iustin Pop
  @type txt: str
1629 46fbdd04 Iustin Pop
  @param txt: the message
1630 46fbdd04 Iustin Pop

1631 46fbdd04 Iustin Pop
  """
1632 46fbdd04 Iustin Pop
  if args:
1633 46fbdd04 Iustin Pop
    args = tuple(args)
1634 46fbdd04 Iustin Pop
    stream.write(txt % args)
1635 46fbdd04 Iustin Pop
  else:
1636 46fbdd04 Iustin Pop
    stream.write(txt)
1637 46fbdd04 Iustin Pop
  stream.write('\n')
1638 46fbdd04 Iustin Pop
  stream.flush()
1639 46fbdd04 Iustin Pop
1640 46fbdd04 Iustin Pop
1641 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
1642 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
1643 46fbdd04 Iustin Pop

1644 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
1645 46fbdd04 Iustin Pop

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
  _ToStream(sys.stdout, txt, *args)
1651 46fbdd04 Iustin Pop
1652 46fbdd04 Iustin Pop
1653 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
1654 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
1655 46fbdd04 Iustin Pop

1656 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
1657 46fbdd04 Iustin Pop

1658 46fbdd04 Iustin Pop
  @type txt: str
1659 46fbdd04 Iustin Pop
  @param txt: the message
1660 46fbdd04 Iustin Pop

1661 46fbdd04 Iustin Pop
  """
1662 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
1663 479636a3 Iustin Pop
1664 479636a3 Iustin Pop
1665 479636a3 Iustin Pop
class JobExecutor(object):
1666 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
1667 479636a3 Iustin Pop

1668 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
1669 479636a3 Iustin Pop
  GetResults() calls.
1670 479636a3 Iustin Pop

1671 479636a3 Iustin Pop
  """
1672 479636a3 Iustin Pop
  def __init__(self, cl=None, verbose=True):
1673 479636a3 Iustin Pop
    self.queue = []
1674 479636a3 Iustin Pop
    if cl is None:
1675 479636a3 Iustin Pop
      cl = GetClient()
1676 479636a3 Iustin Pop
    self.cl = cl
1677 479636a3 Iustin Pop
    self.verbose = verbose
1678 23b4b983 Iustin Pop
    self.jobs = []
1679 479636a3 Iustin Pop
1680 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
1681 23b4b983 Iustin Pop
    """Record a job for later submit.
1682 479636a3 Iustin Pop

1683 479636a3 Iustin Pop
    @type name: string
1684 479636a3 Iustin Pop
    @param name: a description of the job, will be used in WaitJobSet
1685 479636a3 Iustin Pop
    """
1686 23b4b983 Iustin Pop
    self.queue.append((name, ops))
1687 23b4b983 Iustin Pop
1688 23b4b983 Iustin Pop
  def SubmitPending(self):
1689 23b4b983 Iustin Pop
    """Submit all pending jobs.
1690 23b4b983 Iustin Pop

1691 23b4b983 Iustin Pop
    """
1692 23b4b983 Iustin Pop
    results = self.cl.SubmitManyJobs([row[1] for row in self.queue])
1693 23b4b983 Iustin Pop
    for ((status, data), (name, _)) in zip(results, self.queue):
1694 23b4b983 Iustin Pop
      self.jobs.append((status, data, name))
1695 479636a3 Iustin Pop
1696 479636a3 Iustin Pop
  def GetResults(self):
1697 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
1698 479636a3 Iustin Pop

1699 479636a3 Iustin Pop
    @rtype: list
1700 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
1701 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
1702 479636a3 Iustin Pop
        there will be the error message
1703 479636a3 Iustin Pop

1704 479636a3 Iustin Pop
    """
1705 23b4b983 Iustin Pop
    if not self.jobs:
1706 23b4b983 Iustin Pop
      self.SubmitPending()
1707 479636a3 Iustin Pop
    results = []
1708 479636a3 Iustin Pop
    if self.verbose:
1709 23b4b983 Iustin Pop
      ok_jobs = [row[1] for row in self.jobs if row[0]]
1710 23b4b983 Iustin Pop
      if ok_jobs:
1711 23b4b983 Iustin Pop
        ToStdout("Submitted jobs %s", ", ".join(ok_jobs))
1712 23b4b983 Iustin Pop
    for submit_status, jid, name in self.jobs:
1713 23b4b983 Iustin Pop
      if not submit_status:
1714 23b4b983 Iustin Pop
        ToStderr("Failed to submit job for %s: %s", name, jid)
1715 23b4b983 Iustin Pop
        results.append((False, jid))
1716 23b4b983 Iustin Pop
        continue
1717 479636a3 Iustin Pop
      if self.verbose:
1718 479636a3 Iustin Pop
        ToStdout("Waiting for job %s for %s...", jid, name)
1719 479636a3 Iustin Pop
      try:
1720 479636a3 Iustin Pop
        job_result = PollJob(jid, cl=self.cl)
1721 479636a3 Iustin Pop
        success = True
1722 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
1723 479636a3 Iustin Pop
        _, job_result = FormatError(err)
1724 479636a3 Iustin Pop
        success = False
1725 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
1726 479636a3 Iustin Pop
        ToStderr("Job %s for %s has failed: %s", jid, name, job_result)
1727 479636a3 Iustin Pop
1728 479636a3 Iustin Pop
      results.append((success, job_result))
1729 479636a3 Iustin Pop
    return results
1730 479636a3 Iustin Pop
1731 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
1732 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
1733 479636a3 Iustin Pop

1734 479636a3 Iustin Pop
    @type wait: boolean
1735 479636a3 Iustin Pop
    @param wait: whether to wait or not
1736 479636a3 Iustin Pop

1737 479636a3 Iustin Pop
    """
1738 479636a3 Iustin Pop
    if wait:
1739 479636a3 Iustin Pop
      return self.GetResults()
1740 479636a3 Iustin Pop
    else:
1741 23b4b983 Iustin Pop
      if not self.jobs:
1742 23b4b983 Iustin Pop
        self.SubmitPending()
1743 23b4b983 Iustin Pop
      for status, result, name in self.jobs:
1744 23b4b983 Iustin Pop
        if status:
1745 23b4b983 Iustin Pop
          ToStdout("%s: %s", result, name)
1746 23b4b983 Iustin Pop
        else:
1747 23b4b983 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)