Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ b43dcc5a

History | View | Annotate | Download (78.5 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 783a6c0b Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010 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 685ee993 Iustin Pop
import time
29 46fbdd04 Iustin Pop
import logging
30 73702ee7 Iustin Pop
from cStringIO import StringIO
31 a8083063 Iustin Pop
32 a8083063 Iustin Pop
from ganeti import utils
33 a8083063 Iustin Pop
from ganeti import errors
34 a8083063 Iustin Pop
from ganeti import constants
35 846baef9 Iustin Pop
from ganeti import opcodes
36 ceab32dd Iustin Pop
from ganeti import luxi
37 b33e986b Iustin Pop
from ganeti import ssconf
38 4331f6cd Michael Hanselmann
from ganeti import rpc
39 7e49b6ce Michael Hanselmann
from ganeti import ssh
40 cea881e5 Michael Hanselmann
from ganeti import compat
41 a744b676 Manuel Franceschini
from ganeti import netutils
42 a8083063 Iustin Pop
43 c38c44ad Michael Hanselmann
from optparse import (OptionParser, TitledHelpFormatter,
44 38206f3c Iustin Pop
                      Option, OptionValueError)
45 a8083063 Iustin Pop
46 03298ebe Michael Hanselmann
47 4abc4f1e Iustin Pop
__all__ = [
48 4abc4f1e Iustin Pop
  # Command line options
49 fdad8c4d Balazs Lecz
  "ADD_UIDS_OPT",
50 e7e09483 Iustin Pop
  "ALLOCATABLE_OPT",
51 2d5e7ae1 Iustin Pop
  "ALL_OPT",
52 4c61d894 Iustin Pop
  "AUTO_PROMOTE_OPT",
53 e00f7a05 Iustin Pop
  "AUTO_REPLACE_OPT",
54 087ed2ed Iustin Pop
  "BACKEND_OPT",
55 baef337d Iustin Pop
  "CLEANUP_OPT",
56 3db3eb2a Michael Hanselmann
  "CLUSTER_DOMAIN_SECRET_OPT",
57 4abc4f1e Iustin Pop
  "CONFIRM_OPT",
58 e32df528 Iustin Pop
  "CP_SIZE_OPT",
59 4abc4f1e Iustin Pop
  "DEBUG_OPT",
60 a0c9776a Iustin Pop
  "DEBUG_SIMERR_OPT",
61 4b038a1e Iustin Pop
  "DISKIDX_OPT",
62 e3876ccb Iustin Pop
  "DISK_OPT",
63 4b038a1e Iustin Pop
  "DISK_TEMPLATE_OPT",
64 771734c9 Iustin Pop
  "DRAINED_OPT",
65 26591bfd Luca Bigliardi
  "DRBD_HELPER_OPT",
66 7ea7bcf6 Iustin Pop
  "EARLY_RELEASE_OPT",
67 383a3591 Iustin Pop
  "ENABLED_HV_OPT",
68 14e9e7f3 Iustin Pop
  "ERROR_CODES_OPT",
69 4abc4f1e Iustin Pop
  "FIELDS_OPT",
70 4a25828c Iustin Pop
  "FILESTORE_DIR_OPT",
71 0f87c43e Iustin Pop
  "FILESTORE_DRIVER_OPT",
72 06073e85 Guido Trotter
  "FORCE_OPT",
73 06073e85 Guido Trotter
  "FORCE_VARIANT_OPT",
74 29392516 Iustin Pop
  "GLOBAL_FILEDIR_OPT",
75 073271f6 Iustin Pop
  "HVLIST_OPT",
76 48f212d7 Iustin Pop
  "HVOPTS_OPT",
77 236fd9c4 Iustin Pop
  "HYPERVISOR_OPT",
78 4eb62659 Iustin Pop
  "IALLOCATOR_OPT",
79 bf4af505 Apollon Oikonomopoulos
  "DEFAULT_IALLOCATOR_OPT",
80 e588764d Iustin Pop
  "IDENTIFY_DEFAULTS_OPT",
81 82a786d5 Iustin Pop
  "IGNORE_CONSIST_OPT",
82 b6e841a8 Iustin Pop
  "IGNORE_FAILURES_OPT",
83 8d8d650c Michael Hanselmann
  "IGNORE_REMOVE_FAILURES_OPT",
84 ee3f9578 Iustin Pop
  "IGNORE_SECONDARIES_OPT",
85 05586c90 Iustin Pop
  "IGNORE_SIZE_OPT",
86 e3646f22 Iustin Pop
  "MAC_PREFIX_OPT",
87 3953242f Iustin Pop
  "MAINTAIN_NODE_HEALTH_OPT",
88 29392516 Iustin Pop
  "MASTER_NETDEV_OPT",
89 771734c9 Iustin Pop
  "MC_OPT",
90 783a6c0b Iustin Pop
  "MIGRATION_MODE_OPT",
91 7d3a9fab Iustin Pop
  "NET_OPT",
92 6d4a1656 Michael Hanselmann
  "NEW_CLUSTER_CERT_OPT",
93 3db3eb2a Michael Hanselmann
  "NEW_CLUSTER_DOMAIN_SECRET_OPT",
94 6b7d5878 Michael Hanselmann
  "NEW_CONFD_HMAC_KEY_OPT",
95 6d4a1656 Michael Hanselmann
  "NEW_RAPI_CERT_OPT",
96 a14db5ff Iustin Pop
  "NEW_SECONDARY_OPT",
97 4fbc93dd Iustin Pop
  "NIC_PARAMS_OPT",
98 7edc4637 Iustin Pop
  "NODE_LIST_OPT",
99 990b7886 Iustin Pop
  "NODE_PLACEMENT_OPT",
100 26591bfd Luca Bigliardi
  "NODRBD_STORAGE_OPT",
101 4abc4f1e Iustin Pop
  "NOHDR_OPT",
102 91e0748c Iustin Pop
  "NOIPCHECK_OPT",
103 25a8792c Iustin Pop
  "NO_INSTALL_OPT",
104 460d22be Iustin Pop
  "NONAMECHECK_OPT",
105 831040bf Iustin Pop
  "NOLVM_STORAGE_OPT",
106 29392516 Iustin Pop
  "NOMODIFY_ETCHOSTS_OPT",
107 b989b9d9 Ken Wehr
  "NOMODIFY_SSH_SETUP_OPT",
108 26023ecd Iustin Pop
  "NONICS_OPT",
109 f2a0828c Iustin Pop
  "NONLIVE_OPT",
110 14e9e7f3 Iustin Pop
  "NONPLUS1_OPT",
111 44c44832 Iustin Pop
  "NOSHUTDOWN_OPT",
112 edeb878a Iustin Pop
  "NOSTART_OPT",
113 fcdde7f2 Iustin Pop
  "NOSSH_KEYCHECK_OPT",
114 58371861 Iustin Pop
  "NOVOTING_OPT",
115 3f75b4f3 Iustin Pop
  "NWSYNC_OPT",
116 a72d0a79 Iustin Pop
  "ON_PRIMARY_OPT",
117 feb09e6a Iustin Pop
  "ON_SECONDARY_OPT",
118 771734c9 Iustin Pop
  "OFFLINE_OPT",
119 062a7100 Iustin Pop
  "OSPARAMS_OPT",
120 d3ed23ff Iustin Pop
  "OS_OPT",
121 ff00c1a7 Iustin Pop
  "OS_SIZE_OPT",
122 e7323b5e Manuel Franceschini
  "PRIMARY_IP_VERSION_OPT",
123 6d4a1656 Michael Hanselmann
  "RAPI_CERT_OPT",
124 b8d0f938 Iustin Pop
  "READD_OPT",
125 12054861 Iustin Pop
  "REBOOT_TYPE_OPT",
126 8d8d650c Michael Hanselmann
  "REMOVE_INSTANCE_OPT",
127 fdad8c4d Balazs Lecz
  "REMOVE_UIDS_OPT",
128 f38ea602 Iustin Pop
  "RESERVED_LVS_OPT",
129 31d97b2a Guido Trotter
  "ROMAN_OPT",
130 8d823629 Iustin Pop
  "SECONDARY_IP_OPT",
131 67840b40 Iustin Pop
  "SELECT_OS_OPT",
132 4abc4f1e Iustin Pop
  "SEP_OPT",
133 fdcf4d84 Iustin Pop
  "SHOWCMD_OPT",
134 7e5eaaa8 Guido Trotter
  "SHUTDOWN_TIMEOUT_OPT",
135 f36d7d81 Iustin Pop
  "SINGLE_NODE_OPT",
136 df62e5db Iustin Pop
  "SRC_DIR_OPT",
137 df62e5db Iustin Pop
  "SRC_NODE_OPT",
138 4abc4f1e Iustin Pop
  "SUBMIT_OPT",
139 99a8c799 Iustin Pop
  "STATIC_OPT",
140 4abc4f1e Iustin Pop
  "SYNC_OPT",
141 4abc4f1e Iustin Pop
  "TAG_SRC_OPT",
142 b5762e2a Guido Trotter
  "TIMEOUT_OPT",
143 1338f2b4 Balazs Lecz
  "UIDPOOL_OPT",
144 4abc4f1e Iustin Pop
  "USEUNITS_OPT",
145 74adc100 Iustin Pop
  "USE_REPL_NET_OPT",
146 9cdb9578 Iustin Pop
  "VERBOSE_OPT",
147 b58726e8 Iustin Pop
  "VG_NAME_OPT",
148 1f587d3d Iustin Pop
  "YES_DOIT_OPT",
149 4abc4f1e Iustin Pop
  # Generic functions for CLI programs
150 4abc4f1e Iustin Pop
  "GenericMain",
151 d77490c5 Iustin Pop
  "GenericInstanceCreate",
152 4abc4f1e Iustin Pop
  "GetClient",
153 4abc4f1e Iustin Pop
  "GetOnlineNodes",
154 4abc4f1e Iustin Pop
  "JobExecutor",
155 4abc4f1e Iustin Pop
  "JobSubmittedException",
156 4abc4f1e Iustin Pop
  "ParseTimespec",
157 7e49b6ce Michael Hanselmann
  "RunWhileClusterStopped",
158 4abc4f1e Iustin Pop
  "SubmitOpCode",
159 4abc4f1e Iustin Pop
  "SubmitOrSend",
160 4abc4f1e Iustin Pop
  "UsesRPC",
161 4abc4f1e Iustin Pop
  # Formatting functions
162 4abc4f1e Iustin Pop
  "ToStderr", "ToStdout",
163 4abc4f1e Iustin Pop
  "FormatError",
164 4abc4f1e Iustin Pop
  "GenerateTable",
165 4abc4f1e Iustin Pop
  "AskUser",
166 4abc4f1e Iustin Pop
  "FormatTimestamp",
167 8a7f1c61 Michael Hanselmann
  "FormatLogMessage",
168 4abc4f1e Iustin Pop
  # Tags functions
169 4abc4f1e Iustin Pop
  "ListTags",
170 4abc4f1e Iustin Pop
  "AddTags",
171 4abc4f1e Iustin Pop
  "RemoveTags",
172 4abc4f1e Iustin Pop
  # command line options support infrastructure
173 4abc4f1e Iustin Pop
  "ARGS_MANY_INSTANCES",
174 4abc4f1e Iustin Pop
  "ARGS_MANY_NODES",
175 4abc4f1e Iustin Pop
  "ARGS_NONE",
176 4abc4f1e Iustin Pop
  "ARGS_ONE_INSTANCE",
177 4abc4f1e Iustin Pop
  "ARGS_ONE_NODE",
178 f9faf9c3 Renรฉ Nussbaumer
  "ARGS_ONE_OS",
179 4abc4f1e Iustin Pop
  "ArgChoice",
180 4abc4f1e Iustin Pop
  "ArgCommand",
181 4abc4f1e Iustin Pop
  "ArgFile",
182 4abc4f1e Iustin Pop
  "ArgHost",
183 4abc4f1e Iustin Pop
  "ArgInstance",
184 4abc4f1e Iustin Pop
  "ArgJobId",
185 4abc4f1e Iustin Pop
  "ArgNode",
186 f9faf9c3 Renรฉ Nussbaumer
  "ArgOs",
187 4abc4f1e Iustin Pop
  "ArgSuggest",
188 4abc4f1e Iustin Pop
  "ArgUnknown",
189 4abc4f1e Iustin Pop
  "OPT_COMPL_INST_ADD_NODES",
190 4abc4f1e Iustin Pop
  "OPT_COMPL_MANY_NODES",
191 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_IALLOCATOR",
192 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_INSTANCE",
193 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_NODE",
194 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_OS",
195 4abc4f1e Iustin Pop
  "cli_option",
196 4abc4f1e Iustin Pop
  "SplitNodeOption",
197 07150497 Guido Trotter
  "CalculateOSNames",
198 4abc4f1e Iustin Pop
  ]
199 846baef9 Iustin Pop
200 8b46606c Guido Trotter
NO_PREFIX = "no_"
201 8b46606c Guido Trotter
UN_PREFIX = "-"
202 846baef9 Iustin Pop
203 03298ebe Michael Hanselmann
204 863d7f46 Michael Hanselmann
class _Argument:
205 7260cfbe Iustin Pop
  def __init__(self, min=0, max=None): # pylint: disable-msg=W0622
206 863d7f46 Michael Hanselmann
    self.min = min
207 863d7f46 Michael Hanselmann
    self.max = max
208 863d7f46 Michael Hanselmann
209 863d7f46 Michael Hanselmann
  def __repr__(self):
210 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s>" %
211 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max))
212 863d7f46 Michael Hanselmann
213 863d7f46 Michael Hanselmann
214 863d7f46 Michael Hanselmann
class ArgSuggest(_Argument):
215 863d7f46 Michael Hanselmann
  """Suggesting argument.
216 863d7f46 Michael Hanselmann

217 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor.
218 863d7f46 Michael Hanselmann

219 863d7f46 Michael Hanselmann
  """
220 7260cfbe Iustin Pop
  # pylint: disable-msg=W0622
221 863d7f46 Michael Hanselmann
  def __init__(self, min=0, max=None, choices=None):
222 863d7f46 Michael Hanselmann
    _Argument.__init__(self, min=min, max=max)
223 863d7f46 Michael Hanselmann
    self.choices = choices
224 863d7f46 Michael Hanselmann
225 863d7f46 Michael Hanselmann
  def __repr__(self):
226 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s choices=%r>" %
227 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max, self.choices))
228 863d7f46 Michael Hanselmann
229 863d7f46 Michael Hanselmann
230 863d7f46 Michael Hanselmann
class ArgChoice(ArgSuggest):
231 863d7f46 Michael Hanselmann
  """Choice argument.
232 863d7f46 Michael Hanselmann

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

236 863d7f46 Michael Hanselmann
  """
237 863d7f46 Michael Hanselmann
238 863d7f46 Michael Hanselmann
239 863d7f46 Michael Hanselmann
class ArgUnknown(_Argument):
240 863d7f46 Michael Hanselmann
  """Unknown argument to program (e.g. determined at runtime).
241 863d7f46 Michael Hanselmann

242 863d7f46 Michael Hanselmann
  """
243 863d7f46 Michael Hanselmann
244 863d7f46 Michael Hanselmann
245 863d7f46 Michael Hanselmann
class ArgInstance(_Argument):
246 863d7f46 Michael Hanselmann
  """Instances argument.
247 863d7f46 Michael Hanselmann

248 863d7f46 Michael Hanselmann
  """
249 863d7f46 Michael Hanselmann
250 863d7f46 Michael Hanselmann
251 863d7f46 Michael Hanselmann
class ArgNode(_Argument):
252 863d7f46 Michael Hanselmann
  """Node argument.
253 863d7f46 Michael Hanselmann

254 863d7f46 Michael Hanselmann
  """
255 863d7f46 Michael Hanselmann
256 863d7f46 Michael Hanselmann
class ArgJobId(_Argument):
257 863d7f46 Michael Hanselmann
  """Job ID argument.
258 863d7f46 Michael Hanselmann

259 863d7f46 Michael Hanselmann
  """
260 863d7f46 Michael Hanselmann
261 863d7f46 Michael Hanselmann
262 863d7f46 Michael Hanselmann
class ArgFile(_Argument):
263 863d7f46 Michael Hanselmann
  """File path argument.
264 863d7f46 Michael Hanselmann

265 863d7f46 Michael Hanselmann
  """
266 863d7f46 Michael Hanselmann
267 863d7f46 Michael Hanselmann
268 863d7f46 Michael Hanselmann
class ArgCommand(_Argument):
269 863d7f46 Michael Hanselmann
  """Command argument.
270 863d7f46 Michael Hanselmann

271 863d7f46 Michael Hanselmann
  """
272 863d7f46 Michael Hanselmann
273 863d7f46 Michael Hanselmann
274 83ec7961 Michael Hanselmann
class ArgHost(_Argument):
275 83ec7961 Michael Hanselmann
  """Host argument.
276 83ec7961 Michael Hanselmann

277 83ec7961 Michael Hanselmann
  """
278 83ec7961 Michael Hanselmann
279 83ec7961 Michael Hanselmann
280 f9faf9c3 Renรฉ Nussbaumer
class ArgOs(_Argument):
281 f9faf9c3 Renรฉ Nussbaumer
  """OS argument.
282 f9faf9c3 Renรฉ Nussbaumer

283 f9faf9c3 Renรฉ Nussbaumer
  """
284 f9faf9c3 Renรฉ Nussbaumer
285 f9faf9c3 Renรฉ Nussbaumer
286 4a265c08 Michael Hanselmann
ARGS_NONE = []
287 4a265c08 Michael Hanselmann
ARGS_MANY_INSTANCES = [ArgInstance()]
288 4a265c08 Michael Hanselmann
ARGS_MANY_NODES = [ArgNode()]
289 4a265c08 Michael Hanselmann
ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
290 4a265c08 Michael Hanselmann
ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
291 f9faf9c3 Renรฉ Nussbaumer
ARGS_ONE_OS = [ArgOs(min=1, max=1)]
292 4a265c08 Michael Hanselmann
293 4a265c08 Michael Hanselmann
294 846baef9 Iustin Pop
def _ExtractTagsObject(opts, args):
295 846baef9 Iustin Pop
  """Extract the tag type object.
296 846baef9 Iustin Pop

297 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
298 846baef9 Iustin Pop

299 846baef9 Iustin Pop
  """
300 846baef9 Iustin Pop
  if not hasattr(opts, "tag_type"):
301 846baef9 Iustin Pop
    raise errors.ProgrammerError("tag_type not passed to _ExtractTagsObject")
302 846baef9 Iustin Pop
  kind = opts.tag_type
303 846baef9 Iustin Pop
  if kind == constants.TAG_CLUSTER:
304 846baef9 Iustin Pop
    retval = kind, kind
305 846baef9 Iustin Pop
  elif kind == constants.TAG_NODE or kind == constants.TAG_INSTANCE:
306 846baef9 Iustin Pop
    if not args:
307 0c434948 Iustin Pop
      raise errors.OpPrereqError("no arguments passed to the command")
308 846baef9 Iustin Pop
    name = args.pop(0)
309 846baef9 Iustin Pop
    retval = kind, name
310 846baef9 Iustin Pop
  else:
311 846baef9 Iustin Pop
    raise errors.ProgrammerError("Unhandled tag type '%s'" % kind)
312 846baef9 Iustin Pop
  return retval
313 846baef9 Iustin Pop
314 846baef9 Iustin Pop
315 810c50b7 Iustin Pop
def _ExtendTags(opts, args):
316 810c50b7 Iustin Pop
  """Extend the args if a source file has been given.
317 810c50b7 Iustin Pop

318 810c50b7 Iustin Pop
  This function will extend the tags with the contents of the file
319 810c50b7 Iustin Pop
  passed in the 'tags_source' attribute of the opts parameter. A file
320 810c50b7 Iustin Pop
  named '-' will be replaced by stdin.
321 810c50b7 Iustin Pop

322 810c50b7 Iustin Pop
  """
323 810c50b7 Iustin Pop
  fname = opts.tags_source
324 810c50b7 Iustin Pop
  if fname is None:
325 810c50b7 Iustin Pop
    return
326 810c50b7 Iustin Pop
  if fname == "-":
327 810c50b7 Iustin Pop
    new_fh = sys.stdin
328 810c50b7 Iustin Pop
  else:
329 810c50b7 Iustin Pop
    new_fh = open(fname, "r")
330 810c50b7 Iustin Pop
  new_data = []
331 810c50b7 Iustin Pop
  try:
332 810c50b7 Iustin Pop
    # we don't use the nice 'new_data = [line.strip() for line in fh]'
333 810c50b7 Iustin Pop
    # because of python bug 1633941
334 810c50b7 Iustin Pop
    while True:
335 810c50b7 Iustin Pop
      line = new_fh.readline()
336 810c50b7 Iustin Pop
      if not line:
337 810c50b7 Iustin Pop
        break
338 810c50b7 Iustin Pop
      new_data.append(line.strip())
339 810c50b7 Iustin Pop
  finally:
340 810c50b7 Iustin Pop
    new_fh.close()
341 810c50b7 Iustin Pop
  args.extend(new_data)
342 810c50b7 Iustin Pop
343 810c50b7 Iustin Pop
344 846baef9 Iustin Pop
def ListTags(opts, args):
345 846baef9 Iustin Pop
  """List the tags on a given object.
346 846baef9 Iustin Pop

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

352 846baef9 Iustin Pop
  """
353 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
354 7699c3af Iustin Pop
  cl = GetClient()
355 7699c3af Iustin Pop
  result = cl.QueryTags(kind, name)
356 846baef9 Iustin Pop
  result = list(result)
357 846baef9 Iustin Pop
  result.sort()
358 846baef9 Iustin Pop
  for tag in result:
359 03298ebe Michael Hanselmann
    ToStdout(tag)
360 846baef9 Iustin Pop
361 846baef9 Iustin Pop
362 846baef9 Iustin Pop
def AddTags(opts, args):
363 846baef9 Iustin Pop
  """Add tags on a given object.
364 846baef9 Iustin Pop

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

370 846baef9 Iustin Pop
  """
371 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
372 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
373 846baef9 Iustin Pop
  if not args:
374 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be added")
375 846baef9 Iustin Pop
  op = opcodes.OpAddTags(kind=kind, name=name, tags=args)
376 846baef9 Iustin Pop
  SubmitOpCode(op)
377 846baef9 Iustin Pop
378 846baef9 Iustin Pop
379 846baef9 Iustin Pop
def RemoveTags(opts, args):
380 846baef9 Iustin Pop
  """Remove tags from a given object.
381 846baef9 Iustin Pop

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

387 846baef9 Iustin Pop
  """
388 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
389 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
390 846baef9 Iustin Pop
  if not args:
391 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be removed")
392 846baef9 Iustin Pop
  op = opcodes.OpDelTags(kind=kind, name=name, tags=args)
393 846baef9 Iustin Pop
  SubmitOpCode(op)
394 846baef9 Iustin Pop
395 a8083063 Iustin Pop
396 8929d28c Iustin Pop
def check_unit(option, opt, value): # pylint: disable-msg=W0613
397 65fe4693 Iustin Pop
  """OptParsers custom converter for units.
398 65fe4693 Iustin Pop

399 65fe4693 Iustin Pop
  """
400 a8083063 Iustin Pop
  try:
401 a8083063 Iustin Pop
    return utils.ParseUnit(value)
402 a8083063 Iustin Pop
  except errors.UnitParseError, err:
403 3ecf6786 Iustin Pop
    raise OptionValueError("option %s: %s" % (opt, err))
404 a8083063 Iustin Pop
405 a8083063 Iustin Pop
406 a8469393 Iustin Pop
def _SplitKeyVal(opt, data):
407 a8469393 Iustin Pop
  """Convert a KeyVal string into a dict.
408 a8469393 Iustin Pop

409 a8469393 Iustin Pop
  This function will convert a key=val[,...] string into a dict. Empty
410 a8469393 Iustin Pop
  values will be converted specially: keys which have the prefix 'no_'
411 a8469393 Iustin Pop
  will have the value=False and the prefix stripped, the others will
412 a8469393 Iustin Pop
  have value=True.
413 a8469393 Iustin Pop

414 a8469393 Iustin Pop
  @type opt: string
415 a8469393 Iustin Pop
  @param opt: a string holding the option name for which we process the
416 a8469393 Iustin Pop
      data, used in building error messages
417 a8469393 Iustin Pop
  @type data: string
418 a8469393 Iustin Pop
  @param data: a string of the format key=val,key=val,...
419 a8469393 Iustin Pop
  @rtype: dict
420 a8469393 Iustin Pop
  @return: {key=val, key=val}
421 a8469393 Iustin Pop
  @raises errors.ParameterError: if there are duplicate keys
422 a8469393 Iustin Pop

423 a8469393 Iustin Pop
  """
424 a8469393 Iustin Pop
  kv_dict = {}
425 4f31882e Guido Trotter
  if data:
426 1b3a7656 Iustin Pop
    for elem in utils.UnescapeAndSplit(data, sep=","):
427 4f31882e Guido Trotter
      if "=" in elem:
428 4f31882e Guido Trotter
        key, val = elem.split("=", 1)
429 a8469393 Iustin Pop
      else:
430 4f31882e Guido Trotter
        if elem.startswith(NO_PREFIX):
431 4f31882e Guido Trotter
          key, val = elem[len(NO_PREFIX):], False
432 4f31882e Guido Trotter
        elif elem.startswith(UN_PREFIX):
433 4f31882e Guido Trotter
          key, val = elem[len(UN_PREFIX):], None
434 4f31882e Guido Trotter
        else:
435 4f31882e Guido Trotter
          key, val = elem, True
436 4f31882e Guido Trotter
      if key in kv_dict:
437 4f31882e Guido Trotter
        raise errors.ParameterError("Duplicate key '%s' in option %s" %
438 4f31882e Guido Trotter
                                    (key, opt))
439 4f31882e Guido Trotter
      kv_dict[key] = val
440 a8469393 Iustin Pop
  return kv_dict
441 a8469393 Iustin Pop
442 a8469393 Iustin Pop
443 8929d28c Iustin Pop
def check_ident_key_val(option, opt, value):  # pylint: disable-msg=W0613
444 552c8dff Michael Hanselmann
  """Custom parser for ident:key=val,key=val options.
445 552c8dff Michael Hanselmann

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

449 a8469393 Iustin Pop
  """
450 a8469393 Iustin Pop
  if ":" not in value:
451 8b46606c Guido Trotter
    ident, rest = value, ''
452 a8469393 Iustin Pop
  else:
453 a8469393 Iustin Pop
    ident, rest = value.split(":", 1)
454 8b46606c Guido Trotter
455 8b46606c Guido Trotter
  if ident.startswith(NO_PREFIX):
456 8b46606c Guido Trotter
    if rest:
457 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
458 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
459 8b46606c Guido Trotter
    retval = (ident[len(NO_PREFIX):], False)
460 8b46606c Guido Trotter
  elif ident.startswith(UN_PREFIX):
461 8b46606c Guido Trotter
    if rest:
462 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
463 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
464 8b46606c Guido Trotter
    retval = (ident[len(UN_PREFIX):], None)
465 8b46606c Guido Trotter
  else:
466 a8469393 Iustin Pop
    kv_dict = _SplitKeyVal(opt, rest)
467 a8469393 Iustin Pop
    retval = (ident, kv_dict)
468 a8469393 Iustin Pop
  return retval
469 a8469393 Iustin Pop
470 a8469393 Iustin Pop
471 8929d28c Iustin Pop
def check_key_val(option, opt, value):  # pylint: disable-msg=W0613
472 552c8dff Michael Hanselmann
  """Custom parser class for key=val,key=val options.
473 552c8dff Michael Hanselmann

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

476 a8469393 Iustin Pop
  """
477 a8469393 Iustin Pop
  return _SplitKeyVal(opt, value)
478 a8469393 Iustin Pop
479 a8469393 Iustin Pop
480 e7b61bb0 Iustin Pop
def check_bool(option, opt, value): # pylint: disable-msg=W0613
481 e7b61bb0 Iustin Pop
  """Custom parser for yes/no options.
482 e7b61bb0 Iustin Pop

483 e7b61bb0 Iustin Pop
  This will store the parsed value as either True or False.
484 e7b61bb0 Iustin Pop

485 e7b61bb0 Iustin Pop
  """
486 e7b61bb0 Iustin Pop
  value = value.lower()
487 e7b61bb0 Iustin Pop
  if value == constants.VALUE_FALSE or value == "no":
488 e7b61bb0 Iustin Pop
    return False
489 e7b61bb0 Iustin Pop
  elif value == constants.VALUE_TRUE or value == "yes":
490 e7b61bb0 Iustin Pop
    return True
491 e7b61bb0 Iustin Pop
  else:
492 e7b61bb0 Iustin Pop
    raise errors.ParameterError("Invalid boolean value '%s'" % value)
493 e7b61bb0 Iustin Pop
494 e7b61bb0 Iustin Pop
495 63d44c55 Michael Hanselmann
# completion_suggestion is normally a list. Using numeric values not evaluating
496 63d44c55 Michael Hanselmann
# to False for dynamic completion.
497 63d44c55 Michael Hanselmann
(OPT_COMPL_MANY_NODES,
498 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_NODE,
499 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_INSTANCE,
500 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_OS,
501 2d3ed64b Michael Hanselmann
 OPT_COMPL_ONE_IALLOCATOR,
502 2d3ed64b Michael Hanselmann
 OPT_COMPL_INST_ADD_NODES) = range(100, 106)
503 63d44c55 Michael Hanselmann
504 63d44c55 Michael Hanselmann
OPT_COMPL_ALL = frozenset([
505 63d44c55 Michael Hanselmann
  OPT_COMPL_MANY_NODES,
506 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_NODE,
507 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_INSTANCE,
508 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_OS,
509 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_IALLOCATOR,
510 2d3ed64b Michael Hanselmann
  OPT_COMPL_INST_ADD_NODES,
511 63d44c55 Michael Hanselmann
  ])
512 63d44c55 Michael Hanselmann
513 63d44c55 Michael Hanselmann
514 552c8dff Michael Hanselmann
class CliOption(Option):
515 552c8dff Michael Hanselmann
  """Custom option class for optparse.
516 a8469393 Iustin Pop

517 a8469393 Iustin Pop
  """
518 863d7f46 Michael Hanselmann
  ATTRS = Option.ATTRS + [
519 863d7f46 Michael Hanselmann
    "completion_suggest",
520 863d7f46 Michael Hanselmann
    ]
521 552c8dff Michael Hanselmann
  TYPES = Option.TYPES + (
522 552c8dff Michael Hanselmann
    "identkeyval",
523 552c8dff Michael Hanselmann
    "keyval",
524 552c8dff Michael Hanselmann
    "unit",
525 e7b61bb0 Iustin Pop
    "bool",
526 552c8dff Michael Hanselmann
    )
527 552c8dff Michael Hanselmann
  TYPE_CHECKER = Option.TYPE_CHECKER.copy()
528 552c8dff Michael Hanselmann
  TYPE_CHECKER["identkeyval"] = check_ident_key_val
529 a8469393 Iustin Pop
  TYPE_CHECKER["keyval"] = check_key_val
530 552c8dff Michael Hanselmann
  TYPE_CHECKER["unit"] = check_unit
531 e7b61bb0 Iustin Pop
  TYPE_CHECKER["bool"] = check_bool
532 a8469393 Iustin Pop
533 a8469393 Iustin Pop
534 a8083063 Iustin Pop
# optparse.py sets make_option, so we do it for our own option class, too
535 a8083063 Iustin Pop
cli_option = CliOption
536 a8083063 Iustin Pop
537 a8083063 Iustin Pop
538 771734c9 Iustin Pop
_YORNO = "yes|no"
539 771734c9 Iustin Pop
540 ea34193f Iustin Pop
DEBUG_OPT = cli_option("-d", "--debug", default=0, action="count",
541 ea34193f Iustin Pop
                       help="Increase debugging level")
542 c38c44ad Michael Hanselmann
543 c38c44ad Michael Hanselmann
NOHDR_OPT = cli_option("--no-headers", default=False,
544 c38c44ad Michael Hanselmann
                       action="store_true", dest="no_headers",
545 c38c44ad Michael Hanselmann
                       help="Don't display column headers")
546 c38c44ad Michael Hanselmann
547 c38c44ad Michael Hanselmann
SEP_OPT = cli_option("--separator", default=None,
548 c38c44ad Michael Hanselmann
                     action="store", dest="separator",
549 c38c44ad Michael Hanselmann
                     help=("Separator between output fields"
550 c38c44ad Michael Hanselmann
                           " (defaults to one space)"))
551 c38c44ad Michael Hanselmann
552 c38c44ad Michael Hanselmann
USEUNITS_OPT = cli_option("--units", default=None,
553 c38c44ad Michael Hanselmann
                          dest="units", choices=('h', 'm', 'g', 't'),
554 c38c44ad Michael Hanselmann
                          help="Specify units for output (one of hmgt)")
555 c38c44ad Michael Hanselmann
556 c38c44ad Michael Hanselmann
FIELDS_OPT = cli_option("-o", "--output", dest="output", action="store",
557 c38c44ad Michael Hanselmann
                        type="string", metavar="FIELDS",
558 c38c44ad Michael Hanselmann
                        help="Comma separated list of output fields")
559 c38c44ad Michael Hanselmann
560 c38c44ad Michael Hanselmann
FORCE_OPT = cli_option("-f", "--force", dest="force", action="store_true",
561 c38c44ad Michael Hanselmann
                       default=False, help="Force the operation")
562 c38c44ad Michael Hanselmann
563 c38c44ad Michael Hanselmann
CONFIRM_OPT = cli_option("--yes", dest="confirm", action="store_true",
564 c38c44ad Michael Hanselmann
                         default=False, help="Do not require confirmation")
565 c38c44ad Michael Hanselmann
566 c38c44ad Michael Hanselmann
TAG_SRC_OPT = cli_option("--from", dest="tags_source",
567 c38c44ad Michael Hanselmann
                         default=None, help="File with tag names")
568 c38c44ad Michael Hanselmann
569 c38c44ad Michael Hanselmann
SUBMIT_OPT = cli_option("--submit", dest="submit_only",
570 c38c44ad Michael Hanselmann
                        default=False, action="store_true",
571 c38c44ad Michael Hanselmann
                        help=("Submit the job and return the job ID, but"
572 c38c44ad Michael Hanselmann
                              " don't wait for the job to finish"))
573 c38c44ad Michael Hanselmann
574 c38c44ad Michael Hanselmann
SYNC_OPT = cli_option("--sync", dest="do_locking",
575 c38c44ad Michael Hanselmann
                      default=False, action="store_true",
576 c38c44ad Michael Hanselmann
                      help=("Grab locks while doing the queries"
577 c38c44ad Michael Hanselmann
                            " in order to ensure more consistent results"))
578 c38c44ad Michael Hanselmann
579 c38c44ad Michael Hanselmann
_DRY_RUN_OPT = cli_option("--dry-run", default=False,
580 c38c44ad Michael Hanselmann
                          action="store_true",
581 c38c44ad Michael Hanselmann
                          help=("Do not execute the operation, just run the"
582 c38c44ad Michael Hanselmann
                                " check steps and verify it it could be"
583 c38c44ad Michael Hanselmann
                                " executed"))
584 c38c44ad Michael Hanselmann
585 9cdb9578 Iustin Pop
VERBOSE_OPT = cli_option("-v", "--verbose", default=False,
586 9cdb9578 Iustin Pop
                         action="store_true",
587 9cdb9578 Iustin Pop
                         help="Increase the verbosity of the operation")
588 9cdb9578 Iustin Pop
589 a0c9776a Iustin Pop
DEBUG_SIMERR_OPT = cli_option("--debug-simulate-errors", default=False,
590 a0c9776a Iustin Pop
                              action="store_true", dest="simulate_errors",
591 a0c9776a Iustin Pop
                              help="Debugging option that makes the operation"
592 a0c9776a Iustin Pop
                              " treat most runtime checks as failed")
593 a0c9776a Iustin Pop
594 3f75b4f3 Iustin Pop
NWSYNC_OPT = cli_option("--no-wait-for-sync", dest="wait_for_sync",
595 3f75b4f3 Iustin Pop
                        default=True, action="store_false",
596 3f75b4f3 Iustin Pop
                        help="Don't wait for sync (DANGEROUS!)")
597 3f75b4f3 Iustin Pop
598 4f365444 Iustin Pop
DISK_TEMPLATE_OPT = cli_option("-t", "--disk-template", dest="disk_template",
599 4f365444 Iustin Pop
                               help="Custom disk setup (diskless, file,"
600 4f365444 Iustin Pop
                               " plain or drbd)",
601 4f365444 Iustin Pop
                               default=None, metavar="TEMPL",
602 4f365444 Iustin Pop
                               choices=list(constants.DISK_TEMPLATES))
603 4f365444 Iustin Pop
604 26023ecd Iustin Pop
NONICS_OPT = cli_option("--no-nics", default=False, action="store_true",
605 26023ecd Iustin Pop
                        help="Do not create any network cards for"
606 26023ecd Iustin Pop
                        " the instance")
607 26023ecd Iustin Pop
608 4a25828c Iustin Pop
FILESTORE_DIR_OPT = cli_option("--file-storage-dir", dest="file_storage_dir",
609 4a25828c Iustin Pop
                               help="Relative path under default cluster-wide"
610 4a25828c Iustin Pop
                               " file storage dir to store file-based disks",
611 4a25828c Iustin Pop
                               default=None, metavar="<DIR>")
612 4a25828c Iustin Pop
613 0f87c43e Iustin Pop
FILESTORE_DRIVER_OPT = cli_option("--file-driver", dest="file_driver",
614 0f87c43e Iustin Pop
                                  help="Driver to use for image files",
615 0f87c43e Iustin Pop
                                  default="loop", metavar="<DRIVER>",
616 0f87c43e Iustin Pop
                                  choices=list(constants.FILE_DRIVER))
617 0f87c43e Iustin Pop
618 4eb62659 Iustin Pop
IALLOCATOR_OPT = cli_option("-I", "--iallocator", metavar="<NAME>",
619 4eb62659 Iustin Pop
                            help="Select nodes for the instance automatically"
620 4eb62659 Iustin Pop
                            " using the <NAME> iallocator plugin",
621 4eb62659 Iustin Pop
                            default=None, type="string",
622 4eb62659 Iustin Pop
                            completion_suggest=OPT_COMPL_ONE_IALLOCATOR)
623 4eb62659 Iustin Pop
624 bf4af505 Apollon Oikonomopoulos
DEFAULT_IALLOCATOR_OPT = cli_option("-I", "--default-iallocator",
625 bf4af505 Apollon Oikonomopoulos
                            metavar="<NAME>",
626 bf4af505 Apollon Oikonomopoulos
                            help="Set the default instance allocator plugin",
627 bf4af505 Apollon Oikonomopoulos
                            default=None, type="string",
628 bf4af505 Apollon Oikonomopoulos
                            completion_suggest=OPT_COMPL_ONE_IALLOCATOR)
629 bf4af505 Apollon Oikonomopoulos
630 d3ed23ff Iustin Pop
OS_OPT = cli_option("-o", "--os-type", dest="os", help="What OS to run",
631 d3ed23ff Iustin Pop
                    metavar="<os>",
632 d3ed23ff Iustin Pop
                    completion_suggest=OPT_COMPL_ONE_OS)
633 d3ed23ff Iustin Pop
634 062a7100 Iustin Pop
OSPARAMS_OPT = cli_option("-O", "--os-parameters", dest="osparams",
635 062a7100 Iustin Pop
                         type="keyval", default={},
636 062a7100 Iustin Pop
                         help="OS parameters")
637 062a7100 Iustin Pop
638 06073e85 Guido Trotter
FORCE_VARIANT_OPT = cli_option("--force-variant", dest="force_variant",
639 06073e85 Guido Trotter
                               action="store_true", default=False,
640 06073e85 Guido Trotter
                               help="Force an unknown variant")
641 06073e85 Guido Trotter
642 25a8792c Iustin Pop
NO_INSTALL_OPT = cli_option("--no-install", dest="no_install",
643 25a8792c Iustin Pop
                            action="store_true", default=False,
644 25a8792c Iustin Pop
                            help="Do not install the OS (will"
645 25a8792c Iustin Pop
                            " enable no-start)")
646 25a8792c Iustin Pop
647 087ed2ed Iustin Pop
BACKEND_OPT = cli_option("-B", "--backend-parameters", dest="beparams",
648 087ed2ed Iustin Pop
                         type="keyval", default={},
649 087ed2ed Iustin Pop
                         help="Backend parameters")
650 48f212d7 Iustin Pop
651 48f212d7 Iustin Pop
HVOPTS_OPT =  cli_option("-H", "--hypervisor-parameters", type="keyval",
652 48f212d7 Iustin Pop
                         default={}, dest="hvparams",
653 48f212d7 Iustin Pop
                         help="Hypervisor parameters")
654 087ed2ed Iustin Pop
655 236fd9c4 Iustin Pop
HYPERVISOR_OPT = cli_option("-H", "--hypervisor-parameters", dest="hypervisor",
656 236fd9c4 Iustin Pop
                            help="Hypervisor and hypervisor options, in the"
657 236fd9c4 Iustin Pop
                            " format hypervisor:option=value,option=value,...",
658 236fd9c4 Iustin Pop
                            default=None, type="identkeyval")
659 073271f6 Iustin Pop
660 073271f6 Iustin Pop
HVLIST_OPT = cli_option("-H", "--hypervisor-parameters", dest="hvparams",
661 073271f6 Iustin Pop
                        help="Hypervisor and hypervisor options, in the"
662 073271f6 Iustin Pop
                        " format hypervisor:option=value,option=value,...",
663 073271f6 Iustin Pop
                        default=[], action="append", type="identkeyval")
664 236fd9c4 Iustin Pop
665 91e0748c Iustin Pop
NOIPCHECK_OPT = cli_option("--no-ip-check", dest="ip_check", default=True,
666 91e0748c Iustin Pop
                           action="store_false",
667 91e0748c Iustin Pop
                           help="Don't check that the instance's IP"
668 91e0748c Iustin Pop
                           " is alive")
669 91e0748c Iustin Pop
670 460d22be Iustin Pop
NONAMECHECK_OPT = cli_option("--no-name-check", dest="name_check",
671 460d22be Iustin Pop
                             default=True, action="store_false",
672 460d22be Iustin Pop
                             help="Don't check that the instance's name"
673 460d22be Iustin Pop
                             " is resolvable")
674 460d22be Iustin Pop
675 7d3a9fab Iustin Pop
NET_OPT = cli_option("--net",
676 7d3a9fab Iustin Pop
                     help="NIC parameters", default=[],
677 7d3a9fab Iustin Pop
                     dest="nics", action="append", type="identkeyval")
678 e3876ccb Iustin Pop
679 e3876ccb Iustin Pop
DISK_OPT = cli_option("--disk", help="Disk parameters", default=[],
680 e3876ccb Iustin Pop
                      dest="disks", action="append", type="identkeyval")
681 91e0748c Iustin Pop
682 4b038a1e Iustin Pop
DISKIDX_OPT = cli_option("--disks", dest="disks", default=None,
683 4b038a1e Iustin Pop
                         help="Comma-separated list of disks"
684 4b038a1e Iustin Pop
                         " indices to act on (e.g. 0,2) (optional,"
685 4b038a1e Iustin Pop
                         " defaults to all disks)")
686 4b038a1e Iustin Pop
687 ff00c1a7 Iustin Pop
OS_SIZE_OPT = cli_option("-s", "--os-size", dest="sd_size",
688 ff00c1a7 Iustin Pop
                         help="Enforces a single-disk configuration using the"
689 ff00c1a7 Iustin Pop
                         " given disk size, in MiB unless a suffix is used",
690 ff00c1a7 Iustin Pop
                         default=None, type="unit", metavar="<size>")
691 ff00c1a7 Iustin Pop
692 82a786d5 Iustin Pop
IGNORE_CONSIST_OPT = cli_option("--ignore-consistency",
693 82a786d5 Iustin Pop
                                dest="ignore_consistency",
694 82a786d5 Iustin Pop
                                action="store_true", default=False,
695 82a786d5 Iustin Pop
                                help="Ignore the consistency of the disks on"
696 82a786d5 Iustin Pop
                                " the secondary")
697 82a786d5 Iustin Pop
698 f2a0828c Iustin Pop
NONLIVE_OPT = cli_option("--non-live", dest="live",
699 f2a0828c Iustin Pop
                         default=True, action="store_false",
700 f2a0828c Iustin Pop
                         help="Do a non-live migration (this usually means"
701 f2a0828c Iustin Pop
                         " freeze the instance, save the state, transfer and"
702 f2a0828c Iustin Pop
                         " only then resume running on the secondary node)")
703 f2a0828c Iustin Pop
704 783a6c0b Iustin Pop
MIGRATION_MODE_OPT = cli_option("--migration-mode", dest="migration_mode",
705 e71b9ef4 Iustin Pop
                                default=None,
706 783a6c0b Iustin Pop
                                choices=list(constants.HT_MIGRATION_MODES),
707 783a6c0b Iustin Pop
                                help="Override default migration mode (choose"
708 e71b9ef4 Iustin Pop
                                " either live or non-live")
709 e71b9ef4 Iustin Pop
710 990b7886 Iustin Pop
NODE_PLACEMENT_OPT = cli_option("-n", "--node", dest="node",
711 990b7886 Iustin Pop
                                help="Target node and optional secondary node",
712 990b7886 Iustin Pop
                                metavar="<pnode>[:<snode>]",
713 990b7886 Iustin Pop
                                completion_suggest=OPT_COMPL_INST_ADD_NODES)
714 990b7886 Iustin Pop
715 7edc4637 Iustin Pop
NODE_LIST_OPT = cli_option("-n", "--node", dest="nodes", default=[],
716 7edc4637 Iustin Pop
                           action="append", metavar="<node>",
717 7edc4637 Iustin Pop
                           help="Use only this node (can be used multiple"
718 7edc4637 Iustin Pop
                           " times, if not given defaults to all nodes)",
719 7edc4637 Iustin Pop
                           completion_suggest=OPT_COMPL_ONE_NODE)
720 f36d7d81 Iustin Pop
721 f36d7d81 Iustin Pop
SINGLE_NODE_OPT = cli_option("-n", "--node", dest="node", help="Target node",
722 f36d7d81 Iustin Pop
                             metavar="<node>",
723 f36d7d81 Iustin Pop
                             completion_suggest=OPT_COMPL_ONE_NODE)
724 7edc4637 Iustin Pop
725 edeb878a Iustin Pop
NOSTART_OPT = cli_option("--no-start", dest="start", default=True,
726 edeb878a Iustin Pop
                         action="store_false",
727 edeb878a Iustin Pop
                         help="Don't start the instance after creation")
728 edeb878a Iustin Pop
729 fdcf4d84 Iustin Pop
SHOWCMD_OPT = cli_option("--show-cmd", dest="show_command",
730 fdcf4d84 Iustin Pop
                         action="store_true", default=False,
731 fdcf4d84 Iustin Pop
                         help="Show command instead of executing it")
732 fdcf4d84 Iustin Pop
733 baef337d Iustin Pop
CLEANUP_OPT = cli_option("--cleanup", dest="cleanup",
734 baef337d Iustin Pop
                         default=False, action="store_true",
735 baef337d Iustin Pop
                         help="Instead of performing the migration, try to"
736 baef337d Iustin Pop
                         " recover from a failed cleanup. This is safe"
737 baef337d Iustin Pop
                         " to run even if the instance is healthy, but it"
738 baef337d Iustin Pop
                         " will create extra replication traffic and "
739 baef337d Iustin Pop
                         " disrupt briefly the replication (like during the"
740 baef337d Iustin Pop
                         " migration")
741 baef337d Iustin Pop
742 99a8c799 Iustin Pop
STATIC_OPT = cli_option("-s", "--static", dest="static",
743 99a8c799 Iustin Pop
                        action="store_true", default=False,
744 99a8c799 Iustin Pop
                        help="Only show configuration data, not runtime data")
745 99a8c799 Iustin Pop
746 2d5e7ae1 Iustin Pop
ALL_OPT = cli_option("--all", dest="show_all",
747 2d5e7ae1 Iustin Pop
                     default=False, action="store_true",
748 2d5e7ae1 Iustin Pop
                     help="Show info on all instances on the cluster."
749 2d5e7ae1 Iustin Pop
                     " This can take a long time to run, use wisely")
750 2d5e7ae1 Iustin Pop
751 67840b40 Iustin Pop
SELECT_OS_OPT = cli_option("--select-os", dest="select_os",
752 67840b40 Iustin Pop
                           action="store_true", default=False,
753 67840b40 Iustin Pop
                           help="Interactive OS reinstall, lists available"
754 67840b40 Iustin Pop
                           " OS templates for selection")
755 2d5e7ae1 Iustin Pop
756 b6e841a8 Iustin Pop
IGNORE_FAILURES_OPT = cli_option("--ignore-failures", dest="ignore_failures",
757 b6e841a8 Iustin Pop
                                 action="store_true", default=False,
758 b6e841a8 Iustin Pop
                                 help="Remove the instance from the cluster"
759 b6e841a8 Iustin Pop
                                 " configuration even if there are failures"
760 b6e841a8 Iustin Pop
                                 " during the removal process")
761 b6e841a8 Iustin Pop
762 8d8d650c Michael Hanselmann
IGNORE_REMOVE_FAILURES_OPT = cli_option("--ignore-remove-failures",
763 8d8d650c Michael Hanselmann
                                        dest="ignore_remove_failures",
764 8d8d650c Michael Hanselmann
                                        action="store_true", default=False,
765 8d8d650c Michael Hanselmann
                                        help="Remove the instance from the"
766 8d8d650c Michael Hanselmann
                                        " cluster configuration even if there"
767 8d8d650c Michael Hanselmann
                                        " are failures during the removal"
768 8d8d650c Michael Hanselmann
                                        " process")
769 8d8d650c Michael Hanselmann
770 8d8d650c Michael Hanselmann
REMOVE_INSTANCE_OPT = cli_option("--remove-instance", dest="remove_instance",
771 8d8d650c Michael Hanselmann
                                 action="store_true", default=False,
772 8d8d650c Michael Hanselmann
                                 help="Remove the instance from the cluster")
773 8d8d650c Michael Hanselmann
774 a14db5ff Iustin Pop
NEW_SECONDARY_OPT = cli_option("-n", "--new-secondary", dest="dst_node",
775 a14db5ff Iustin Pop
                               help="Specifies the new secondary node",
776 a14db5ff Iustin Pop
                               metavar="NODE", default=None,
777 a14db5ff Iustin Pop
                               completion_suggest=OPT_COMPL_ONE_NODE)
778 a14db5ff Iustin Pop
779 a72d0a79 Iustin Pop
ON_PRIMARY_OPT = cli_option("-p", "--on-primary", dest="on_primary",
780 a72d0a79 Iustin Pop
                            default=False, action="store_true",
781 a72d0a79 Iustin Pop
                            help="Replace the disk(s) on the primary"
782 a72d0a79 Iustin Pop
                            " node (only for the drbd template)")
783 feb09e6a Iustin Pop
784 feb09e6a Iustin Pop
ON_SECONDARY_OPT = cli_option("-s", "--on-secondary", dest="on_secondary",
785 feb09e6a Iustin Pop
                              default=False, action="store_true",
786 feb09e6a Iustin Pop
                              help="Replace the disk(s) on the secondary"
787 feb09e6a Iustin Pop
                              " node (only for the drbd template)")
788 e00f7a05 Iustin Pop
789 4c61d894 Iustin Pop
AUTO_PROMOTE_OPT = cli_option("--auto-promote", dest="auto_promote",
790 4c61d894 Iustin Pop
                              default=False, action="store_true",
791 4c61d894 Iustin Pop
                              help="Lock all nodes and auto-promote as needed"
792 4c61d894 Iustin Pop
                              " to MC status")
793 4c61d894 Iustin Pop
794 e00f7a05 Iustin Pop
AUTO_REPLACE_OPT = cli_option("-a", "--auto", dest="auto",
795 e00f7a05 Iustin Pop
                              default=False, action="store_true",
796 e00f7a05 Iustin Pop
                              help="Automatically replace faulty disks"
797 e00f7a05 Iustin Pop
                              " (only for the drbd template)")
798 a72d0a79 Iustin Pop
799 05586c90 Iustin Pop
IGNORE_SIZE_OPT = cli_option("--ignore-size", dest="ignore_size",
800 05586c90 Iustin Pop
                             default=False, action="store_true",
801 05586c90 Iustin Pop
                             help="Ignore current recorded size"
802 05586c90 Iustin Pop
                             " (useful for forcing activation when"
803 05586c90 Iustin Pop
                             " the recorded size is wrong)")
804 05586c90 Iustin Pop
805 df62e5db Iustin Pop
SRC_NODE_OPT = cli_option("--src-node", dest="src_node", help="Source node",
806 df62e5db Iustin Pop
                          metavar="<node>",
807 df62e5db Iustin Pop
                          completion_suggest=OPT_COMPL_ONE_NODE)
808 df62e5db Iustin Pop
809 df62e5db Iustin Pop
SRC_DIR_OPT = cli_option("--src-dir", dest="src_dir", help="Source directory",
810 df62e5db Iustin Pop
                         metavar="<dir>")
811 df62e5db Iustin Pop
812 8d823629 Iustin Pop
SECONDARY_IP_OPT = cli_option("-s", "--secondary-ip", dest="secondary_ip",
813 8d823629 Iustin Pop
                              help="Specify the secondary ip for the node",
814 8d823629 Iustin Pop
                              metavar="ADDRESS", default=None)
815 8d823629 Iustin Pop
816 b8d0f938 Iustin Pop
READD_OPT = cli_option("--readd", dest="readd",
817 b8d0f938 Iustin Pop
                       default=False, action="store_true",
818 b8d0f938 Iustin Pop
                       help="Readd old node after replacing it")
819 b8d0f938 Iustin Pop
820 fcdde7f2 Iustin Pop
NOSSH_KEYCHECK_OPT = cli_option("--no-ssh-key-check", dest="ssh_key_check",
821 fcdde7f2 Iustin Pop
                                default=True, action="store_false",
822 fcdde7f2 Iustin Pop
                                help="Disable SSH key fingerprint checking")
823 fcdde7f2 Iustin Pop
824 c38c44ad Michael Hanselmann
825 771734c9 Iustin Pop
MC_OPT = cli_option("-C", "--master-candidate", dest="master_candidate",
826 e7b61bb0 Iustin Pop
                    type="bool", default=None, metavar=_YORNO,
827 771734c9 Iustin Pop
                    help="Set the master_candidate flag on the node")
828 771734c9 Iustin Pop
829 771734c9 Iustin Pop
OFFLINE_OPT = cli_option("-O", "--offline", dest="offline", metavar=_YORNO,
830 e7b61bb0 Iustin Pop
                         type="bool", default=None,
831 771734c9 Iustin Pop
                         help="Set the offline flag on the node")
832 771734c9 Iustin Pop
833 771734c9 Iustin Pop
DRAINED_OPT = cli_option("-D", "--drained", dest="drained", metavar=_YORNO,
834 e7b61bb0 Iustin Pop
                         type="bool", default=None,
835 771734c9 Iustin Pop
                         help="Set the drained flag on the node")
836 771734c9 Iustin Pop
837 e7e09483 Iustin Pop
ALLOCATABLE_OPT = cli_option("--allocatable", dest="allocatable",
838 e7b61bb0 Iustin Pop
                             type="bool", default=None, metavar=_YORNO,
839 e7e09483 Iustin Pop
                             help="Set the allocatable flag on a volume")
840 e7e09483 Iustin Pop
841 831040bf Iustin Pop
NOLVM_STORAGE_OPT = cli_option("--no-lvm-storage", dest="lvm_storage",
842 831040bf Iustin Pop
                               help="Disable support for lvm based instances"
843 831040bf Iustin Pop
                               " (cluster-wide)",
844 831040bf Iustin Pop
                               action="store_false", default=True)
845 831040bf Iustin Pop
846 383a3591 Iustin Pop
ENABLED_HV_OPT = cli_option("--enabled-hypervisors",
847 383a3591 Iustin Pop
                            dest="enabled_hypervisors",
848 383a3591 Iustin Pop
                            help="Comma-separated list of hypervisors",
849 383a3591 Iustin Pop
                            type="string", default=None)
850 383a3591 Iustin Pop
851 4fbc93dd Iustin Pop
NIC_PARAMS_OPT = cli_option("-N", "--nic-parameters", dest="nicparams",
852 4fbc93dd Iustin Pop
                            type="keyval", default={},
853 4fbc93dd Iustin Pop
                            help="NIC parameters")
854 4fbc93dd Iustin Pop
855 e32df528 Iustin Pop
CP_SIZE_OPT = cli_option("-C", "--candidate-pool-size", default=None,
856 e32df528 Iustin Pop
                         dest="candidate_pool_size", type="int",
857 e32df528 Iustin Pop
                         help="Set the candidate pool size")
858 e32df528 Iustin Pop
859 b58726e8 Iustin Pop
VG_NAME_OPT = cli_option("-g", "--vg-name", dest="vg_name",
860 b58726e8 Iustin Pop
                         help="Enables LVM and specifies the volume group"
861 b58726e8 Iustin Pop
                         " name (cluster-wide) for disk allocation [xenvg]",
862 b58726e8 Iustin Pop
                         metavar="VG", default=None)
863 b58726e8 Iustin Pop
864 1f587d3d Iustin Pop
YES_DOIT_OPT = cli_option("--yes-do-it", dest="yes_do_it",
865 1f587d3d Iustin Pop
                          help="Destroy cluster", action="store_true")
866 b58726e8 Iustin Pop
867 58371861 Iustin Pop
NOVOTING_OPT = cli_option("--no-voting", dest="no_voting",
868 58371861 Iustin Pop
                          help="Skip node agreement check (dangerous)",
869 58371861 Iustin Pop
                          action="store_true", default=False)
870 58371861 Iustin Pop
871 e3646f22 Iustin Pop
MAC_PREFIX_OPT = cli_option("-m", "--mac-prefix", dest="mac_prefix",
872 e3646f22 Iustin Pop
                            help="Specify the mac prefix for the instance IP"
873 e3646f22 Iustin Pop
                            " addresses, in the format XX:XX:XX",
874 e3646f22 Iustin Pop
                            metavar="PREFIX",
875 e3646f22 Iustin Pop
                            default=None)
876 e3646f22 Iustin Pop
877 29392516 Iustin Pop
MASTER_NETDEV_OPT = cli_option("--master-netdev", dest="master_netdev",
878 29392516 Iustin Pop
                               help="Specify the node interface (cluster-wide)"
879 29392516 Iustin Pop
                               " on which the master IP address will be added "
880 29392516 Iustin Pop
                               " [%s]" % constants.DEFAULT_BRIDGE,
881 29392516 Iustin Pop
                               metavar="NETDEV",
882 29392516 Iustin Pop
                               default=constants.DEFAULT_BRIDGE)
883 29392516 Iustin Pop
884 29392516 Iustin Pop
GLOBAL_FILEDIR_OPT = cli_option("--file-storage-dir", dest="file_storage_dir",
885 29392516 Iustin Pop
                                help="Specify the default directory (cluster-"
886 29392516 Iustin Pop
                                "wide) for storing the file-based disks [%s]" %
887 29392516 Iustin Pop
                                constants.DEFAULT_FILE_STORAGE_DIR,
888 29392516 Iustin Pop
                                metavar="DIR",
889 29392516 Iustin Pop
                                default=constants.DEFAULT_FILE_STORAGE_DIR)
890 29392516 Iustin Pop
891 29392516 Iustin Pop
NOMODIFY_ETCHOSTS_OPT = cli_option("--no-etc-hosts", dest="modify_etc_hosts",
892 29392516 Iustin Pop
                                   help="Don't modify /etc/hosts",
893 29392516 Iustin Pop
                                   action="store_false", default=True)
894 29392516 Iustin Pop
895 b989b9d9 Ken Wehr
NOMODIFY_SSH_SETUP_OPT = cli_option("--no-ssh-init", dest="modify_ssh_setup",
896 b989b9d9 Ken Wehr
                                    help="Don't initialize SSH keys",
897 b989b9d9 Ken Wehr
                                    action="store_false", default=True)
898 b989b9d9 Ken Wehr
899 14e9e7f3 Iustin Pop
ERROR_CODES_OPT = cli_option("--error-codes", dest="error_codes",
900 14e9e7f3 Iustin Pop
                             help="Enable parseable error messages",
901 14e9e7f3 Iustin Pop
                             action="store_true", default=False)
902 14e9e7f3 Iustin Pop
903 14e9e7f3 Iustin Pop
NONPLUS1_OPT = cli_option("--no-nplus1-mem", dest="skip_nplusone_mem",
904 14e9e7f3 Iustin Pop
                          help="Skip N+1 memory redundancy tests",
905 14e9e7f3 Iustin Pop
                          action="store_true", default=False)
906 14e9e7f3 Iustin Pop
907 12054861 Iustin Pop
REBOOT_TYPE_OPT = cli_option("-t", "--type", dest="reboot_type",
908 12054861 Iustin Pop
                             help="Type of reboot: soft/hard/full",
909 12054861 Iustin Pop
                             default=constants.INSTANCE_REBOOT_HARD,
910 12054861 Iustin Pop
                             metavar="<REBOOT>",
911 12054861 Iustin Pop
                             choices=list(constants.REBOOT_TYPES))
912 12054861 Iustin Pop
913 ee3f9578 Iustin Pop
IGNORE_SECONDARIES_OPT = cli_option("--ignore-secondaries",
914 ee3f9578 Iustin Pop
                                    dest="ignore_secondaries",
915 ee3f9578 Iustin Pop
                                    default=False, action="store_true",
916 ee3f9578 Iustin Pop
                                    help="Ignore errors from secondaries")
917 ee3f9578 Iustin Pop
918 69b99987 Michael Hanselmann
NOSHUTDOWN_OPT = cli_option("--noshutdown", dest="shutdown",
919 44c44832 Iustin Pop
                            action="store_false", default=True,
920 44c44832 Iustin Pop
                            help="Don't shutdown the instance (unsafe)")
921 44c44832 Iustin Pop
922 b5762e2a Guido Trotter
TIMEOUT_OPT = cli_option("--timeout", dest="timeout", type="int",
923 b5762e2a Guido Trotter
                         default=constants.DEFAULT_SHUTDOWN_TIMEOUT,
924 b5762e2a Guido Trotter
                         help="Maximum time to wait")
925 44c44832 Iustin Pop
926 4d98c565 Guido Trotter
SHUTDOWN_TIMEOUT_OPT = cli_option("--shutdown-timeout",
927 4d98c565 Guido Trotter
                         dest="shutdown_timeout", type="int",
928 7e5eaaa8 Guido Trotter
                         default=constants.DEFAULT_SHUTDOWN_TIMEOUT,
929 7e5eaaa8 Guido Trotter
                         help="Maximum time to wait for instance shutdown")
930 7e5eaaa8 Guido Trotter
931 7ea7bcf6 Iustin Pop
EARLY_RELEASE_OPT = cli_option("--early-release",
932 7ea7bcf6 Iustin Pop
                               dest="early_release", default=False,
933 7ea7bcf6 Iustin Pop
                               action="store_true",
934 7ea7bcf6 Iustin Pop
                               help="Release the locks on the secondary"
935 7ea7bcf6 Iustin Pop
                               " node(s) early")
936 7ea7bcf6 Iustin Pop
937 6d4a1656 Michael Hanselmann
NEW_CLUSTER_CERT_OPT = cli_option("--new-cluster-certificate",
938 6d4a1656 Michael Hanselmann
                                  dest="new_cluster_cert",
939 6d4a1656 Michael Hanselmann
                                  default=False, action="store_true",
940 6d4a1656 Michael Hanselmann
                                  help="Generate a new cluster certificate")
941 6d4a1656 Michael Hanselmann
942 6d4a1656 Michael Hanselmann
RAPI_CERT_OPT = cli_option("--rapi-certificate", dest="rapi_cert",
943 6d4a1656 Michael Hanselmann
                           default=None,
944 6d4a1656 Michael Hanselmann
                           help="File containing new RAPI certificate")
945 6d4a1656 Michael Hanselmann
946 6d4a1656 Michael Hanselmann
NEW_RAPI_CERT_OPT = cli_option("--new-rapi-certificate", dest="new_rapi_cert",
947 6d4a1656 Michael Hanselmann
                               default=None, action="store_true",
948 6d4a1656 Michael Hanselmann
                               help=("Generate a new self-signed RAPI"
949 6d4a1656 Michael Hanselmann
                                     " certificate"))
950 6d4a1656 Michael Hanselmann
951 6b7d5878 Michael Hanselmann
NEW_CONFD_HMAC_KEY_OPT = cli_option("--new-confd-hmac-key",
952 6b7d5878 Michael Hanselmann
                                    dest="new_confd_hmac_key",
953 6b7d5878 Michael Hanselmann
                                    default=False, action="store_true",
954 6b7d5878 Michael Hanselmann
                                    help=("Create a new HMAC key for %s" %
955 6b7d5878 Michael Hanselmann
                                          constants.CONFD))
956 6d4a1656 Michael Hanselmann
957 3db3eb2a Michael Hanselmann
CLUSTER_DOMAIN_SECRET_OPT = cli_option("--cluster-domain-secret",
958 3db3eb2a Michael Hanselmann
                                       dest="cluster_domain_secret",
959 3db3eb2a Michael Hanselmann
                                       default=None,
960 3db3eb2a Michael Hanselmann
                                       help=("Load new new cluster domain"
961 3db3eb2a Michael Hanselmann
                                             " secret from file"))
962 3db3eb2a Michael Hanselmann
963 3db3eb2a Michael Hanselmann
NEW_CLUSTER_DOMAIN_SECRET_OPT = cli_option("--new-cluster-domain-secret",
964 3db3eb2a Michael Hanselmann
                                           dest="new_cluster_domain_secret",
965 3db3eb2a Michael Hanselmann
                                           default=False, action="store_true",
966 3db3eb2a Michael Hanselmann
                                           help=("Create a new cluster domain"
967 3db3eb2a Michael Hanselmann
                                                 " secret"))
968 3db3eb2a Michael Hanselmann
969 74adc100 Iustin Pop
USE_REPL_NET_OPT = cli_option("--use-replication-network",
970 74adc100 Iustin Pop
                              dest="use_replication_network",
971 74adc100 Iustin Pop
                              help="Whether to use the replication network"
972 74adc100 Iustin Pop
                              " for talking to the nodes",
973 74adc100 Iustin Pop
                              action="store_true", default=False)
974 74adc100 Iustin Pop
975 3953242f Iustin Pop
MAINTAIN_NODE_HEALTH_OPT = \
976 3953242f Iustin Pop
    cli_option("--maintain-node-health", dest="maintain_node_health",
977 3953242f Iustin Pop
               metavar=_YORNO, default=None, type="bool",
978 3953242f Iustin Pop
               help="Configure the cluster to automatically maintain node"
979 3953242f Iustin Pop
               " health, by shutting down unknown instances, shutting down"
980 3953242f Iustin Pop
               " unknown DRBD devices, etc.")
981 3953242f Iustin Pop
982 e588764d Iustin Pop
IDENTIFY_DEFAULTS_OPT = \
983 e588764d Iustin Pop
    cli_option("--identify-defaults", dest="identify_defaults",
984 e588764d Iustin Pop
               default=False, action="store_true",
985 e588764d Iustin Pop
               help="Identify which saved instance parameters are equal to"
986 e588764d Iustin Pop
               " the current cluster defaults and set them as such, instead"
987 e588764d Iustin Pop
               " of marking them as overridden")
988 e588764d Iustin Pop
989 1338f2b4 Balazs Lecz
UIDPOOL_OPT = cli_option("--uid-pool", default=None,
990 1338f2b4 Balazs Lecz
                         action="store", dest="uid_pool",
991 1338f2b4 Balazs Lecz
                         help=("A list of user-ids or user-id"
992 1338f2b4 Balazs Lecz
                               " ranges separated by commas"))
993 1338f2b4 Balazs Lecz
994 fdad8c4d Balazs Lecz
ADD_UIDS_OPT = cli_option("--add-uids", default=None,
995 fdad8c4d Balazs Lecz
                          action="store", dest="add_uids",
996 fdad8c4d Balazs Lecz
                          help=("A list of user-ids or user-id"
997 fdad8c4d Balazs Lecz
                                " ranges separated by commas, to be"
998 fdad8c4d Balazs Lecz
                                " added to the user-id pool"))
999 fdad8c4d Balazs Lecz
1000 fdad8c4d Balazs Lecz
REMOVE_UIDS_OPT = cli_option("--remove-uids", default=None,
1001 fdad8c4d Balazs Lecz
                             action="store", dest="remove_uids",
1002 fdad8c4d Balazs Lecz
                             help=("A list of user-ids or user-id"
1003 fdad8c4d Balazs Lecz
                                   " ranges separated by commas, to be"
1004 fdad8c4d Balazs Lecz
                                   " removed from the user-id pool"))
1005 fdad8c4d Balazs Lecz
1006 f38ea602 Iustin Pop
RESERVED_LVS_OPT = cli_option("--reserved-lvs", default=None,
1007 f38ea602 Iustin Pop
                             action="store", dest="reserved_lvs",
1008 f38ea602 Iustin Pop
                             help=("A comma-separated list of reserved"
1009 f38ea602 Iustin Pop
                                   " logical volumes names, that will be"
1010 f38ea602 Iustin Pop
                                   " ignored by cluster verify"))
1011 f38ea602 Iustin Pop
1012 31d97b2a Guido Trotter
ROMAN_OPT = cli_option("--roman",
1013 31d97b2a Guido Trotter
                       dest="roman_integers", default=False,
1014 31d97b2a Guido Trotter
                       action="store_true",
1015 31d97b2a Guido Trotter
                       help="Use roman numbers for positive integers")
1016 31d97b2a Guido Trotter
1017 26591bfd Luca Bigliardi
DRBD_HELPER_OPT = cli_option("--drbd-usermode-helper", dest="drbd_helper",
1018 26591bfd Luca Bigliardi
                             action="store", default=None,
1019 26591bfd Luca Bigliardi
                             help="Specifies usermode helper for DRBD")
1020 26591bfd Luca Bigliardi
1021 26591bfd Luca Bigliardi
NODRBD_STORAGE_OPT = cli_option("--no-drbd-storage", dest="drbd_storage",
1022 26591bfd Luca Bigliardi
                                action="store_false", default=True,
1023 26591bfd Luca Bigliardi
                                help="Disable support for DRBD")
1024 31d97b2a Guido Trotter
1025 e7323b5e Manuel Franceschini
PRIMARY_IP_VERSION_OPT = \
1026 e7323b5e Manuel Franceschini
    cli_option("--primary-ip-version", default=constants.IP4_VERSION,
1027 e7323b5e Manuel Franceschini
               action="store", dest="primary_ip_version",
1028 e7323b5e Manuel Franceschini
               metavar="%d|%d" % (constants.IP4_VERSION,
1029 e7323b5e Manuel Franceschini
                                  constants.IP6_VERSION),
1030 e7323b5e Manuel Franceschini
               help="Cluster-wide IP version for primary IP")
1031 e7323b5e Manuel Franceschini
1032 771734c9 Iustin Pop
1033 de47cf8f Guido Trotter
def _ParseArgs(argv, commands, aliases):
1034 c41eea6e Iustin Pop
  """Parser for the command line arguments.
1035 a8083063 Iustin Pop

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

1039 c41eea6e Iustin Pop
  @param argv: the command line
1040 c41eea6e Iustin Pop
  @param commands: dictionary with special contents, see the design
1041 c41eea6e Iustin Pop
      doc for cmdline handling
1042 c41eea6e Iustin Pop
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
1043 098c0958 Michael Hanselmann

1044 a8083063 Iustin Pop
  """
1045 a8083063 Iustin Pop
  if len(argv) == 0:
1046 a8083063 Iustin Pop
    binary = "<command>"
1047 a8083063 Iustin Pop
  else:
1048 a8083063 Iustin Pop
    binary = argv[0].split("/")[-1]
1049 a8083063 Iustin Pop
1050 a8083063 Iustin Pop
  if len(argv) > 1 and argv[1] == "--version":
1051 84a12e40 Iustin Pop
    ToStdout("%s (ganeti %s) %s", binary, constants.VCS_VERSION,
1052 84a12e40 Iustin Pop
             constants.RELEASE_VERSION)
1053 a8083063 Iustin Pop
    # Quit right away. That way we don't have to care about this special
1054 a8083063 Iustin Pop
    # argument. optparse.py does it the same.
1055 a8083063 Iustin Pop
    sys.exit(0)
1056 a8083063 Iustin Pop
1057 de47cf8f Guido Trotter
  if len(argv) < 2 or not (argv[1] in commands or
1058 70a35b6f Guido Trotter
                           argv[1] in aliases):
1059 a8083063 Iustin Pop
    # let's do a nice thing
1060 a8083063 Iustin Pop
    sortedcmds = commands.keys()
1061 a8083063 Iustin Pop
    sortedcmds.sort()
1062 03298ebe Michael Hanselmann
1063 03298ebe Michael Hanselmann
    ToStdout("Usage: %s {command} [options...] [argument...]", binary)
1064 03298ebe Michael Hanselmann
    ToStdout("%s <command> --help to see details, or man %s", binary, binary)
1065 03298ebe Michael Hanselmann
    ToStdout("")
1066 03298ebe Michael Hanselmann
1067 a8083063 Iustin Pop
    # compute the max line length for cmd + usage
1068 4e713df6 Iustin Pop
    mlen = max([len(" %s" % cmd) for cmd in commands])
1069 a8083063 Iustin Pop
    mlen = min(60, mlen) # should not get here...
1070 03298ebe Michael Hanselmann
1071 a8083063 Iustin Pop
    # and format a nice command list
1072 03298ebe Michael Hanselmann
    ToStdout("Commands:")
1073 a8083063 Iustin Pop
    for cmd in sortedcmds:
1074 4e713df6 Iustin Pop
      cmdstr = " %s" % (cmd,)
1075 9a033156 Iustin Pop
      help_text = commands[cmd][4]
1076 03298ebe Michael Hanselmann
      help_lines = textwrap.wrap(help_text, 79 - 3 - mlen)
1077 03298ebe Michael Hanselmann
      ToStdout("%-*s - %s", mlen, cmdstr, help_lines.pop(0))
1078 a8083063 Iustin Pop
      for line in help_lines:
1079 03298ebe Michael Hanselmann
        ToStdout("%-*s   %s", mlen, "", line)
1080 03298ebe Michael Hanselmann
1081 03298ebe Michael Hanselmann
    ToStdout("")
1082 03298ebe Michael Hanselmann
1083 a8083063 Iustin Pop
    return None, None, None
1084 de47cf8f Guido Trotter
1085 de47cf8f Guido Trotter
  # get command, unalias it, and look it up in commands
1086 a8083063 Iustin Pop
  cmd = argv.pop(1)
1087 de47cf8f Guido Trotter
  if cmd in aliases:
1088 de47cf8f Guido Trotter
    if cmd in commands:
1089 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' overrides an existing"
1090 de47cf8f Guido Trotter
                                   " command" % cmd)
1091 de47cf8f Guido Trotter
1092 de47cf8f Guido Trotter
    if aliases[cmd] not in commands:
1093 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' maps to non-existing"
1094 de47cf8f Guido Trotter
                                   " command '%s'" % (cmd, aliases[cmd]))
1095 de47cf8f Guido Trotter
1096 de47cf8f Guido Trotter
    cmd = aliases[cmd]
1097 de47cf8f Guido Trotter
1098 a8005e17 Michael Hanselmann
  func, args_def, parser_opts, usage, description = commands[cmd]
1099 064c21f8 Iustin Pop
  parser = OptionParser(option_list=parser_opts + [_DRY_RUN_OPT, DEBUG_OPT],
1100 a8083063 Iustin Pop
                        description=description,
1101 a8083063 Iustin Pop
                        formatter=TitledHelpFormatter(),
1102 a8083063 Iustin Pop
                        usage="%%prog %s %s" % (cmd, usage))
1103 a8083063 Iustin Pop
  parser.disable_interspersed_args()
1104 a8083063 Iustin Pop
  options, args = parser.parse_args()
1105 a8005e17 Michael Hanselmann
1106 a8005e17 Michael Hanselmann
  if not _CheckArguments(cmd, args_def, args):
1107 a8083063 Iustin Pop
    return None, None, None
1108 a8083063 Iustin Pop
1109 a8083063 Iustin Pop
  return func, options, args
1110 a8083063 Iustin Pop
1111 a8083063 Iustin Pop
1112 a8005e17 Michael Hanselmann
def _CheckArguments(cmd, args_def, args):
1113 a8005e17 Michael Hanselmann
  """Verifies the arguments using the argument definition.
1114 a8005e17 Michael Hanselmann

1115 a8005e17 Michael Hanselmann
  Algorithm:
1116 a8005e17 Michael Hanselmann

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

1119 a8005e17 Michael Hanselmann
    1. For each argument in definition
1120 a8005e17 Michael Hanselmann

1121 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
1122 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
1123 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
1124 a8005e17 Michael Hanselmann

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

1127 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
1128 a8005e17 Michael Hanselmann

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

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

1133 a8005e17 Michael Hanselmann
  """
1134 a8005e17 Michael Hanselmann
  if args and not args_def:
1135 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects no arguments", cmd)
1136 a8005e17 Michael Hanselmann
    return False
1137 a8005e17 Michael Hanselmann
1138 a8005e17 Michael Hanselmann
  min_count = None
1139 a8005e17 Michael Hanselmann
  max_count = None
1140 a8005e17 Michael Hanselmann
  check_max = None
1141 a8005e17 Michael Hanselmann
1142 a8005e17 Michael Hanselmann
  last_idx = len(args_def) - 1
1143 a8005e17 Michael Hanselmann
1144 a8005e17 Michael Hanselmann
  for idx, arg in enumerate(args_def):
1145 a8005e17 Michael Hanselmann
    if min_count is None:
1146 a8005e17 Michael Hanselmann
      min_count = arg.min
1147 a8005e17 Michael Hanselmann
    elif arg.min is not None:
1148 a8005e17 Michael Hanselmann
      min_count += arg.min
1149 a8005e17 Michael Hanselmann
1150 a8005e17 Michael Hanselmann
    if max_count is None:
1151 a8005e17 Michael Hanselmann
      max_count = arg.max
1152 a8005e17 Michael Hanselmann
    elif arg.max is not None:
1153 a8005e17 Michael Hanselmann
      max_count += arg.max
1154 a8005e17 Michael Hanselmann
1155 a8005e17 Michael Hanselmann
    if idx == last_idx:
1156 a8005e17 Michael Hanselmann
      check_max = (arg.max is not None)
1157 a8005e17 Michael Hanselmann
1158 a8005e17 Michael Hanselmann
    elif arg.max is None:
1159 a8005e17 Michael Hanselmann
      raise errors.ProgrammerError("Only the last argument can have max=None")
1160 a8005e17 Michael Hanselmann
1161 a8005e17 Michael Hanselmann
  if check_max:
1162 a8005e17 Michael Hanselmann
    # Command with exact number of arguments
1163 a8005e17 Michael Hanselmann
    if (min_count is not None and max_count is not None and
1164 a8005e17 Michael Hanselmann
        min_count == max_count and len(args) != min_count):
1165 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects %d argument(s)", cmd, min_count)
1166 a8005e17 Michael Hanselmann
      return False
1167 a8005e17 Michael Hanselmann
1168 a8005e17 Michael Hanselmann
    # Command with limited number of arguments
1169 a8005e17 Michael Hanselmann
    if max_count is not None and len(args) > max_count:
1170 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects only %d argument(s)",
1171 a8005e17 Michael Hanselmann
               cmd, max_count)
1172 a8005e17 Michael Hanselmann
      return False
1173 a8005e17 Michael Hanselmann
1174 a8005e17 Michael Hanselmann
  # Command with some required arguments
1175 a8005e17 Michael Hanselmann
  if min_count is not None and len(args) < min_count:
1176 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects at least %d argument(s)",
1177 a8005e17 Michael Hanselmann
             cmd, min_count)
1178 a8005e17 Michael Hanselmann
    return False
1179 a8005e17 Michael Hanselmann
1180 a8005e17 Michael Hanselmann
  return True
1181 a8005e17 Michael Hanselmann
1182 a8005e17 Michael Hanselmann
1183 60d49723 Michael Hanselmann
def SplitNodeOption(value):
1184 60d49723 Michael Hanselmann
  """Splits the value of a --node option.
1185 60d49723 Michael Hanselmann

1186 60d49723 Michael Hanselmann
  """
1187 60d49723 Michael Hanselmann
  if value and ':' in value:
1188 60d49723 Michael Hanselmann
    return value.split(':', 1)
1189 60d49723 Michael Hanselmann
  else:
1190 60d49723 Michael Hanselmann
    return (value, None)
1191 60d49723 Michael Hanselmann
1192 60d49723 Michael Hanselmann
1193 07150497 Guido Trotter
def CalculateOSNames(os_name, os_variants):
1194 07150497 Guido Trotter
  """Calculates all the names an OS can be called, according to its variants.
1195 07150497 Guido Trotter

1196 07150497 Guido Trotter
  @type os_name: string
1197 07150497 Guido Trotter
  @param os_name: base name of the os
1198 07150497 Guido Trotter
  @type os_variants: list or None
1199 07150497 Guido Trotter
  @param os_variants: list of supported variants
1200 07150497 Guido Trotter
  @rtype: list
1201 07150497 Guido Trotter
  @return: list of valid names
1202 07150497 Guido Trotter

1203 07150497 Guido Trotter
  """
1204 07150497 Guido Trotter
  if os_variants:
1205 07150497 Guido Trotter
    return ['%s+%s' % (os_name, v) for v in os_variants]
1206 07150497 Guido Trotter
  else:
1207 07150497 Guido Trotter
    return [os_name]
1208 07150497 Guido Trotter
1209 07150497 Guido Trotter
1210 e0e916fe Iustin Pop
UsesRPC = rpc.RunWithRPC
1211 4331f6cd Michael Hanselmann
1212 4331f6cd Michael Hanselmann
1213 47988778 Iustin Pop
def AskUser(text, choices=None):
1214 47988778 Iustin Pop
  """Ask the user a question.
1215 a8083063 Iustin Pop

1216 c41eea6e Iustin Pop
  @param text: the question to ask
1217 a8083063 Iustin Pop

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

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

1227 a8083063 Iustin Pop
  """
1228 47988778 Iustin Pop
  if choices is None:
1229 47988778 Iustin Pop
    choices = [('y', True, 'Perform the operation'),
1230 47988778 Iustin Pop
               ('n', False, 'Do not perform the operation')]
1231 47988778 Iustin Pop
  if not choices or not isinstance(choices, list):
1232 5bbd3f7f Michael Hanselmann
    raise errors.ProgrammerError("Invalid choices argument to AskUser")
1233 47988778 Iustin Pop
  for entry in choices:
1234 47988778 Iustin Pop
    if not isinstance(entry, tuple) or len(entry) < 3 or entry[0] == '?':
1235 5bbd3f7f Michael Hanselmann
      raise errors.ProgrammerError("Invalid choices element to AskUser")
1236 47988778 Iustin Pop
1237 47988778 Iustin Pop
  answer = choices[-1][1]
1238 47988778 Iustin Pop
  new_text = []
1239 47988778 Iustin Pop
  for line in text.splitlines():
1240 47988778 Iustin Pop
    new_text.append(textwrap.fill(line, 70, replace_whitespace=False))
1241 47988778 Iustin Pop
  text = "\n".join(new_text)
1242 a8083063 Iustin Pop
  try:
1243 3023170f Iustin Pop
    f = file("/dev/tty", "a+")
1244 a8083063 Iustin Pop
  except IOError:
1245 47988778 Iustin Pop
    return answer
1246 a8083063 Iustin Pop
  try:
1247 47988778 Iustin Pop
    chars = [entry[0] for entry in choices]
1248 47988778 Iustin Pop
    chars[-1] = "[%s]" % chars[-1]
1249 47988778 Iustin Pop
    chars.append('?')
1250 47988778 Iustin Pop
    maps = dict([(entry[0], entry[1]) for entry in choices])
1251 47988778 Iustin Pop
    while True:
1252 47988778 Iustin Pop
      f.write(text)
1253 47988778 Iustin Pop
      f.write('\n')
1254 47988778 Iustin Pop
      f.write("/".join(chars))
1255 47988778 Iustin Pop
      f.write(": ")
1256 47988778 Iustin Pop
      line = f.readline(2).strip().lower()
1257 47988778 Iustin Pop
      if line in maps:
1258 47988778 Iustin Pop
        answer = maps[line]
1259 47988778 Iustin Pop
        break
1260 47988778 Iustin Pop
      elif line == '?':
1261 47988778 Iustin Pop
        for entry in choices:
1262 47988778 Iustin Pop
          f.write(" %s - %s\n" % (entry[0], entry[2]))
1263 47988778 Iustin Pop
        f.write("\n")
1264 47988778 Iustin Pop
        continue
1265 a8083063 Iustin Pop
  finally:
1266 a8083063 Iustin Pop
    f.close()
1267 a8083063 Iustin Pop
  return answer
1268 a8083063 Iustin Pop
1269 a8083063 Iustin Pop
1270 e9d741b6 Iustin Pop
class JobSubmittedException(Exception):
1271 e9d741b6 Iustin Pop
  """Job was submitted, client should exit.
1272 e9d741b6 Iustin Pop

1273 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1274 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1275 e9d741b6 Iustin Pop

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

1278 e9d741b6 Iustin Pop
  """
1279 e9d741b6 Iustin Pop
1280 e9d741b6 Iustin Pop
1281 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1282 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1283 a8083063 Iustin Pop

1284 0a1e74d9 Iustin Pop
  @type ops: list
1285 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1286 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1287 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1288 0a1e74d9 Iustin Pop
             if None, a new client will be created
1289 a8083063 Iustin Pop

1290 a8083063 Iustin Pop
  """
1291 e2212007 Iustin Pop
  if cl is None:
1292 b33e986b Iustin Pop
    cl = GetClient()
1293 685ee993 Iustin Pop
1294 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1295 0a1e74d9 Iustin Pop
1296 0a1e74d9 Iustin Pop
  return job_id
1297 0a1e74d9 Iustin Pop
1298 0a1e74d9 Iustin Pop
1299 4e338533 Michael Hanselmann
def GenericPollJob(job_id, cbs, report_cbs):
1300 4e338533 Michael Hanselmann
  """Generic job-polling function.
1301 0a1e74d9 Iustin Pop

1302 4e338533 Michael Hanselmann
  @type job_id: number
1303 4e338533 Michael Hanselmann
  @param job_id: Job ID
1304 4e338533 Michael Hanselmann
  @type cbs: Instance of L{JobPollCbBase}
1305 4e338533 Michael Hanselmann
  @param cbs: Data callbacks
1306 4e338533 Michael Hanselmann
  @type report_cbs: Instance of L{JobPollReportCbBase}
1307 4e338533 Michael Hanselmann
  @param report_cbs: Reporting callbacks
1308 0a1e74d9 Iustin Pop

1309 0a1e74d9 Iustin Pop
  """
1310 6c5a7090 Michael Hanselmann
  prev_job_info = None
1311 6c5a7090 Michael Hanselmann
  prev_logmsg_serial = None
1312 6c5a7090 Michael Hanselmann
1313 f4484122 Michael Hanselmann
  status = None
1314 f4484122 Michael Hanselmann
1315 685ee993 Iustin Pop
  while True:
1316 4e338533 Michael Hanselmann
    result = cbs.WaitForJobChangeOnce(job_id, ["status"], prev_job_info,
1317 4e338533 Michael Hanselmann
                                      prev_logmsg_serial)
1318 6c5a7090 Michael Hanselmann
    if not result:
1319 685ee993 Iustin Pop
      # job not found, go away!
1320 0bbe448c Michael Hanselmann
      raise errors.JobLost("Job with id %s lost" % job_id)
1321 4e338533 Michael Hanselmann
1322 4e338533 Michael Hanselmann
    if result == constants.JOB_NOTCHANGED:
1323 4e338533 Michael Hanselmann
      report_cbs.ReportNotChanged(job_id, status)
1324 f4484122 Michael Hanselmann
1325 f4484122 Michael Hanselmann
      # Wait again
1326 f4484122 Michael Hanselmann
      continue
1327 685ee993 Iustin Pop
1328 6c5a7090 Michael Hanselmann
    # Split result, a tuple of (field values, log entries)
1329 6c5a7090 Michael Hanselmann
    (job_info, log_entries) = result
1330 6c5a7090 Michael Hanselmann
    (status, ) = job_info
1331 6c5a7090 Michael Hanselmann
1332 6c5a7090 Michael Hanselmann
    if log_entries:
1333 6c5a7090 Michael Hanselmann
      for log_entry in log_entries:
1334 4e338533 Michael Hanselmann
        (serial, timestamp, log_type, message) = log_entry
1335 4e338533 Michael Hanselmann
        report_cbs.ReportLogMessage(job_id, serial, timestamp,
1336 4e338533 Michael Hanselmann
                                    log_type, message)
1337 6c5a7090 Michael Hanselmann
        prev_logmsg_serial = max(prev_logmsg_serial, serial)
1338 6c5a7090 Michael Hanselmann
1339 0bbe448c Michael Hanselmann
    # TODO: Handle canceled and archived jobs
1340 fbf0262f Michael Hanselmann
    elif status in (constants.JOB_STATUS_SUCCESS,
1341 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_ERROR,
1342 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELING,
1343 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELED):
1344 685ee993 Iustin Pop
      break
1345 6c5a7090 Michael Hanselmann
1346 6c5a7090 Michael Hanselmann
    prev_job_info = job_info
1347 685ee993 Iustin Pop
1348 4e338533 Michael Hanselmann
  jobs = cbs.QueryJobs([job_id], ["status", "opstatus", "opresult"])
1349 0bbe448c Michael Hanselmann
  if not jobs:
1350 0bbe448c Michael Hanselmann
    raise errors.JobLost("Job with id %s lost" % job_id)
1351 685ee993 Iustin Pop
1352 0e050889 Iustin Pop
  status, opstatus, result = jobs[0]
1353 4e338533 Michael Hanselmann
1354 0bbe448c Michael Hanselmann
  if status == constants.JOB_STATUS_SUCCESS:
1355 53c04d04 Iustin Pop
    return result
1356 4e338533 Michael Hanselmann
1357 4e338533 Michael Hanselmann
  if status in (constants.JOB_STATUS_CANCELING, constants.JOB_STATUS_CANCELED):
1358 fbf0262f Michael Hanselmann
    raise errors.OpExecError("Job was canceled")
1359 4e338533 Michael Hanselmann
1360 4e338533 Michael Hanselmann
  has_ok = False
1361 4e338533 Michael Hanselmann
  for idx, (status, msg) in enumerate(zip(opstatus, result)):
1362 4e338533 Michael Hanselmann
    if status == constants.OP_STATUS_SUCCESS:
1363 4e338533 Michael Hanselmann
      has_ok = True
1364 4e338533 Michael Hanselmann
    elif status == constants.OP_STATUS_ERROR:
1365 4e338533 Michael Hanselmann
      errors.MaybeRaise(msg)
1366 4e338533 Michael Hanselmann
1367 4e338533 Michael Hanselmann
      if has_ok:
1368 4e338533 Michael Hanselmann
        raise errors.OpExecError("partial failure (opcode %d): %s" %
1369 4e338533 Michael Hanselmann
                                 (idx, msg))
1370 4e338533 Michael Hanselmann
1371 4e338533 Michael Hanselmann
      raise errors.OpExecError(str(msg))
1372 4e338533 Michael Hanselmann
1373 4e338533 Michael Hanselmann
  # default failure mode
1374 4e338533 Michael Hanselmann
  raise errors.OpExecError(result)
1375 4e338533 Michael Hanselmann
1376 4e338533 Michael Hanselmann
1377 4e338533 Michael Hanselmann
class JobPollCbBase:
1378 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} callbacks.
1379 4e338533 Michael Hanselmann

1380 4e338533 Michael Hanselmann
  """
1381 4e338533 Michael Hanselmann
  def __init__(self):
1382 4e338533 Michael Hanselmann
    """Initializes this class.
1383 4e338533 Michael Hanselmann

1384 4e338533 Michael Hanselmann
    """
1385 4e338533 Michael Hanselmann
1386 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1387 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1388 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1389 4e338533 Michael Hanselmann

1390 4e338533 Michael Hanselmann
    """
1391 4e338533 Michael Hanselmann
    raise NotImplementedError()
1392 4e338533 Michael Hanselmann
1393 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1394 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1395 4e338533 Michael Hanselmann

1396 4e338533 Michael Hanselmann
    @type job_ids: list of numbers
1397 4e338533 Michael Hanselmann
    @param job_ids: Job IDs
1398 4e338533 Michael Hanselmann
    @type fields: list of strings
1399 4e338533 Michael Hanselmann
    @param fields: Fields
1400 4e338533 Michael Hanselmann

1401 4e338533 Michael Hanselmann
    """
1402 4e338533 Michael Hanselmann
    raise NotImplementedError()
1403 4e338533 Michael Hanselmann
1404 4e338533 Michael Hanselmann
1405 4e338533 Michael Hanselmann
class JobPollReportCbBase:
1406 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} reporting callbacks.
1407 4e338533 Michael Hanselmann

1408 4e338533 Michael Hanselmann
  """
1409 4e338533 Michael Hanselmann
  def __init__(self):
1410 4e338533 Michael Hanselmann
    """Initializes this class.
1411 4e338533 Michael Hanselmann

1412 4e338533 Michael Hanselmann
    """
1413 4e338533 Michael Hanselmann
1414 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1415 4e338533 Michael Hanselmann
    """Handles a log message.
1416 4e338533 Michael Hanselmann

1417 4e338533 Michael Hanselmann
    """
1418 4e338533 Michael Hanselmann
    raise NotImplementedError()
1419 4e338533 Michael Hanselmann
1420 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1421 4e338533 Michael Hanselmann
    """Called for if a job hasn't changed in a while.
1422 4e338533 Michael Hanselmann

1423 4e338533 Michael Hanselmann
    @type job_id: number
1424 4e338533 Michael Hanselmann
    @param job_id: Job ID
1425 4e338533 Michael Hanselmann
    @type status: string or None
1426 4e338533 Michael Hanselmann
    @param status: Job status if available
1427 4e338533 Michael Hanselmann

1428 4e338533 Michael Hanselmann
    """
1429 4e338533 Michael Hanselmann
    raise NotImplementedError()
1430 4e338533 Michael Hanselmann
1431 4e338533 Michael Hanselmann
1432 4e338533 Michael Hanselmann
class _LuxiJobPollCb(JobPollCbBase):
1433 4e338533 Michael Hanselmann
  def __init__(self, cl):
1434 4e338533 Michael Hanselmann
    """Initializes this class.
1435 4e338533 Michael Hanselmann

1436 4e338533 Michael Hanselmann
    """
1437 4e338533 Michael Hanselmann
    JobPollCbBase.__init__(self)
1438 4e338533 Michael Hanselmann
    self.cl = cl
1439 4e338533 Michael Hanselmann
1440 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1441 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1442 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1443 4e338533 Michael Hanselmann

1444 4e338533 Michael Hanselmann
    """
1445 4e338533 Michael Hanselmann
    return self.cl.WaitForJobChangeOnce(job_id, fields,
1446 4e338533 Michael Hanselmann
                                        prev_job_info, prev_log_serial)
1447 4e338533 Michael Hanselmann
1448 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1449 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1450 4e338533 Michael Hanselmann

1451 4e338533 Michael Hanselmann
    """
1452 4e338533 Michael Hanselmann
    return self.cl.QueryJobs(job_ids, fields)
1453 4e338533 Michael Hanselmann
1454 4e338533 Michael Hanselmann
1455 4e338533 Michael Hanselmann
class FeedbackFnJobPollReportCb(JobPollReportCbBase):
1456 4e338533 Michael Hanselmann
  def __init__(self, feedback_fn):
1457 4e338533 Michael Hanselmann
    """Initializes this class.
1458 4e338533 Michael Hanselmann

1459 4e338533 Michael Hanselmann
    """
1460 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1461 4e338533 Michael Hanselmann
1462 4e338533 Michael Hanselmann
    self.feedback_fn = feedback_fn
1463 4e338533 Michael Hanselmann
1464 4e338533 Michael Hanselmann
    assert callable(feedback_fn)
1465 4e338533 Michael Hanselmann
1466 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1467 4e338533 Michael Hanselmann
    """Handles a log message.
1468 4e338533 Michael Hanselmann

1469 4e338533 Michael Hanselmann
    """
1470 4e338533 Michael Hanselmann
    self.feedback_fn((timestamp, log_type, log_msg))
1471 4e338533 Michael Hanselmann
1472 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1473 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1474 4e338533 Michael Hanselmann

1475 4e338533 Michael Hanselmann
    """
1476 4e338533 Michael Hanselmann
    # Ignore
1477 4e338533 Michael Hanselmann
1478 4e338533 Michael Hanselmann
1479 4e338533 Michael Hanselmann
class StdioJobPollReportCb(JobPollReportCbBase):
1480 4e338533 Michael Hanselmann
  def __init__(self):
1481 4e338533 Michael Hanselmann
    """Initializes this class.
1482 4e338533 Michael Hanselmann

1483 4e338533 Michael Hanselmann
    """
1484 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1485 4e338533 Michael Hanselmann
1486 4e338533 Michael Hanselmann
    self.notified_queued = False
1487 4e338533 Michael Hanselmann
    self.notified_waitlock = False
1488 4e338533 Michael Hanselmann
1489 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1490 4e338533 Michael Hanselmann
    """Handles a log message.
1491 4e338533 Michael Hanselmann

1492 4e338533 Michael Hanselmann
    """
1493 4e338533 Michael Hanselmann
    ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)),
1494 8a7f1c61 Michael Hanselmann
             FormatLogMessage(log_type, log_msg))
1495 4e338533 Michael Hanselmann
1496 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1497 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1498 4e338533 Michael Hanselmann

1499 4e338533 Michael Hanselmann
    """
1500 4e338533 Michael Hanselmann
    if status is None:
1501 4e338533 Michael Hanselmann
      return
1502 4e338533 Michael Hanselmann
1503 4e338533 Michael Hanselmann
    if status == constants.JOB_STATUS_QUEUED and not self.notified_queued:
1504 4e338533 Michael Hanselmann
      ToStderr("Job %s is waiting in queue", job_id)
1505 4e338533 Michael Hanselmann
      self.notified_queued = True
1506 4e338533 Michael Hanselmann
1507 4e338533 Michael Hanselmann
    elif status == constants.JOB_STATUS_WAITLOCK and not self.notified_waitlock:
1508 4e338533 Michael Hanselmann
      ToStderr("Job %s is trying to acquire all necessary locks", job_id)
1509 4e338533 Michael Hanselmann
      self.notified_waitlock = True
1510 4e338533 Michael Hanselmann
1511 4e338533 Michael Hanselmann
1512 8a7f1c61 Michael Hanselmann
def FormatLogMessage(log_type, log_msg):
1513 8a7f1c61 Michael Hanselmann
  """Formats a job message according to its type.
1514 8a7f1c61 Michael Hanselmann

1515 8a7f1c61 Michael Hanselmann
  """
1516 8a7f1c61 Michael Hanselmann
  if log_type != constants.ELOG_MESSAGE:
1517 8a7f1c61 Michael Hanselmann
    log_msg = str(log_msg)
1518 8a7f1c61 Michael Hanselmann
1519 8a7f1c61 Michael Hanselmann
  return utils.SafeEncode(log_msg)
1520 8a7f1c61 Michael Hanselmann
1521 8a7f1c61 Michael Hanselmann
1522 583163a6 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None, reporter=None):
1523 4e338533 Michael Hanselmann
  """Function to poll for the result of a job.
1524 4e338533 Michael Hanselmann

1525 4e338533 Michael Hanselmann
  @type job_id: job identified
1526 4e338533 Michael Hanselmann
  @param job_id: the job to poll for results
1527 4e338533 Michael Hanselmann
  @type cl: luxi.Client
1528 4e338533 Michael Hanselmann
  @param cl: the luxi client to use for communicating with the master;
1529 4e338533 Michael Hanselmann
             if None, a new client will be created
1530 4e338533 Michael Hanselmann

1531 4e338533 Michael Hanselmann
  """
1532 4e338533 Michael Hanselmann
  if cl is None:
1533 4e338533 Michael Hanselmann
    cl = GetClient()
1534 4e338533 Michael Hanselmann
1535 583163a6 Michael Hanselmann
  if reporter is None:
1536 583163a6 Michael Hanselmann
    if feedback_fn:
1537 583163a6 Michael Hanselmann
      reporter = FeedbackFnJobPollReportCb(feedback_fn)
1538 583163a6 Michael Hanselmann
    else:
1539 583163a6 Michael Hanselmann
      reporter = StdioJobPollReportCb()
1540 583163a6 Michael Hanselmann
  elif feedback_fn:
1541 583163a6 Michael Hanselmann
    raise errors.ProgrammerError("Can't specify reporter and feedback function")
1542 4e338533 Michael Hanselmann
1543 4e338533 Michael Hanselmann
  return GenericPollJob(job_id, _LuxiJobPollCb(cl), reporter)
1544 ceab32dd Iustin Pop
1545 ceab32dd Iustin Pop
1546 583163a6 Michael Hanselmann
def SubmitOpCode(op, cl=None, feedback_fn=None, opts=None, reporter=None):
1547 0a1e74d9 Iustin Pop
  """Legacy function to submit an opcode.
1548 0a1e74d9 Iustin Pop

1549 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1550 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1551 0a1e74d9 Iustin Pop
  interaction functions.
1552 0a1e74d9 Iustin Pop

1553 0a1e74d9 Iustin Pop
  """
1554 0a1e74d9 Iustin Pop
  if cl is None:
1555 0a1e74d9 Iustin Pop
    cl = GetClient()
1556 0a1e74d9 Iustin Pop
1557 293ba2d8 Iustin Pop
  SetGenericOpcodeOpts([op], opts)
1558 293ba2d8 Iustin Pop
1559 5d297d8a Michael Hanselmann
  job_id = SendJob([op], cl=cl)
1560 0a1e74d9 Iustin Pop
1561 583163a6 Michael Hanselmann
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn,
1562 583163a6 Michael Hanselmann
                       reporter=reporter)
1563 53c04d04 Iustin Pop
1564 53c04d04 Iustin Pop
  return op_results[0]
1565 0a1e74d9 Iustin Pop
1566 0a1e74d9 Iustin Pop
1567 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1568 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1569 94428652 Iustin Pop

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

1575 293ba2d8 Iustin Pop
  It will also process the opcodes if we're sending the via SendJob
1576 293ba2d8 Iustin Pop
  (otherwise SubmitOpCode does it).
1577 64c65a2a Iustin Pop

1578 94428652 Iustin Pop
  """
1579 94428652 Iustin Pop
  if opts and opts.submit_only:
1580 293ba2d8 Iustin Pop
    job = [op]
1581 293ba2d8 Iustin Pop
    SetGenericOpcodeOpts(job, opts)
1582 293ba2d8 Iustin Pop
    job_id = SendJob(job, cl=cl)
1583 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
1584 94428652 Iustin Pop
  else:
1585 293ba2d8 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
1586 293ba2d8 Iustin Pop
1587 293ba2d8 Iustin Pop
1588 293ba2d8 Iustin Pop
def SetGenericOpcodeOpts(opcode_list, options):
1589 293ba2d8 Iustin Pop
  """Processor for generic options.
1590 293ba2d8 Iustin Pop

1591 293ba2d8 Iustin Pop
  This function updates the given opcodes based on generic command
1592 293ba2d8 Iustin Pop
  line options (like debug, dry-run, etc.).
1593 293ba2d8 Iustin Pop

1594 293ba2d8 Iustin Pop
  @param opcode_list: list of opcodes
1595 293ba2d8 Iustin Pop
  @param options: command line options or None
1596 293ba2d8 Iustin Pop
  @return: None (in-place modification)
1597 293ba2d8 Iustin Pop

1598 293ba2d8 Iustin Pop
  """
1599 293ba2d8 Iustin Pop
  if not options:
1600 293ba2d8 Iustin Pop
    return
1601 293ba2d8 Iustin Pop
  for op in opcode_list:
1602 293ba2d8 Iustin Pop
    op.dry_run = options.dry_run
1603 293ba2d8 Iustin Pop
    op.debug_level = options.debug
1604 94428652 Iustin Pop
1605 94428652 Iustin Pop
1606 af30b2fd Michael Hanselmann
def GetClient():
1607 af30b2fd Michael Hanselmann
  # TODO: Cache object?
1608 b33e986b Iustin Pop
  try:
1609 b33e986b Iustin Pop
    client = luxi.Client()
1610 b33e986b Iustin Pop
  except luxi.NoMasterError:
1611 d9a51679 Michael Hanselmann
    ss = ssconf.SimpleStore()
1612 d9a51679 Michael Hanselmann
1613 d9a51679 Michael Hanselmann
    # Try to read ssconf file
1614 d9a51679 Michael Hanselmann
    try:
1615 d9a51679 Michael Hanselmann
      ss.GetMasterNode()
1616 d9a51679 Michael Hanselmann
    except errors.ConfigurationError:
1617 d9a51679 Michael Hanselmann
      raise errors.OpPrereqError("Cluster not initialized or this machine is"
1618 d9a51679 Michael Hanselmann
                                 " not part of a cluster")
1619 d9a51679 Michael Hanselmann
1620 d9a51679 Michael Hanselmann
    master, myself = ssconf.GetMasterAndMyself(ss=ss)
1621 b33e986b Iustin Pop
    if master != myself:
1622 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
1623 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
1624 b33e986b Iustin Pop
                                 master)
1625 d9a51679 Michael Hanselmann
    raise
1626 b33e986b Iustin Pop
  return client
1627 af30b2fd Michael Hanselmann
1628 af30b2fd Michael Hanselmann
1629 73702ee7 Iustin Pop
def FormatError(err):
1630 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
1631 73702ee7 Iustin Pop

1632 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
1633 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
1634 73702ee7 Iustin Pop
  second, a string describing the error message (not
1635 73702ee7 Iustin Pop
  newline-terminated).
1636 73702ee7 Iustin Pop

1637 73702ee7 Iustin Pop
  """
1638 73702ee7 Iustin Pop
  retcode = 1
1639 73702ee7 Iustin Pop
  obuf = StringIO()
1640 e2e521d0 Iustin Pop
  msg = str(err)
1641 73702ee7 Iustin Pop
  if isinstance(err, errors.ConfigurationError):
1642 e2e521d0 Iustin Pop
    txt = "Corrupt configuration file: %s" % msg
1643 46fbdd04 Iustin Pop
    logging.error(txt)
1644 e2e521d0 Iustin Pop
    obuf.write(txt + "\n")
1645 73702ee7 Iustin Pop
    obuf.write("Aborting.")
1646 73702ee7 Iustin Pop
    retcode = 2
1647 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksAbort):
1648 73702ee7 Iustin Pop
    obuf.write("Failure: hooks execution failed:\n")
1649 73702ee7 Iustin Pop
    for node, script, out in err.args[0]:
1650 73702ee7 Iustin Pop
      if out:
1651 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s, output: %s\n" %
1652 73702ee7 Iustin Pop
                   (node, script, out))
1653 73702ee7 Iustin Pop
      else:
1654 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s (no output)\n" %
1655 73702ee7 Iustin Pop
                   (node, script))
1656 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksFailure):
1657 e2e521d0 Iustin Pop
    obuf.write("Failure: hooks general failure: %s" % msg)
1658 73702ee7 Iustin Pop
  elif isinstance(err, errors.ResolverError):
1659 b705c7a6 Manuel Franceschini
    this_host = netutils.Hostname.GetSysName()
1660 73702ee7 Iustin Pop
    if err.args[0] == this_host:
1661 73702ee7 Iustin Pop
      msg = "Failure: can't resolve my own hostname ('%s')"
1662 73702ee7 Iustin Pop
    else:
1663 73702ee7 Iustin Pop
      msg = "Failure: can't resolve hostname '%s'"
1664 73702ee7 Iustin Pop
    obuf.write(msg % err.args[0])
1665 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpPrereqError):
1666 5c983ee5 Iustin Pop
    if len(err.args) == 2:
1667 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
1668 5c983ee5 Iustin Pop
               " operation:\nerror type: %s, error details:\n%s" %
1669 5c983ee5 Iustin Pop
                 (err.args[1], err.args[0]))
1670 5c983ee5 Iustin Pop
    else:
1671 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
1672 5c983ee5 Iustin Pop
                 " operation:\n%s" % msg)
1673 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpExecError):
1674 e2e521d0 Iustin Pop
    obuf.write("Failure: command execution error:\n%s" % msg)
1675 73702ee7 Iustin Pop
  elif isinstance(err, errors.TagError):
1676 e2e521d0 Iustin Pop
    obuf.write("Failure: invalid tag(s) given:\n%s" % msg)
1677 686d7433 Iustin Pop
  elif isinstance(err, errors.JobQueueDrainError):
1678 686d7433 Iustin Pop
    obuf.write("Failure: the job queue is marked for drain and doesn't"
1679 686d7433 Iustin Pop
               " accept new requests\n")
1680 f87b405e Michael Hanselmann
  elif isinstance(err, errors.JobQueueFull):
1681 f87b405e Michael Hanselmann
    obuf.write("Failure: the job queue is full and doesn't accept new"
1682 f87b405e Michael Hanselmann
               " job submissions until old jobs are archived\n")
1683 a5728081 Guido Trotter
  elif isinstance(err, errors.TypeEnforcementError):
1684 a5728081 Guido Trotter
    obuf.write("Parameter Error: %s" % msg)
1685 c1ce76bb Iustin Pop
  elif isinstance(err, errors.ParameterError):
1686 c1ce76bb Iustin Pop
    obuf.write("Failure: unknown/wrong parameter name '%s'" % msg)
1687 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.NoMasterError):
1688 03a8dbdc Iustin Pop
    obuf.write("Cannot communicate with the master daemon.\nIs it running"
1689 082c5adb Michael Hanselmann
               " and listening for connections?")
1690 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.TimeoutError):
1691 03a8dbdc Iustin Pop
    obuf.write("Timeout while talking to the master daemon. Error:\n"
1692 03a8dbdc Iustin Pop
               "%s" % msg)
1693 5a1c22fe Iustin Pop
  elif isinstance(err, luxi.PermissionError):
1694 5a1c22fe Iustin Pop
    obuf.write("It seems you don't have permissions to connect to the"
1695 5a1c22fe Iustin Pop
               " master daemon.\nPlease retry as a different user.")
1696 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.ProtocolError):
1697 03a8dbdc Iustin Pop
    obuf.write("Unhandled protocol error while talking to the master daemon:\n"
1698 03a8dbdc Iustin Pop
               "%s" % msg)
1699 91c622a8 Iustin Pop
  elif isinstance(err, errors.JobLost):
1700 91c622a8 Iustin Pop
    obuf.write("Error checking job status: %s" % msg)
1701 797506fc Michael Hanselmann
  elif isinstance(err, errors.GenericError):
1702 797506fc Michael Hanselmann
    obuf.write("Unhandled Ganeti error: %s" % msg)
1703 e9d741b6 Iustin Pop
  elif isinstance(err, JobSubmittedException):
1704 e9d741b6 Iustin Pop
    obuf.write("JobID: %s\n" % err.args[0])
1705 e9d741b6 Iustin Pop
    retcode = 0
1706 73702ee7 Iustin Pop
  else:
1707 e2e521d0 Iustin Pop
    obuf.write("Unhandled exception: %s" % msg)
1708 73702ee7 Iustin Pop
  return retcode, obuf.getvalue().rstrip('\n')
1709 73702ee7 Iustin Pop
1710 73702ee7 Iustin Pop
1711 de47cf8f Guido Trotter
def GenericMain(commands, override=None, aliases=None):
1712 a8083063 Iustin Pop
  """Generic main function for all the gnt-* commands.
1713 a8083063 Iustin Pop

1714 334d1483 Iustin Pop
  Arguments:
1715 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
1716 334d1483 Iustin Pop
                for command line handling.
1717 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
1718 334d1483 Iustin Pop
                override command line options; this can be used to pass
1719 334d1483 Iustin Pop
                options from the scripts to generic functions
1720 de47cf8f Guido Trotter
    - aliases: dictionary with command aliases {'alias': 'target, ...}
1721 a8083063 Iustin Pop

1722 a8083063 Iustin Pop
  """
1723 a8083063 Iustin Pop
  # save the program name and the entire command line for later logging
1724 a8083063 Iustin Pop
  if sys.argv:
1725 a8083063 Iustin Pop
    binary = os.path.basename(sys.argv[0]) or sys.argv[0]
1726 a8083063 Iustin Pop
    if len(sys.argv) >= 2:
1727 a8083063 Iustin Pop
      binary += " " + sys.argv[1]
1728 a8083063 Iustin Pop
      old_cmdline = " ".join(sys.argv[2:])
1729 a8083063 Iustin Pop
    else:
1730 a8083063 Iustin Pop
      old_cmdline = ""
1731 a8083063 Iustin Pop
  else:
1732 a8083063 Iustin Pop
    binary = "<unknown program>"
1733 a8083063 Iustin Pop
    old_cmdline = ""
1734 a8083063 Iustin Pop
1735 de47cf8f Guido Trotter
  if aliases is None:
1736 de47cf8f Guido Trotter
    aliases = {}
1737 de47cf8f Guido Trotter
1738 3126878d Guido Trotter
  try:
1739 3126878d Guido Trotter
    func, options, args = _ParseArgs(sys.argv, commands, aliases)
1740 3126878d Guido Trotter
  except errors.ParameterError, err:
1741 3126878d Guido Trotter
    result, err_msg = FormatError(err)
1742 3126878d Guido Trotter
    ToStderr(err_msg)
1743 3126878d Guido Trotter
    return 1
1744 3126878d Guido Trotter
1745 a8083063 Iustin Pop
  if func is None: # parse error
1746 a8083063 Iustin Pop
    return 1
1747 a8083063 Iustin Pop
1748 334d1483 Iustin Pop
  if override is not None:
1749 334d1483 Iustin Pop
    for key, val in override.iteritems():
1750 334d1483 Iustin Pop
      setattr(options, key, val)
1751 334d1483 Iustin Pop
1752 82d9caef Iustin Pop
  utils.SetupLogging(constants.LOG_COMMANDS, debug=options.debug,
1753 82d9caef Iustin Pop
                     stderr_logging=True, program=binary)
1754 a8083063 Iustin Pop
1755 a8083063 Iustin Pop
  if old_cmdline:
1756 46fbdd04 Iustin Pop
    logging.info("run with arguments '%s'", old_cmdline)
1757 a8083063 Iustin Pop
  else:
1758 46fbdd04 Iustin Pop
    logging.info("run with no arguments")
1759 a8083063 Iustin Pop
1760 a8083063 Iustin Pop
  try:
1761 a4af651e Iustin Pop
    result = func(options, args)
1762 d8353c3a Iustin Pop
  except (errors.GenericError, luxi.ProtocolError,
1763 d8353c3a Iustin Pop
          JobSubmittedException), err:
1764 a4af651e Iustin Pop
    result, err_msg = FormatError(err)
1765 5bbd3f7f Michael Hanselmann
    logging.exception("Error during command processing")
1766 46fbdd04 Iustin Pop
    ToStderr(err_msg)
1767 a8083063 Iustin Pop
1768 a8083063 Iustin Pop
  return result
1769 137161c9 Michael Hanselmann
1770 137161c9 Michael Hanselmann
1771 d77490c5 Iustin Pop
def GenericInstanceCreate(mode, opts, args):
1772 d77490c5 Iustin Pop
  """Add an instance to the cluster via either creation or import.
1773 d77490c5 Iustin Pop

1774 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
1775 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
1776 d77490c5 Iustin Pop
  @type args: list
1777 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
1778 d77490c5 Iustin Pop
  @rtype: int
1779 d77490c5 Iustin Pop
  @return: the desired exit code
1780 d77490c5 Iustin Pop

1781 d77490c5 Iustin Pop
  """
1782 d77490c5 Iustin Pop
  instance = args[0]
1783 d77490c5 Iustin Pop
1784 d77490c5 Iustin Pop
  (pnode, snode) = SplitNodeOption(opts.node)
1785 d77490c5 Iustin Pop
1786 d77490c5 Iustin Pop
  hypervisor = None
1787 d77490c5 Iustin Pop
  hvparams = {}
1788 d77490c5 Iustin Pop
  if opts.hypervisor:
1789 d77490c5 Iustin Pop
    hypervisor, hvparams = opts.hypervisor
1790 d77490c5 Iustin Pop
1791 d77490c5 Iustin Pop
  if opts.nics:
1792 d77490c5 Iustin Pop
    try:
1793 21bcb9aa Michael Hanselmann
      nic_max = max(int(nidx[0]) + 1 for nidx in opts.nics)
1794 d77490c5 Iustin Pop
    except ValueError, err:
1795 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Invalid NIC index passed: %s" % str(err))
1796 d77490c5 Iustin Pop
    nics = [{}] * nic_max
1797 d77490c5 Iustin Pop
    for nidx, ndict in opts.nics:
1798 d77490c5 Iustin Pop
      nidx = int(nidx)
1799 d77490c5 Iustin Pop
      if not isinstance(ndict, dict):
1800 d77490c5 Iustin Pop
        msg = "Invalid nic/%d value: expected dict, got %s" % (nidx, ndict)
1801 d77490c5 Iustin Pop
        raise errors.OpPrereqError(msg)
1802 d77490c5 Iustin Pop
      nics[nidx] = ndict
1803 d77490c5 Iustin Pop
  elif opts.no_nics:
1804 d77490c5 Iustin Pop
    # no nics
1805 d77490c5 Iustin Pop
    nics = []
1806 0af0f641 Iustin Pop
  elif mode == constants.INSTANCE_CREATE:
1807 d77490c5 Iustin Pop
    # default of one nic, all auto
1808 d77490c5 Iustin Pop
    nics = [{}]
1809 0af0f641 Iustin Pop
  else:
1810 0af0f641 Iustin Pop
    # mode == import
1811 0af0f641 Iustin Pop
    nics = []
1812 d77490c5 Iustin Pop
1813 d77490c5 Iustin Pop
  if opts.disk_template == constants.DT_DISKLESS:
1814 d77490c5 Iustin Pop
    if opts.disks or opts.sd_size is not None:
1815 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Diskless instance but disk"
1816 d77490c5 Iustin Pop
                                 " information passed")
1817 d77490c5 Iustin Pop
    disks = []
1818 d77490c5 Iustin Pop
  else:
1819 9b12ed0f Iustin Pop
    if (not opts.disks and not opts.sd_size
1820 9b12ed0f Iustin Pop
        and mode == constants.INSTANCE_CREATE):
1821 d77490c5 Iustin Pop
      raise errors.OpPrereqError("No disk information specified")
1822 d77490c5 Iustin Pop
    if opts.disks and opts.sd_size is not None:
1823 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Please use either the '--disk' or"
1824 d77490c5 Iustin Pop
                                 " '-s' option")
1825 d77490c5 Iustin Pop
    if opts.sd_size is not None:
1826 d77490c5 Iustin Pop
      opts.disks = [(0, {"size": opts.sd_size})]
1827 9b12ed0f Iustin Pop
1828 9b12ed0f Iustin Pop
    if opts.disks:
1829 9b12ed0f Iustin Pop
      try:
1830 9b12ed0f Iustin Pop
        disk_max = max(int(didx[0]) + 1 for didx in opts.disks)
1831 9b12ed0f Iustin Pop
      except ValueError, err:
1832 9b12ed0f Iustin Pop
        raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err))
1833 9b12ed0f Iustin Pop
      disks = [{}] * disk_max
1834 9b12ed0f Iustin Pop
    else:
1835 9b12ed0f Iustin Pop
      disks = []
1836 d77490c5 Iustin Pop
    for didx, ddict in opts.disks:
1837 d77490c5 Iustin Pop
      didx = int(didx)
1838 d77490c5 Iustin Pop
      if not isinstance(ddict, dict):
1839 d77490c5 Iustin Pop
        msg = "Invalid disk/%d value: expected dict, got %s" % (didx, ddict)
1840 d77490c5 Iustin Pop
        raise errors.OpPrereqError(msg)
1841 5029db65 Iustin Pop
      elif "size" in ddict:
1842 5029db65 Iustin Pop
        if "adopt" in ddict:
1843 5029db65 Iustin Pop
          raise errors.OpPrereqError("Only one of 'size' and 'adopt' allowed"
1844 5029db65 Iustin Pop
                                     " (disk %d)" % didx)
1845 5029db65 Iustin Pop
        try:
1846 5029db65 Iustin Pop
          ddict["size"] = utils.ParseUnit(ddict["size"])
1847 5029db65 Iustin Pop
        except ValueError, err:
1848 5029db65 Iustin Pop
          raise errors.OpPrereqError("Invalid disk size for disk %d: %s" %
1849 5029db65 Iustin Pop
                                     (didx, err))
1850 5029db65 Iustin Pop
      elif "adopt" in ddict:
1851 5029db65 Iustin Pop
        if mode == constants.INSTANCE_IMPORT:
1852 5029db65 Iustin Pop
          raise errors.OpPrereqError("Disk adoption not allowed for instance"
1853 5029db65 Iustin Pop
                                     " import")
1854 5029db65 Iustin Pop
        ddict["size"] = 0
1855 5029db65 Iustin Pop
      else:
1856 5029db65 Iustin Pop
        raise errors.OpPrereqError("Missing size or adoption source for"
1857 5029db65 Iustin Pop
                                   " disk %d" % didx)
1858 d77490c5 Iustin Pop
      disks[didx] = ddict
1859 d77490c5 Iustin Pop
1860 d77490c5 Iustin Pop
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_TYPES)
1861 d77490c5 Iustin Pop
  utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
1862 d77490c5 Iustin Pop
1863 d77490c5 Iustin Pop
  if mode == constants.INSTANCE_CREATE:
1864 d77490c5 Iustin Pop
    start = opts.start
1865 d77490c5 Iustin Pop
    os_type = opts.os
1866 1ee8e01a Guido Trotter
    force_variant = opts.force_variant
1867 d77490c5 Iustin Pop
    src_node = None
1868 d77490c5 Iustin Pop
    src_path = None
1869 25a8792c Iustin Pop
    no_install = opts.no_install
1870 e588764d Iustin Pop
    identify_defaults = False
1871 d77490c5 Iustin Pop
  elif mode == constants.INSTANCE_IMPORT:
1872 d77490c5 Iustin Pop
    start = False
1873 d77490c5 Iustin Pop
    os_type = None
1874 1ee8e01a Guido Trotter
    force_variant = False
1875 d77490c5 Iustin Pop
    src_node = opts.src_node
1876 d77490c5 Iustin Pop
    src_path = opts.src_dir
1877 25a8792c Iustin Pop
    no_install = None
1878 e588764d Iustin Pop
    identify_defaults = opts.identify_defaults
1879 d77490c5 Iustin Pop
  else:
1880 d77490c5 Iustin Pop
    raise errors.ProgrammerError("Invalid creation mode %s" % mode)
1881 d77490c5 Iustin Pop
1882 d77490c5 Iustin Pop
  op = opcodes.OpCreateInstance(instance_name=instance,
1883 d77490c5 Iustin Pop
                                disks=disks,
1884 d77490c5 Iustin Pop
                                disk_template=opts.disk_template,
1885 d77490c5 Iustin Pop
                                nics=nics,
1886 d77490c5 Iustin Pop
                                pnode=pnode, snode=snode,
1887 d77490c5 Iustin Pop
                                ip_check=opts.ip_check,
1888 460d22be Iustin Pop
                                name_check=opts.name_check,
1889 d77490c5 Iustin Pop
                                wait_for_sync=opts.wait_for_sync,
1890 d77490c5 Iustin Pop
                                file_storage_dir=opts.file_storage_dir,
1891 d77490c5 Iustin Pop
                                file_driver=opts.file_driver,
1892 d77490c5 Iustin Pop
                                iallocator=opts.iallocator,
1893 d77490c5 Iustin Pop
                                hypervisor=hypervisor,
1894 d77490c5 Iustin Pop
                                hvparams=hvparams,
1895 d77490c5 Iustin Pop
                                beparams=opts.beparams,
1896 062a7100 Iustin Pop
                                osparams=opts.osparams,
1897 d77490c5 Iustin Pop
                                mode=mode,
1898 d77490c5 Iustin Pop
                                start=start,
1899 d77490c5 Iustin Pop
                                os_type=os_type,
1900 1ee8e01a Guido Trotter
                                force_variant=force_variant,
1901 d77490c5 Iustin Pop
                                src_node=src_node,
1902 25a8792c Iustin Pop
                                src_path=src_path,
1903 e588764d Iustin Pop
                                no_install=no_install,
1904 e588764d Iustin Pop
                                identify_defaults=identify_defaults)
1905 d77490c5 Iustin Pop
1906 d77490c5 Iustin Pop
  SubmitOrSend(op, opts)
1907 d77490c5 Iustin Pop
  return 0
1908 d77490c5 Iustin Pop
1909 d77490c5 Iustin Pop
1910 7e49b6ce Michael Hanselmann
class _RunWhileClusterStoppedHelper:
1911 7e49b6ce Michael Hanselmann
  """Helper class for L{RunWhileClusterStopped} to simplify state management
1912 7e49b6ce Michael Hanselmann

1913 7e49b6ce Michael Hanselmann
  """
1914 7e49b6ce Michael Hanselmann
  def __init__(self, feedback_fn, cluster_name, master_node, online_nodes):
1915 7e49b6ce Michael Hanselmann
    """Initializes this class.
1916 7e49b6ce Michael Hanselmann

1917 7e49b6ce Michael Hanselmann
    @type feedback_fn: callable
1918 7e49b6ce Michael Hanselmann
    @param feedback_fn: Feedback function
1919 7e49b6ce Michael Hanselmann
    @type cluster_name: string
1920 7e49b6ce Michael Hanselmann
    @param cluster_name: Cluster name
1921 7e49b6ce Michael Hanselmann
    @type master_node: string
1922 7e49b6ce Michael Hanselmann
    @param master_node Master node name
1923 7e49b6ce Michael Hanselmann
    @type online_nodes: list
1924 7e49b6ce Michael Hanselmann
    @param online_nodes: List of names of online nodes
1925 7e49b6ce Michael Hanselmann

1926 7e49b6ce Michael Hanselmann
    """
1927 7e49b6ce Michael Hanselmann
    self.feedback_fn = feedback_fn
1928 7e49b6ce Michael Hanselmann
    self.cluster_name = cluster_name
1929 7e49b6ce Michael Hanselmann
    self.master_node = master_node
1930 7e49b6ce Michael Hanselmann
    self.online_nodes = online_nodes
1931 7e49b6ce Michael Hanselmann
1932 7e49b6ce Michael Hanselmann
    self.ssh = ssh.SshRunner(self.cluster_name)
1933 7e49b6ce Michael Hanselmann
1934 7e49b6ce Michael Hanselmann
    self.nonmaster_nodes = [name for name in online_nodes
1935 7e49b6ce Michael Hanselmann
                            if name != master_node]
1936 7e49b6ce Michael Hanselmann
1937 7e49b6ce Michael Hanselmann
    assert self.master_node not in self.nonmaster_nodes
1938 7e49b6ce Michael Hanselmann
1939 7e49b6ce Michael Hanselmann
  def _RunCmd(self, node_name, cmd):
1940 7e49b6ce Michael Hanselmann
    """Runs a command on the local or a remote machine.
1941 7e49b6ce Michael Hanselmann

1942 7e49b6ce Michael Hanselmann
    @type node_name: string
1943 7e49b6ce Michael Hanselmann
    @param node_name: Machine name
1944 7e49b6ce Michael Hanselmann
    @type cmd: list
1945 7e49b6ce Michael Hanselmann
    @param cmd: Command
1946 7e49b6ce Michael Hanselmann

1947 7e49b6ce Michael Hanselmann
    """
1948 7e49b6ce Michael Hanselmann
    if node_name is None or node_name == self.master_node:
1949 7e49b6ce Michael Hanselmann
      # No need to use SSH
1950 7e49b6ce Michael Hanselmann
      result = utils.RunCmd(cmd)
1951 7e49b6ce Michael Hanselmann
    else:
1952 7e49b6ce Michael Hanselmann
      result = self.ssh.Run(node_name, "root", utils.ShellQuoteArgs(cmd))
1953 7e49b6ce Michael Hanselmann
1954 7e49b6ce Michael Hanselmann
    if result.failed:
1955 7e49b6ce Michael Hanselmann
      errmsg = ["Failed to run command %s" % result.cmd]
1956 7e49b6ce Michael Hanselmann
      if node_name:
1957 7e49b6ce Michael Hanselmann
        errmsg.append("on node %s" % node_name)
1958 7e49b6ce Michael Hanselmann
      errmsg.append(": exitcode %s and error %s" %
1959 7e49b6ce Michael Hanselmann
                    (result.exit_code, result.output))
1960 7e49b6ce Michael Hanselmann
      raise errors.OpExecError(" ".join(errmsg))
1961 7e49b6ce Michael Hanselmann
1962 7e49b6ce Michael Hanselmann
  def Call(self, fn, *args):
1963 7e49b6ce Michael Hanselmann
    """Call function while all daemons are stopped.
1964 7e49b6ce Michael Hanselmann

1965 7e49b6ce Michael Hanselmann
    @type fn: callable
1966 7e49b6ce Michael Hanselmann
    @param fn: Function to be called
1967 7e49b6ce Michael Hanselmann

1968 7e49b6ce Michael Hanselmann
    """
1969 7e49b6ce Michael Hanselmann
    # Pause watcher by acquiring an exclusive lock on watcher state file
1970 7e49b6ce Michael Hanselmann
    self.feedback_fn("Blocking watcher")
1971 7e49b6ce Michael Hanselmann
    watcher_block = utils.FileLock.Open(constants.WATCHER_STATEFILE)
1972 7e49b6ce Michael Hanselmann
    try:
1973 7e49b6ce Michael Hanselmann
      # TODO: Currently, this just blocks. There's no timeout.
1974 7e49b6ce Michael Hanselmann
      # TODO: Should it be a shared lock?
1975 7e49b6ce Michael Hanselmann
      watcher_block.Exclusive(blocking=True)
1976 7e49b6ce Michael Hanselmann
1977 7e49b6ce Michael Hanselmann
      # Stop master daemons, so that no new jobs can come in and all running
1978 7e49b6ce Michael Hanselmann
      # ones are finished
1979 7e49b6ce Michael Hanselmann
      self.feedback_fn("Stopping master daemons")
1980 7e49b6ce Michael Hanselmann
      self._RunCmd(None, [constants.DAEMON_UTIL, "stop-master"])
1981 7e49b6ce Michael Hanselmann
      try:
1982 7e49b6ce Michael Hanselmann
        # Stop daemons on all nodes
1983 7e49b6ce Michael Hanselmann
        for node_name in self.online_nodes:
1984 7e49b6ce Michael Hanselmann
          self.feedback_fn("Stopping daemons on %s" % node_name)
1985 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "stop-all"])
1986 7e49b6ce Michael Hanselmann
1987 7e49b6ce Michael Hanselmann
        # All daemons are shut down now
1988 7e49b6ce Michael Hanselmann
        try:
1989 7e49b6ce Michael Hanselmann
          return fn(self, *args)
1990 d512e84b Michael Hanselmann
        except Exception, err:
1991 d512e84b Michael Hanselmann
          _, errmsg = FormatError(err)
1992 7e49b6ce Michael Hanselmann
          logging.exception("Caught exception")
1993 d512e84b Michael Hanselmann
          self.feedback_fn(errmsg)
1994 7e49b6ce Michael Hanselmann
          raise
1995 7e49b6ce Michael Hanselmann
      finally:
1996 7e49b6ce Michael Hanselmann
        # Start cluster again, master node last
1997 7e49b6ce Michael Hanselmann
        for node_name in self.nonmaster_nodes + [self.master_node]:
1998 7e49b6ce Michael Hanselmann
          self.feedback_fn("Starting daemons on %s" % node_name)
1999 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "start-all"])
2000 7e49b6ce Michael Hanselmann
    finally:
2001 7e49b6ce Michael Hanselmann
      # Resume watcher
2002 7e49b6ce Michael Hanselmann
      watcher_block.Close()
2003 7e49b6ce Michael Hanselmann
2004 7e49b6ce Michael Hanselmann
2005 7e49b6ce Michael Hanselmann
def RunWhileClusterStopped(feedback_fn, fn, *args):
2006 7e49b6ce Michael Hanselmann
  """Calls a function while all cluster daemons are stopped.
2007 7e49b6ce Michael Hanselmann

2008 7e49b6ce Michael Hanselmann
  @type feedback_fn: callable
2009 7e49b6ce Michael Hanselmann
  @param feedback_fn: Feedback function
2010 7e49b6ce Michael Hanselmann
  @type fn: callable
2011 7e49b6ce Michael Hanselmann
  @param fn: Function to be called when daemons are stopped
2012 7e49b6ce Michael Hanselmann

2013 7e49b6ce Michael Hanselmann
  """
2014 7e49b6ce Michael Hanselmann
  feedback_fn("Gathering cluster information")
2015 7e49b6ce Michael Hanselmann
2016 7e49b6ce Michael Hanselmann
  # This ensures we're running on the master daemon
2017 7e49b6ce Michael Hanselmann
  cl = GetClient()
2018 7e49b6ce Michael Hanselmann
2019 7e49b6ce Michael Hanselmann
  (cluster_name, master_node) = \
2020 7e49b6ce Michael Hanselmann
    cl.QueryConfigValues(["cluster_name", "master_node"])
2021 7e49b6ce Michael Hanselmann
2022 7e49b6ce Michael Hanselmann
  online_nodes = GetOnlineNodes([], cl=cl)
2023 7e49b6ce Michael Hanselmann
2024 7e49b6ce Michael Hanselmann
  # Don't keep a reference to the client. The master daemon will go away.
2025 7e49b6ce Michael Hanselmann
  del cl
2026 7e49b6ce Michael Hanselmann
2027 7e49b6ce Michael Hanselmann
  assert master_node in online_nodes
2028 7e49b6ce Michael Hanselmann
2029 7e49b6ce Michael Hanselmann
  return _RunWhileClusterStoppedHelper(feedback_fn, cluster_name, master_node,
2030 7e49b6ce Michael Hanselmann
                                       online_nodes).Call(fn, *args)
2031 7e49b6ce Michael Hanselmann
2032 7e49b6ce Michael Hanselmann
2033 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
2034 9fbfbb7b Iustin Pop
                  numfields=None, unitfields=None,
2035 9fbfbb7b Iustin Pop
                  units=None):
2036 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
2037 137161c9 Michael Hanselmann

2038 9fbfbb7b Iustin Pop
  @type headers: dict
2039 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
2040 9fbfbb7b Iustin Pop
      the table
2041 9fbfbb7b Iustin Pop
  @type fields: list
2042 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
2043 9fbfbb7b Iustin Pop
      the data field
2044 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
2045 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
2046 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
2047 9fbfbb7b Iustin Pop
      each field
2048 9fbfbb7b Iustin Pop
  @type data: list
2049 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
2050 9fbfbb7b Iustin Pop
  @type numfields: list
2051 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
2052 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
2053 9fbfbb7b Iustin Pop
  @type unitfields: list
2054 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
2055 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
2056 9fbfbb7b Iustin Pop
  @type units: string or None
2057 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
2058 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
2059 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
2060 137161c9 Michael Hanselmann

2061 137161c9 Michael Hanselmann
  """
2062 9fbfbb7b Iustin Pop
  if units is None:
2063 9fbfbb7b Iustin Pop
    if separator:
2064 9fbfbb7b Iustin Pop
      units = "m"
2065 9fbfbb7b Iustin Pop
    else:
2066 9fbfbb7b Iustin Pop
      units = "h"
2067 9fbfbb7b Iustin Pop
2068 137161c9 Michael Hanselmann
  if numfields is None:
2069 137161c9 Michael Hanselmann
    numfields = []
2070 137161c9 Michael Hanselmann
  if unitfields is None:
2071 137161c9 Michael Hanselmann
    unitfields = []
2072 137161c9 Michael Hanselmann
2073 fe267188 Iustin Pop
  numfields = utils.FieldSet(*numfields)   # pylint: disable-msg=W0142
2074 fe267188 Iustin Pop
  unitfields = utils.FieldSet(*unitfields) # pylint: disable-msg=W0142
2075 00430f8e Iustin Pop
2076 137161c9 Michael Hanselmann
  format_fields = []
2077 137161c9 Michael Hanselmann
  for field in fields:
2078 01ca31ae Iustin Pop
    if headers and field not in headers:
2079 ea5a5b74 Guido Trotter
      # TODO: handle better unknown fields (either revert to old
2080 71c1af58 Iustin Pop
      # style of raising exception, or deal more intelligently with
2081 71c1af58 Iustin Pop
      # variable fields)
2082 71c1af58 Iustin Pop
      headers[field] = field
2083 137161c9 Michael Hanselmann
    if separator is not None:
2084 137161c9 Michael Hanselmann
      format_fields.append("%s")
2085 00430f8e Iustin Pop
    elif numfields.Matches(field):
2086 137161c9 Michael Hanselmann
      format_fields.append("%*s")
2087 137161c9 Michael Hanselmann
    else:
2088 137161c9 Michael Hanselmann
      format_fields.append("%-*s")
2089 137161c9 Michael Hanselmann
2090 137161c9 Michael Hanselmann
  if separator is None:
2091 137161c9 Michael Hanselmann
    mlens = [0 for name in fields]
2092 c04bc777 Iustin Pop
    format_str = ' '.join(format_fields)
2093 137161c9 Michael Hanselmann
  else:
2094 c04bc777 Iustin Pop
    format_str = separator.replace("%", "%%").join(format_fields)
2095 137161c9 Michael Hanselmann
2096 137161c9 Michael Hanselmann
  for row in data:
2097 dcbd6288 Guido Trotter
    if row is None:
2098 dcbd6288 Guido Trotter
      continue
2099 137161c9 Michael Hanselmann
    for idx, val in enumerate(row):
2100 00430f8e Iustin Pop
      if unitfields.Matches(fields[idx]):
2101 137161c9 Michael Hanselmann
        try:
2102 137161c9 Michael Hanselmann
          val = int(val)
2103 691744c4 Iustin Pop
        except (TypeError, ValueError):
2104 137161c9 Michael Hanselmann
          pass
2105 137161c9 Michael Hanselmann
        else:
2106 9fbfbb7b Iustin Pop
          val = row[idx] = utils.FormatUnit(val, units)
2107 01ca31ae Iustin Pop
      val = row[idx] = str(val)
2108 137161c9 Michael Hanselmann
      if separator is None:
2109 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(val))
2110 137161c9 Michael Hanselmann
2111 16be8703 Iustin Pop
  result = []
2112 137161c9 Michael Hanselmann
  if headers:
2113 137161c9 Michael Hanselmann
    args = []
2114 137161c9 Michael Hanselmann
    for idx, name in enumerate(fields):
2115 137161c9 Michael Hanselmann
      hdr = headers[name]
2116 137161c9 Michael Hanselmann
      if separator is None:
2117 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(hdr))
2118 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2119 137161c9 Michael Hanselmann
      args.append(hdr)
2120 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2121 137161c9 Michael Hanselmann
2122 ec39d63c Michael Hanselmann
  if separator is None:
2123 ec39d63c Michael Hanselmann
    assert len(mlens) == len(fields)
2124 ec39d63c Michael Hanselmann
2125 ec39d63c Michael Hanselmann
    if fields and not numfields.Matches(fields[-1]):
2126 ec39d63c Michael Hanselmann
      mlens[-1] = 0
2127 ec39d63c Michael Hanselmann
2128 137161c9 Michael Hanselmann
  for line in data:
2129 137161c9 Michael Hanselmann
    args = []
2130 dcbd6288 Guido Trotter
    if line is None:
2131 dcbd6288 Guido Trotter
      line = ['-' for _ in fields]
2132 f1501b3f Michael Hanselmann
    for idx in range(len(fields)):
2133 137161c9 Michael Hanselmann
      if separator is None:
2134 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2135 137161c9 Michael Hanselmann
      args.append(line[idx])
2136 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2137 16be8703 Iustin Pop
2138 16be8703 Iustin Pop
  return result
2139 3386e7a9 Iustin Pop
2140 3386e7a9 Iustin Pop
2141 3386e7a9 Iustin Pop
def FormatTimestamp(ts):
2142 3386e7a9 Iustin Pop
  """Formats a given timestamp.
2143 3386e7a9 Iustin Pop

2144 3386e7a9 Iustin Pop
  @type ts: timestamp
2145 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
2146 3386e7a9 Iustin Pop

2147 3386e7a9 Iustin Pop
  @rtype: string
2148 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
2149 3386e7a9 Iustin Pop

2150 3386e7a9 Iustin Pop
  """
2151 e0ec0ff6 Iustin Pop
  if not isinstance (ts, (tuple, list)) or len(ts) != 2:
2152 e0ec0ff6 Iustin Pop
    return '?'
2153 3386e7a9 Iustin Pop
  sec, usec = ts
2154 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
2155 2241e2b9 Iustin Pop
2156 2241e2b9 Iustin Pop
2157 2241e2b9 Iustin Pop
def ParseTimespec(value):
2158 2241e2b9 Iustin Pop
  """Parse a time specification.
2159 2241e2b9 Iustin Pop

2160 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
2161 2241e2b9 Iustin Pop

2162 2241e2b9 Iustin Pop
    - s: seconds
2163 2241e2b9 Iustin Pop
    - m: minutes
2164 2241e2b9 Iustin Pop
    - h: hours
2165 2241e2b9 Iustin Pop
    - d: day
2166 2241e2b9 Iustin Pop
    - w: weeks
2167 2241e2b9 Iustin Pop

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

2170 2241e2b9 Iustin Pop
  """
2171 2241e2b9 Iustin Pop
  value = str(value)
2172 2241e2b9 Iustin Pop
  if not value:
2173 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
2174 2241e2b9 Iustin Pop
  suffix_map = {
2175 2241e2b9 Iustin Pop
    's': 1,
2176 2241e2b9 Iustin Pop
    'm': 60,
2177 2241e2b9 Iustin Pop
    'h': 3600,
2178 2241e2b9 Iustin Pop
    'd': 86400,
2179 2241e2b9 Iustin Pop
    'w': 604800,
2180 2241e2b9 Iustin Pop
    }
2181 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
2182 2241e2b9 Iustin Pop
    try:
2183 2241e2b9 Iustin Pop
      value = int(value)
2184 691744c4 Iustin Pop
    except (TypeError, ValueError):
2185 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2186 2241e2b9 Iustin Pop
  else:
2187 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
2188 2241e2b9 Iustin Pop
    value = value[:-1]
2189 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
2190 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
2191 2241e2b9 Iustin Pop
                                 " suffix passed)")
2192 2241e2b9 Iustin Pop
    try:
2193 2241e2b9 Iustin Pop
      value = int(value) * multiplier
2194 691744c4 Iustin Pop
    except (TypeError, ValueError):
2195 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2196 2241e2b9 Iustin Pop
  return value
2197 46fbdd04 Iustin Pop
2198 46fbdd04 Iustin Pop
2199 e9e26bb3 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False, secondary_ips=False,
2200 e9e26bb3 Iustin Pop
                   filter_master=False):
2201 4040a784 Iustin Pop
  """Returns the names of online nodes.
2202 4040a784 Iustin Pop

2203 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
2204 4040a784 Iustin Pop
  the online nodes.
2205 4040a784 Iustin Pop

2206 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
2207 4040a784 Iustin Pop
      offline ones)
2208 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
2209 4040a784 Iustin Pop
  @type nowarn: boolean
2210 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
2211 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
2212 4040a784 Iustin Pop
      note is not displayed
2213 e9e26bb3 Iustin Pop
  @type secondary_ips: boolean
2214 e9e26bb3 Iustin Pop
  @param secondary_ips: if True, return the secondary IPs instead of the
2215 e9e26bb3 Iustin Pop
      names, useful for doing network traffic over the replication interface
2216 e9e26bb3 Iustin Pop
      (if any)
2217 e9e26bb3 Iustin Pop
  @type filter_master: boolean
2218 e9e26bb3 Iustin Pop
  @param filter_master: if True, do not return the master node in the list
2219 e9e26bb3 Iustin Pop
      (useful in coordination with secondary_ips where we cannot check our
2220 e9e26bb3 Iustin Pop
      node name against the list)
2221 4040a784 Iustin Pop

2222 4040a784 Iustin Pop
  """
2223 4040a784 Iustin Pop
  if cl is None:
2224 4040a784 Iustin Pop
    cl = GetClient()
2225 4040a784 Iustin Pop
2226 e9e26bb3 Iustin Pop
  if secondary_ips:
2227 e9e26bb3 Iustin Pop
    name_idx = 2
2228 e9e26bb3 Iustin Pop
  else:
2229 e9e26bb3 Iustin Pop
    name_idx = 0
2230 e9e26bb3 Iustin Pop
2231 e9e26bb3 Iustin Pop
  if filter_master:
2232 e9e26bb3 Iustin Pop
    master_node = cl.QueryConfigValues(["master_node"])[0]
2233 e9e26bb3 Iustin Pop
    filter_fn = lambda x: x != master_node
2234 e9e26bb3 Iustin Pop
  else:
2235 e9e26bb3 Iustin Pop
    filter_fn = lambda _: True
2236 e9e26bb3 Iustin Pop
2237 e9e26bb3 Iustin Pop
  result = cl.QueryNodes(names=nodes, fields=["name", "offline", "sip"],
2238 2e7b8369 Iustin Pop
                         use_locking=False)
2239 4040a784 Iustin Pop
  offline = [row[0] for row in result if row[1]]
2240 4040a784 Iustin Pop
  if offline and not nowarn:
2241 1f864b60 Iustin Pop
    ToStderr("Note: skipping offline node(s): %s" % utils.CommaJoin(offline))
2242 e9e26bb3 Iustin Pop
  return [row[name_idx] for row in result if not row[1] and filter_fn(row[0])]
2243 4040a784 Iustin Pop
2244 4040a784 Iustin Pop
2245 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
2246 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
2247 46fbdd04 Iustin Pop

2248 46fbdd04 Iustin Pop
  @type stream: file object
2249 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
2250 46fbdd04 Iustin Pop
  @type txt: str
2251 46fbdd04 Iustin Pop
  @param txt: the message
2252 46fbdd04 Iustin Pop

2253 46fbdd04 Iustin Pop
  """
2254 46fbdd04 Iustin Pop
  if args:
2255 46fbdd04 Iustin Pop
    args = tuple(args)
2256 46fbdd04 Iustin Pop
    stream.write(txt % args)
2257 46fbdd04 Iustin Pop
  else:
2258 46fbdd04 Iustin Pop
    stream.write(txt)
2259 46fbdd04 Iustin Pop
  stream.write('\n')
2260 46fbdd04 Iustin Pop
  stream.flush()
2261 46fbdd04 Iustin Pop
2262 46fbdd04 Iustin Pop
2263 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
2264 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
2265 46fbdd04 Iustin Pop

2266 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2267 46fbdd04 Iustin Pop

2268 46fbdd04 Iustin Pop
  @type txt: str
2269 46fbdd04 Iustin Pop
  @param txt: the message
2270 46fbdd04 Iustin Pop

2271 46fbdd04 Iustin Pop
  """
2272 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
2273 46fbdd04 Iustin Pop
2274 46fbdd04 Iustin Pop
2275 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
2276 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
2277 46fbdd04 Iustin Pop

2278 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2279 46fbdd04 Iustin Pop

2280 46fbdd04 Iustin Pop
  @type txt: str
2281 46fbdd04 Iustin Pop
  @param txt: the message
2282 46fbdd04 Iustin Pop

2283 46fbdd04 Iustin Pop
  """
2284 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
2285 479636a3 Iustin Pop
2286 479636a3 Iustin Pop
2287 479636a3 Iustin Pop
class JobExecutor(object):
2288 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
2289 479636a3 Iustin Pop

2290 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
2291 479636a3 Iustin Pop
  GetResults() calls.
2292 479636a3 Iustin Pop

2293 479636a3 Iustin Pop
  """
2294 919ca415 Iustin Pop
  def __init__(self, cl=None, verbose=True, opts=None, feedback_fn=None):
2295 479636a3 Iustin Pop
    self.queue = []
2296 479636a3 Iustin Pop
    if cl is None:
2297 479636a3 Iustin Pop
      cl = GetClient()
2298 479636a3 Iustin Pop
    self.cl = cl
2299 479636a3 Iustin Pop
    self.verbose = verbose
2300 23b4b983 Iustin Pop
    self.jobs = []
2301 cff5fa7f Iustin Pop
    self.opts = opts
2302 919ca415 Iustin Pop
    self.feedback_fn = feedback_fn
2303 479636a3 Iustin Pop
2304 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
2305 23b4b983 Iustin Pop
    """Record a job for later submit.
2306 479636a3 Iustin Pop

2307 479636a3 Iustin Pop
    @type name: string
2308 479636a3 Iustin Pop
    @param name: a description of the job, will be used in WaitJobSet
2309 479636a3 Iustin Pop
    """
2310 cff5fa7f Iustin Pop
    SetGenericOpcodeOpts(ops, self.opts)
2311 23b4b983 Iustin Pop
    self.queue.append((name, ops))
2312 23b4b983 Iustin Pop
2313 66ecc479 Guido Trotter
  def SubmitPending(self, each=False):
2314 23b4b983 Iustin Pop
    """Submit all pending jobs.
2315 23b4b983 Iustin Pop

2316 23b4b983 Iustin Pop
    """
2317 66ecc479 Guido Trotter
    if each:
2318 66ecc479 Guido Trotter
      results = []
2319 66ecc479 Guido Trotter
      for row in self.queue:
2320 66ecc479 Guido Trotter
        # SubmitJob will remove the success status, but raise an exception if
2321 66ecc479 Guido Trotter
        # the submission fails, so we'll notice that anyway.
2322 66ecc479 Guido Trotter
        results.append([True, self.cl.SubmitJob(row[1])])
2323 66ecc479 Guido Trotter
    else:
2324 66ecc479 Guido Trotter
      results = self.cl.SubmitManyJobs([row[1] for row in self.queue])
2325 5299e61f Iustin Pop
    for (idx, ((status, data), (name, _))) in enumerate(zip(results,
2326 5299e61f Iustin Pop
                                                            self.queue)):
2327 5299e61f Iustin Pop
      self.jobs.append((idx, status, data, name))
2328 5299e61f Iustin Pop
2329 5299e61f Iustin Pop
  def _ChooseJob(self):
2330 5299e61f Iustin Pop
    """Choose a non-waiting/queued job to poll next.
2331 5299e61f Iustin Pop

2332 5299e61f Iustin Pop
    """
2333 5299e61f Iustin Pop
    assert self.jobs, "_ChooseJob called with empty job list"
2334 5299e61f Iustin Pop
2335 5299e61f Iustin Pop
    result = self.cl.QueryJobs([i[2] for i in self.jobs], ["status"])
2336 5299e61f Iustin Pop
    assert result
2337 5299e61f Iustin Pop
2338 5299e61f Iustin Pop
    for job_data, status in zip(self.jobs, result):
2339 91c622a8 Iustin Pop
      if (isinstance(status, list) and status and
2340 91c622a8 Iustin Pop
          status[0] in (constants.JOB_STATUS_QUEUED,
2341 91c622a8 Iustin Pop
                        constants.JOB_STATUS_WAITLOCK,
2342 91c622a8 Iustin Pop
                        constants.JOB_STATUS_CANCELING)):
2343 91c622a8 Iustin Pop
        # job is still present and waiting
2344 5299e61f Iustin Pop
        continue
2345 91c622a8 Iustin Pop
      # good candidate found (either running job or lost job)
2346 5299e61f Iustin Pop
      self.jobs.remove(job_data)
2347 5299e61f Iustin Pop
      return job_data
2348 5299e61f Iustin Pop
2349 5299e61f Iustin Pop
    # no job found
2350 5299e61f Iustin Pop
    return self.jobs.pop(0)
2351 479636a3 Iustin Pop
2352 479636a3 Iustin Pop
  def GetResults(self):
2353 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
2354 479636a3 Iustin Pop

2355 479636a3 Iustin Pop
    @rtype: list
2356 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
2357 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
2358 479636a3 Iustin Pop
        there will be the error message
2359 479636a3 Iustin Pop

2360 479636a3 Iustin Pop
    """
2361 23b4b983 Iustin Pop
    if not self.jobs:
2362 23b4b983 Iustin Pop
      self.SubmitPending()
2363 479636a3 Iustin Pop
    results = []
2364 479636a3 Iustin Pop
    if self.verbose:
2365 5299e61f Iustin Pop
      ok_jobs = [row[2] for row in self.jobs if row[1]]
2366 23b4b983 Iustin Pop
      if ok_jobs:
2367 1f864b60 Iustin Pop
        ToStdout("Submitted jobs %s", utils.CommaJoin(ok_jobs))
2368 5299e61f Iustin Pop
2369 5299e61f Iustin Pop
    # first, remove any non-submitted jobs
2370 cea881e5 Michael Hanselmann
    self.jobs, failures = compat.partition(self.jobs, lambda x: x[1])
2371 5299e61f Iustin Pop
    for idx, _, jid, name in failures:
2372 c63355f2 Iustin Pop
      ToStderr("Failed to submit job for %s: %s", name, jid)
2373 c63355f2 Iustin Pop
      results.append((idx, False, jid))
2374 5299e61f Iustin Pop
2375 5299e61f Iustin Pop
    while self.jobs:
2376 5299e61f Iustin Pop
      (idx, _, jid, name) = self._ChooseJob()
2377 5299e61f Iustin Pop
      ToStdout("Waiting for job %s for %s...", jid, name)
2378 479636a3 Iustin Pop
      try:
2379 919ca415 Iustin Pop
        job_result = PollJob(jid, cl=self.cl, feedback_fn=self.feedback_fn)
2380 479636a3 Iustin Pop
        success = True
2381 91c622a8 Iustin Pop
      except errors.JobLost, err:
2382 91c622a8 Iustin Pop
        _, job_result = FormatError(err)
2383 91c622a8 Iustin Pop
        ToStderr("Job %s for %s has been archived, cannot check its result",
2384 91c622a8 Iustin Pop
                 jid, name)
2385 91c622a8 Iustin Pop
        success = False
2386 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
2387 479636a3 Iustin Pop
        _, job_result = FormatError(err)
2388 479636a3 Iustin Pop
        success = False
2389 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
2390 479636a3 Iustin Pop
        ToStderr("Job %s for %s has failed: %s", jid, name, job_result)
2391 479636a3 Iustin Pop
2392 5299e61f Iustin Pop
      results.append((idx, success, job_result))
2393 5299e61f Iustin Pop
2394 5299e61f Iustin Pop
    # sort based on the index, then drop it
2395 5299e61f Iustin Pop
    results.sort()
2396 5299e61f Iustin Pop
    results = [i[1:] for i in results]
2397 5299e61f Iustin Pop
2398 479636a3 Iustin Pop
    return results
2399 479636a3 Iustin Pop
2400 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
2401 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
2402 479636a3 Iustin Pop

2403 479636a3 Iustin Pop
    @type wait: boolean
2404 479636a3 Iustin Pop
    @param wait: whether to wait or not
2405 479636a3 Iustin Pop

2406 479636a3 Iustin Pop
    """
2407 479636a3 Iustin Pop
    if wait:
2408 479636a3 Iustin Pop
      return self.GetResults()
2409 479636a3 Iustin Pop
    else:
2410 23b4b983 Iustin Pop
      if not self.jobs:
2411 23b4b983 Iustin Pop
        self.SubmitPending()
2412 71834b2a Guido Trotter
      for _, status, result, name in self.jobs:
2413 23b4b983 Iustin Pop
        if status:
2414 23b4b983 Iustin Pop
          ToStdout("%s: %s", result, name)
2415 23b4b983 Iustin Pop
        else:
2416 23b4b983 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)
2417 53a8a54d Iustin Pop
      return [row[1:3] for row in self.jobs]