Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ 887c7aa6

History | View | Annotate | Download (79.2 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 a0a6ff34 Iustin Pop
  "DRY_RUN_OPT",
66 26591bfd Luca Bigliardi
  "DRBD_HELPER_OPT",
67 7ea7bcf6 Iustin Pop
  "EARLY_RELEASE_OPT",
68 383a3591 Iustin Pop
  "ENABLED_HV_OPT",
69 14e9e7f3 Iustin Pop
  "ERROR_CODES_OPT",
70 4abc4f1e Iustin Pop
  "FIELDS_OPT",
71 4a25828c Iustin Pop
  "FILESTORE_DIR_OPT",
72 0f87c43e Iustin Pop
  "FILESTORE_DRIVER_OPT",
73 06073e85 Guido Trotter
  "FORCE_OPT",
74 06073e85 Guido Trotter
  "FORCE_VARIANT_OPT",
75 29392516 Iustin Pop
  "GLOBAL_FILEDIR_OPT",
76 073271f6 Iustin Pop
  "HVLIST_OPT",
77 48f212d7 Iustin Pop
  "HVOPTS_OPT",
78 236fd9c4 Iustin Pop
  "HYPERVISOR_OPT",
79 4eb62659 Iustin Pop
  "IALLOCATOR_OPT",
80 bf4af505 Apollon Oikonomopoulos
  "DEFAULT_IALLOCATOR_OPT",
81 e588764d Iustin Pop
  "IDENTIFY_DEFAULTS_OPT",
82 82a786d5 Iustin Pop
  "IGNORE_CONSIST_OPT",
83 b6e841a8 Iustin Pop
  "IGNORE_FAILURES_OPT",
84 8d8d650c Michael Hanselmann
  "IGNORE_REMOVE_FAILURES_OPT",
85 ee3f9578 Iustin Pop
  "IGNORE_SECONDARIES_OPT",
86 05586c90 Iustin Pop
  "IGNORE_SIZE_OPT",
87 19b9ba9a Michael Hanselmann
  "INTERVAL_OPT",
88 e3646f22 Iustin Pop
  "MAC_PREFIX_OPT",
89 3953242f Iustin Pop
  "MAINTAIN_NODE_HEALTH_OPT",
90 29392516 Iustin Pop
  "MASTER_NETDEV_OPT",
91 771734c9 Iustin Pop
  "MC_OPT",
92 783a6c0b Iustin Pop
  "MIGRATION_MODE_OPT",
93 7d3a9fab Iustin Pop
  "NET_OPT",
94 6d4a1656 Michael Hanselmann
  "NEW_CLUSTER_CERT_OPT",
95 3db3eb2a Michael Hanselmann
  "NEW_CLUSTER_DOMAIN_SECRET_OPT",
96 6b7d5878 Michael Hanselmann
  "NEW_CONFD_HMAC_KEY_OPT",
97 6d4a1656 Michael Hanselmann
  "NEW_RAPI_CERT_OPT",
98 a14db5ff Iustin Pop
  "NEW_SECONDARY_OPT",
99 4fbc93dd Iustin Pop
  "NIC_PARAMS_OPT",
100 7edc4637 Iustin Pop
  "NODE_LIST_OPT",
101 990b7886 Iustin Pop
  "NODE_PLACEMENT_OPT",
102 26591bfd Luca Bigliardi
  "NODRBD_STORAGE_OPT",
103 4abc4f1e Iustin Pop
  "NOHDR_OPT",
104 91e0748c Iustin Pop
  "NOIPCHECK_OPT",
105 25a8792c Iustin Pop
  "NO_INSTALL_OPT",
106 460d22be Iustin Pop
  "NONAMECHECK_OPT",
107 831040bf Iustin Pop
  "NOLVM_STORAGE_OPT",
108 29392516 Iustin Pop
  "NOMODIFY_ETCHOSTS_OPT",
109 b989b9d9 Ken Wehr
  "NOMODIFY_SSH_SETUP_OPT",
110 26023ecd Iustin Pop
  "NONICS_OPT",
111 f2a0828c Iustin Pop
  "NONLIVE_OPT",
112 14e9e7f3 Iustin Pop
  "NONPLUS1_OPT",
113 44c44832 Iustin Pop
  "NOSHUTDOWN_OPT",
114 edeb878a Iustin Pop
  "NOSTART_OPT",
115 fcdde7f2 Iustin Pop
  "NOSSH_KEYCHECK_OPT",
116 58371861 Iustin Pop
  "NOVOTING_OPT",
117 3f75b4f3 Iustin Pop
  "NWSYNC_OPT",
118 a72d0a79 Iustin Pop
  "ON_PRIMARY_OPT",
119 feb09e6a Iustin Pop
  "ON_SECONDARY_OPT",
120 771734c9 Iustin Pop
  "OFFLINE_OPT",
121 062a7100 Iustin Pop
  "OSPARAMS_OPT",
122 d3ed23ff Iustin Pop
  "OS_OPT",
123 ff00c1a7 Iustin Pop
  "OS_SIZE_OPT",
124 e7323b5e Manuel Franceschini
  "PRIMARY_IP_VERSION_OPT",
125 6d4a1656 Michael Hanselmann
  "RAPI_CERT_OPT",
126 b8d0f938 Iustin Pop
  "READD_OPT",
127 12054861 Iustin Pop
  "REBOOT_TYPE_OPT",
128 8d8d650c Michael Hanselmann
  "REMOVE_INSTANCE_OPT",
129 fdad8c4d Balazs Lecz
  "REMOVE_UIDS_OPT",
130 f38ea602 Iustin Pop
  "RESERVED_LVS_OPT",
131 31d97b2a Guido Trotter
  "ROMAN_OPT",
132 8d823629 Iustin Pop
  "SECONDARY_IP_OPT",
133 67840b40 Iustin Pop
  "SELECT_OS_OPT",
134 4abc4f1e Iustin Pop
  "SEP_OPT",
135 fdcf4d84 Iustin Pop
  "SHOWCMD_OPT",
136 7e5eaaa8 Guido Trotter
  "SHUTDOWN_TIMEOUT_OPT",
137 f36d7d81 Iustin Pop
  "SINGLE_NODE_OPT",
138 df62e5db Iustin Pop
  "SRC_DIR_OPT",
139 df62e5db Iustin Pop
  "SRC_NODE_OPT",
140 4abc4f1e Iustin Pop
  "SUBMIT_OPT",
141 99a8c799 Iustin Pop
  "STATIC_OPT",
142 4abc4f1e Iustin Pop
  "SYNC_OPT",
143 4abc4f1e Iustin Pop
  "TAG_SRC_OPT",
144 b5762e2a Guido Trotter
  "TIMEOUT_OPT",
145 1338f2b4 Balazs Lecz
  "UIDPOOL_OPT",
146 4abc4f1e Iustin Pop
  "USEUNITS_OPT",
147 74adc100 Iustin Pop
  "USE_REPL_NET_OPT",
148 9cdb9578 Iustin Pop
  "VERBOSE_OPT",
149 b58726e8 Iustin Pop
  "VG_NAME_OPT",
150 1f587d3d Iustin Pop
  "YES_DOIT_OPT",
151 4abc4f1e Iustin Pop
  # Generic functions for CLI programs
152 4abc4f1e Iustin Pop
  "GenericMain",
153 d77490c5 Iustin Pop
  "GenericInstanceCreate",
154 4abc4f1e Iustin Pop
  "GetClient",
155 4abc4f1e Iustin Pop
  "GetOnlineNodes",
156 4abc4f1e Iustin Pop
  "JobExecutor",
157 4abc4f1e Iustin Pop
  "JobSubmittedException",
158 4abc4f1e Iustin Pop
  "ParseTimespec",
159 7e49b6ce Michael Hanselmann
  "RunWhileClusterStopped",
160 4abc4f1e Iustin Pop
  "SubmitOpCode",
161 4abc4f1e Iustin Pop
  "SubmitOrSend",
162 4abc4f1e Iustin Pop
  "UsesRPC",
163 4abc4f1e Iustin Pop
  # Formatting functions
164 4abc4f1e Iustin Pop
  "ToStderr", "ToStdout",
165 4abc4f1e Iustin Pop
  "FormatError",
166 4abc4f1e Iustin Pop
  "GenerateTable",
167 4abc4f1e Iustin Pop
  "AskUser",
168 4abc4f1e Iustin Pop
  "FormatTimestamp",
169 8a7f1c61 Michael Hanselmann
  "FormatLogMessage",
170 4abc4f1e Iustin Pop
  # Tags functions
171 4abc4f1e Iustin Pop
  "ListTags",
172 4abc4f1e Iustin Pop
  "AddTags",
173 4abc4f1e Iustin Pop
  "RemoveTags",
174 4abc4f1e Iustin Pop
  # command line options support infrastructure
175 4abc4f1e Iustin Pop
  "ARGS_MANY_INSTANCES",
176 4abc4f1e Iustin Pop
  "ARGS_MANY_NODES",
177 4abc4f1e Iustin Pop
  "ARGS_NONE",
178 4abc4f1e Iustin Pop
  "ARGS_ONE_INSTANCE",
179 4abc4f1e Iustin Pop
  "ARGS_ONE_NODE",
180 f9faf9c3 René Nussbaumer
  "ARGS_ONE_OS",
181 4abc4f1e Iustin Pop
  "ArgChoice",
182 4abc4f1e Iustin Pop
  "ArgCommand",
183 4abc4f1e Iustin Pop
  "ArgFile",
184 4abc4f1e Iustin Pop
  "ArgHost",
185 4abc4f1e Iustin Pop
  "ArgInstance",
186 4abc4f1e Iustin Pop
  "ArgJobId",
187 4abc4f1e Iustin Pop
  "ArgNode",
188 f9faf9c3 René Nussbaumer
  "ArgOs",
189 4abc4f1e Iustin Pop
  "ArgSuggest",
190 4abc4f1e Iustin Pop
  "ArgUnknown",
191 4abc4f1e Iustin Pop
  "OPT_COMPL_INST_ADD_NODES",
192 4abc4f1e Iustin Pop
  "OPT_COMPL_MANY_NODES",
193 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_IALLOCATOR",
194 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_INSTANCE",
195 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_NODE",
196 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_OS",
197 4abc4f1e Iustin Pop
  "cli_option",
198 4abc4f1e Iustin Pop
  "SplitNodeOption",
199 07150497 Guido Trotter
  "CalculateOSNames",
200 a4ebd726 Michael Hanselmann
  "ParseFields",
201 4abc4f1e Iustin Pop
  ]
202 846baef9 Iustin Pop
203 8b46606c Guido Trotter
NO_PREFIX = "no_"
204 8b46606c Guido Trotter
UN_PREFIX = "-"
205 846baef9 Iustin Pop
206 03298ebe Michael Hanselmann
207 863d7f46 Michael Hanselmann
class _Argument:
208 7260cfbe Iustin Pop
  def __init__(self, min=0, max=None): # pylint: disable-msg=W0622
209 863d7f46 Michael Hanselmann
    self.min = min
210 863d7f46 Michael Hanselmann
    self.max = max
211 863d7f46 Michael Hanselmann
212 863d7f46 Michael Hanselmann
  def __repr__(self):
213 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s>" %
214 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max))
215 863d7f46 Michael Hanselmann
216 863d7f46 Michael Hanselmann
217 863d7f46 Michael Hanselmann
class ArgSuggest(_Argument):
218 863d7f46 Michael Hanselmann
  """Suggesting argument.
219 863d7f46 Michael Hanselmann

220 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor.
221 863d7f46 Michael Hanselmann

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

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

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

245 863d7f46 Michael Hanselmann
  """
246 863d7f46 Michael Hanselmann
247 863d7f46 Michael Hanselmann
248 863d7f46 Michael Hanselmann
class ArgInstance(_Argument):
249 863d7f46 Michael Hanselmann
  """Instances argument.
250 863d7f46 Michael Hanselmann

251 863d7f46 Michael Hanselmann
  """
252 863d7f46 Michael Hanselmann
253 863d7f46 Michael Hanselmann
254 863d7f46 Michael Hanselmann
class ArgNode(_Argument):
255 863d7f46 Michael Hanselmann
  """Node argument.
256 863d7f46 Michael Hanselmann

257 863d7f46 Michael Hanselmann
  """
258 863d7f46 Michael Hanselmann
259 863d7f46 Michael Hanselmann
class ArgJobId(_Argument):
260 863d7f46 Michael Hanselmann
  """Job ID argument.
261 863d7f46 Michael Hanselmann

262 863d7f46 Michael Hanselmann
  """
263 863d7f46 Michael Hanselmann
264 863d7f46 Michael Hanselmann
265 863d7f46 Michael Hanselmann
class ArgFile(_Argument):
266 863d7f46 Michael Hanselmann
  """File path argument.
267 863d7f46 Michael Hanselmann

268 863d7f46 Michael Hanselmann
  """
269 863d7f46 Michael Hanselmann
270 863d7f46 Michael Hanselmann
271 863d7f46 Michael Hanselmann
class ArgCommand(_Argument):
272 863d7f46 Michael Hanselmann
  """Command argument.
273 863d7f46 Michael Hanselmann

274 863d7f46 Michael Hanselmann
  """
275 863d7f46 Michael Hanselmann
276 863d7f46 Michael Hanselmann
277 83ec7961 Michael Hanselmann
class ArgHost(_Argument):
278 83ec7961 Michael Hanselmann
  """Host argument.
279 83ec7961 Michael Hanselmann

280 83ec7961 Michael Hanselmann
  """
281 83ec7961 Michael Hanselmann
282 83ec7961 Michael Hanselmann
283 f9faf9c3 René Nussbaumer
class ArgOs(_Argument):
284 f9faf9c3 René Nussbaumer
  """OS argument.
285 f9faf9c3 René Nussbaumer

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

300 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
301 846baef9 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

486 e7b61bb0 Iustin Pop
  This will store the parsed value as either True or False.
487 e7b61bb0 Iustin Pop

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

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

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

1050 c41eea6e Iustin Pop
  @param argv: the command line
1051 c41eea6e Iustin Pop
  @param commands: dictionary with special contents, see the design
1052 c41eea6e Iustin Pop
      doc for cmdline handling
1053 c41eea6e Iustin Pop
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
1054 098c0958 Michael Hanselmann

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

1126 a8005e17 Michael Hanselmann
  Algorithm:
1127 a8005e17 Michael Hanselmann

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

1130 a8005e17 Michael Hanselmann
    1. For each argument in definition
1131 a8005e17 Michael Hanselmann

1132 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
1133 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
1134 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
1135 a8005e17 Michael Hanselmann

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

1138 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
1139 a8005e17 Michael Hanselmann

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

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

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

1197 60d49723 Michael Hanselmann
  """
1198 60d49723 Michael Hanselmann
  if value and ':' in value:
1199 60d49723 Michael Hanselmann
    return value.split(':', 1)
1200 60d49723 Michael Hanselmann
  else:
1201 60d49723 Michael Hanselmann
    return (value, None)
1202 60d49723 Michael Hanselmann
1203 60d49723 Michael Hanselmann
1204 07150497 Guido Trotter
def CalculateOSNames(os_name, os_variants):
1205 07150497 Guido Trotter
  """Calculates all the names an OS can be called, according to its variants.
1206 07150497 Guido Trotter

1207 07150497 Guido Trotter
  @type os_name: string
1208 07150497 Guido Trotter
  @param os_name: base name of the os
1209 07150497 Guido Trotter
  @type os_variants: list or None
1210 07150497 Guido Trotter
  @param os_variants: list of supported variants
1211 07150497 Guido Trotter
  @rtype: list
1212 07150497 Guido Trotter
  @return: list of valid names
1213 07150497 Guido Trotter

1214 07150497 Guido Trotter
  """
1215 07150497 Guido Trotter
  if os_variants:
1216 07150497 Guido Trotter
    return ['%s+%s' % (os_name, v) for v in os_variants]
1217 07150497 Guido Trotter
  else:
1218 07150497 Guido Trotter
    return [os_name]
1219 07150497 Guido Trotter
1220 07150497 Guido Trotter
1221 a4ebd726 Michael Hanselmann
def ParseFields(selected, default):
1222 a4ebd726 Michael Hanselmann
  """Parses the values of "--field"-like options.
1223 a4ebd726 Michael Hanselmann

1224 a4ebd726 Michael Hanselmann
  @type selected: string or None
1225 a4ebd726 Michael Hanselmann
  @param selected: User-selected options
1226 a4ebd726 Michael Hanselmann
  @type default: list
1227 a4ebd726 Michael Hanselmann
  @param default: Default fields
1228 a4ebd726 Michael Hanselmann

1229 a4ebd726 Michael Hanselmann
  """
1230 a4ebd726 Michael Hanselmann
  if selected is None:
1231 a4ebd726 Michael Hanselmann
    return default
1232 a4ebd726 Michael Hanselmann
1233 a4ebd726 Michael Hanselmann
  if selected.startswith("+"):
1234 a4ebd726 Michael Hanselmann
    return default + selected[1:].split(",")
1235 a4ebd726 Michael Hanselmann
1236 a4ebd726 Michael Hanselmann
  return selected.split(",")
1237 a4ebd726 Michael Hanselmann
1238 a4ebd726 Michael Hanselmann
1239 e0e916fe Iustin Pop
UsesRPC = rpc.RunWithRPC
1240 4331f6cd Michael Hanselmann
1241 4331f6cd Michael Hanselmann
1242 47988778 Iustin Pop
def AskUser(text, choices=None):
1243 47988778 Iustin Pop
  """Ask the user a question.
1244 a8083063 Iustin Pop

1245 c41eea6e Iustin Pop
  @param text: the question to ask
1246 a8083063 Iustin Pop

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

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

1256 a8083063 Iustin Pop
  """
1257 47988778 Iustin Pop
  if choices is None:
1258 47988778 Iustin Pop
    choices = [('y', True, 'Perform the operation'),
1259 47988778 Iustin Pop
               ('n', False, 'Do not perform the operation')]
1260 47988778 Iustin Pop
  if not choices or not isinstance(choices, list):
1261 5bbd3f7f Michael Hanselmann
    raise errors.ProgrammerError("Invalid choices argument to AskUser")
1262 47988778 Iustin Pop
  for entry in choices:
1263 47988778 Iustin Pop
    if not isinstance(entry, tuple) or len(entry) < 3 or entry[0] == '?':
1264 5bbd3f7f Michael Hanselmann
      raise errors.ProgrammerError("Invalid choices element to AskUser")
1265 47988778 Iustin Pop
1266 47988778 Iustin Pop
  answer = choices[-1][1]
1267 47988778 Iustin Pop
  new_text = []
1268 47988778 Iustin Pop
  for line in text.splitlines():
1269 47988778 Iustin Pop
    new_text.append(textwrap.fill(line, 70, replace_whitespace=False))
1270 47988778 Iustin Pop
  text = "\n".join(new_text)
1271 a8083063 Iustin Pop
  try:
1272 3023170f Iustin Pop
    f = file("/dev/tty", "a+")
1273 a8083063 Iustin Pop
  except IOError:
1274 47988778 Iustin Pop
    return answer
1275 a8083063 Iustin Pop
  try:
1276 47988778 Iustin Pop
    chars = [entry[0] for entry in choices]
1277 47988778 Iustin Pop
    chars[-1] = "[%s]" % chars[-1]
1278 47988778 Iustin Pop
    chars.append('?')
1279 47988778 Iustin Pop
    maps = dict([(entry[0], entry[1]) for entry in choices])
1280 47988778 Iustin Pop
    while True:
1281 47988778 Iustin Pop
      f.write(text)
1282 47988778 Iustin Pop
      f.write('\n')
1283 47988778 Iustin Pop
      f.write("/".join(chars))
1284 47988778 Iustin Pop
      f.write(": ")
1285 47988778 Iustin Pop
      line = f.readline(2).strip().lower()
1286 47988778 Iustin Pop
      if line in maps:
1287 47988778 Iustin Pop
        answer = maps[line]
1288 47988778 Iustin Pop
        break
1289 47988778 Iustin Pop
      elif line == '?':
1290 47988778 Iustin Pop
        for entry in choices:
1291 47988778 Iustin Pop
          f.write(" %s - %s\n" % (entry[0], entry[2]))
1292 47988778 Iustin Pop
        f.write("\n")
1293 47988778 Iustin Pop
        continue
1294 a8083063 Iustin Pop
  finally:
1295 a8083063 Iustin Pop
    f.close()
1296 a8083063 Iustin Pop
  return answer
1297 a8083063 Iustin Pop
1298 a8083063 Iustin Pop
1299 e9d741b6 Iustin Pop
class JobSubmittedException(Exception):
1300 e9d741b6 Iustin Pop
  """Job was submitted, client should exit.
1301 e9d741b6 Iustin Pop

1302 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1303 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1304 e9d741b6 Iustin Pop

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

1307 e9d741b6 Iustin Pop
  """
1308 e9d741b6 Iustin Pop
1309 e9d741b6 Iustin Pop
1310 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1311 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1312 a8083063 Iustin Pop

1313 0a1e74d9 Iustin Pop
  @type ops: list
1314 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1315 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1316 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1317 0a1e74d9 Iustin Pop
             if None, a new client will be created
1318 a8083063 Iustin Pop

1319 a8083063 Iustin Pop
  """
1320 e2212007 Iustin Pop
  if cl is None:
1321 b33e986b Iustin Pop
    cl = GetClient()
1322 685ee993 Iustin Pop
1323 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1324 0a1e74d9 Iustin Pop
1325 0a1e74d9 Iustin Pop
  return job_id
1326 0a1e74d9 Iustin Pop
1327 0a1e74d9 Iustin Pop
1328 4e338533 Michael Hanselmann
def GenericPollJob(job_id, cbs, report_cbs):
1329 4e338533 Michael Hanselmann
  """Generic job-polling function.
1330 0a1e74d9 Iustin Pop

1331 4e338533 Michael Hanselmann
  @type job_id: number
1332 4e338533 Michael Hanselmann
  @param job_id: Job ID
1333 4e338533 Michael Hanselmann
  @type cbs: Instance of L{JobPollCbBase}
1334 4e338533 Michael Hanselmann
  @param cbs: Data callbacks
1335 4e338533 Michael Hanselmann
  @type report_cbs: Instance of L{JobPollReportCbBase}
1336 4e338533 Michael Hanselmann
  @param report_cbs: Reporting callbacks
1337 0a1e74d9 Iustin Pop

1338 0a1e74d9 Iustin Pop
  """
1339 6c5a7090 Michael Hanselmann
  prev_job_info = None
1340 6c5a7090 Michael Hanselmann
  prev_logmsg_serial = None
1341 6c5a7090 Michael Hanselmann
1342 f4484122 Michael Hanselmann
  status = None
1343 f4484122 Michael Hanselmann
1344 685ee993 Iustin Pop
  while True:
1345 4e338533 Michael Hanselmann
    result = cbs.WaitForJobChangeOnce(job_id, ["status"], prev_job_info,
1346 4e338533 Michael Hanselmann
                                      prev_logmsg_serial)
1347 6c5a7090 Michael Hanselmann
    if not result:
1348 685ee993 Iustin Pop
      # job not found, go away!
1349 0bbe448c Michael Hanselmann
      raise errors.JobLost("Job with id %s lost" % job_id)
1350 4e338533 Michael Hanselmann
1351 4e338533 Michael Hanselmann
    if result == constants.JOB_NOTCHANGED:
1352 4e338533 Michael Hanselmann
      report_cbs.ReportNotChanged(job_id, status)
1353 f4484122 Michael Hanselmann
1354 f4484122 Michael Hanselmann
      # Wait again
1355 f4484122 Michael Hanselmann
      continue
1356 685ee993 Iustin Pop
1357 6c5a7090 Michael Hanselmann
    # Split result, a tuple of (field values, log entries)
1358 6c5a7090 Michael Hanselmann
    (job_info, log_entries) = result
1359 6c5a7090 Michael Hanselmann
    (status, ) = job_info
1360 6c5a7090 Michael Hanselmann
1361 6c5a7090 Michael Hanselmann
    if log_entries:
1362 6c5a7090 Michael Hanselmann
      for log_entry in log_entries:
1363 4e338533 Michael Hanselmann
        (serial, timestamp, log_type, message) = log_entry
1364 4e338533 Michael Hanselmann
        report_cbs.ReportLogMessage(job_id, serial, timestamp,
1365 4e338533 Michael Hanselmann
                                    log_type, message)
1366 6c5a7090 Michael Hanselmann
        prev_logmsg_serial = max(prev_logmsg_serial, serial)
1367 6c5a7090 Michael Hanselmann
1368 0bbe448c Michael Hanselmann
    # TODO: Handle canceled and archived jobs
1369 fbf0262f Michael Hanselmann
    elif status in (constants.JOB_STATUS_SUCCESS,
1370 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_ERROR,
1371 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELING,
1372 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELED):
1373 685ee993 Iustin Pop
      break
1374 6c5a7090 Michael Hanselmann
1375 6c5a7090 Michael Hanselmann
    prev_job_info = job_info
1376 685ee993 Iustin Pop
1377 4e338533 Michael Hanselmann
  jobs = cbs.QueryJobs([job_id], ["status", "opstatus", "opresult"])
1378 0bbe448c Michael Hanselmann
  if not jobs:
1379 0bbe448c Michael Hanselmann
    raise errors.JobLost("Job with id %s lost" % job_id)
1380 685ee993 Iustin Pop
1381 0e050889 Iustin Pop
  status, opstatus, result = jobs[0]
1382 4e338533 Michael Hanselmann
1383 0bbe448c Michael Hanselmann
  if status == constants.JOB_STATUS_SUCCESS:
1384 53c04d04 Iustin Pop
    return result
1385 4e338533 Michael Hanselmann
1386 4e338533 Michael Hanselmann
  if status in (constants.JOB_STATUS_CANCELING, constants.JOB_STATUS_CANCELED):
1387 fbf0262f Michael Hanselmann
    raise errors.OpExecError("Job was canceled")
1388 4e338533 Michael Hanselmann
1389 4e338533 Michael Hanselmann
  has_ok = False
1390 4e338533 Michael Hanselmann
  for idx, (status, msg) in enumerate(zip(opstatus, result)):
1391 4e338533 Michael Hanselmann
    if status == constants.OP_STATUS_SUCCESS:
1392 4e338533 Michael Hanselmann
      has_ok = True
1393 4e338533 Michael Hanselmann
    elif status == constants.OP_STATUS_ERROR:
1394 4e338533 Michael Hanselmann
      errors.MaybeRaise(msg)
1395 4e338533 Michael Hanselmann
1396 4e338533 Michael Hanselmann
      if has_ok:
1397 4e338533 Michael Hanselmann
        raise errors.OpExecError("partial failure (opcode %d): %s" %
1398 4e338533 Michael Hanselmann
                                 (idx, msg))
1399 4e338533 Michael Hanselmann
1400 4e338533 Michael Hanselmann
      raise errors.OpExecError(str(msg))
1401 4e338533 Michael Hanselmann
1402 4e338533 Michael Hanselmann
  # default failure mode
1403 4e338533 Michael Hanselmann
  raise errors.OpExecError(result)
1404 4e338533 Michael Hanselmann
1405 4e338533 Michael Hanselmann
1406 4e338533 Michael Hanselmann
class JobPollCbBase:
1407 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} callbacks.
1408 4e338533 Michael Hanselmann

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

1413 4e338533 Michael Hanselmann
    """
1414 4e338533 Michael Hanselmann
1415 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1416 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1417 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1418 4e338533 Michael Hanselmann

1419 4e338533 Michael Hanselmann
    """
1420 4e338533 Michael Hanselmann
    raise NotImplementedError()
1421 4e338533 Michael Hanselmann
1422 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1423 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1424 4e338533 Michael Hanselmann

1425 4e338533 Michael Hanselmann
    @type job_ids: list of numbers
1426 4e338533 Michael Hanselmann
    @param job_ids: Job IDs
1427 4e338533 Michael Hanselmann
    @type fields: list of strings
1428 4e338533 Michael Hanselmann
    @param fields: Fields
1429 4e338533 Michael Hanselmann

1430 4e338533 Michael Hanselmann
    """
1431 4e338533 Michael Hanselmann
    raise NotImplementedError()
1432 4e338533 Michael Hanselmann
1433 4e338533 Michael Hanselmann
1434 4e338533 Michael Hanselmann
class JobPollReportCbBase:
1435 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} reporting callbacks.
1436 4e338533 Michael Hanselmann

1437 4e338533 Michael Hanselmann
  """
1438 4e338533 Michael Hanselmann
  def __init__(self):
1439 4e338533 Michael Hanselmann
    """Initializes this class.
1440 4e338533 Michael Hanselmann

1441 4e338533 Michael Hanselmann
    """
1442 4e338533 Michael Hanselmann
1443 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1444 4e338533 Michael Hanselmann
    """Handles a log message.
1445 4e338533 Michael Hanselmann

1446 4e338533 Michael Hanselmann
    """
1447 4e338533 Michael Hanselmann
    raise NotImplementedError()
1448 4e338533 Michael Hanselmann
1449 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1450 4e338533 Michael Hanselmann
    """Called for if a job hasn't changed in a while.
1451 4e338533 Michael Hanselmann

1452 4e338533 Michael Hanselmann
    @type job_id: number
1453 4e338533 Michael Hanselmann
    @param job_id: Job ID
1454 4e338533 Michael Hanselmann
    @type status: string or None
1455 4e338533 Michael Hanselmann
    @param status: Job status if available
1456 4e338533 Michael Hanselmann

1457 4e338533 Michael Hanselmann
    """
1458 4e338533 Michael Hanselmann
    raise NotImplementedError()
1459 4e338533 Michael Hanselmann
1460 4e338533 Michael Hanselmann
1461 4e338533 Michael Hanselmann
class _LuxiJobPollCb(JobPollCbBase):
1462 4e338533 Michael Hanselmann
  def __init__(self, cl):
1463 4e338533 Michael Hanselmann
    """Initializes this class.
1464 4e338533 Michael Hanselmann

1465 4e338533 Michael Hanselmann
    """
1466 4e338533 Michael Hanselmann
    JobPollCbBase.__init__(self)
1467 4e338533 Michael Hanselmann
    self.cl = cl
1468 4e338533 Michael Hanselmann
1469 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1470 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1471 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1472 4e338533 Michael Hanselmann

1473 4e338533 Michael Hanselmann
    """
1474 4e338533 Michael Hanselmann
    return self.cl.WaitForJobChangeOnce(job_id, fields,
1475 4e338533 Michael Hanselmann
                                        prev_job_info, prev_log_serial)
1476 4e338533 Michael Hanselmann
1477 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1478 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1479 4e338533 Michael Hanselmann

1480 4e338533 Michael Hanselmann
    """
1481 4e338533 Michael Hanselmann
    return self.cl.QueryJobs(job_ids, fields)
1482 4e338533 Michael Hanselmann
1483 4e338533 Michael Hanselmann
1484 4e338533 Michael Hanselmann
class FeedbackFnJobPollReportCb(JobPollReportCbBase):
1485 4e338533 Michael Hanselmann
  def __init__(self, feedback_fn):
1486 4e338533 Michael Hanselmann
    """Initializes this class.
1487 4e338533 Michael Hanselmann

1488 4e338533 Michael Hanselmann
    """
1489 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1490 4e338533 Michael Hanselmann
1491 4e338533 Michael Hanselmann
    self.feedback_fn = feedback_fn
1492 4e338533 Michael Hanselmann
1493 4e338533 Michael Hanselmann
    assert callable(feedback_fn)
1494 4e338533 Michael Hanselmann
1495 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1496 4e338533 Michael Hanselmann
    """Handles a log message.
1497 4e338533 Michael Hanselmann

1498 4e338533 Michael Hanselmann
    """
1499 4e338533 Michael Hanselmann
    self.feedback_fn((timestamp, log_type, log_msg))
1500 4e338533 Michael Hanselmann
1501 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1502 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1503 4e338533 Michael Hanselmann

1504 4e338533 Michael Hanselmann
    """
1505 4e338533 Michael Hanselmann
    # Ignore
1506 4e338533 Michael Hanselmann
1507 4e338533 Michael Hanselmann
1508 4e338533 Michael Hanselmann
class StdioJobPollReportCb(JobPollReportCbBase):
1509 4e338533 Michael Hanselmann
  def __init__(self):
1510 4e338533 Michael Hanselmann
    """Initializes this class.
1511 4e338533 Michael Hanselmann

1512 4e338533 Michael Hanselmann
    """
1513 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1514 4e338533 Michael Hanselmann
1515 4e338533 Michael Hanselmann
    self.notified_queued = False
1516 4e338533 Michael Hanselmann
    self.notified_waitlock = False
1517 4e338533 Michael Hanselmann
1518 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1519 4e338533 Michael Hanselmann
    """Handles a log message.
1520 4e338533 Michael Hanselmann

1521 4e338533 Michael Hanselmann
    """
1522 4e338533 Michael Hanselmann
    ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)),
1523 8a7f1c61 Michael Hanselmann
             FormatLogMessage(log_type, log_msg))
1524 4e338533 Michael Hanselmann
1525 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1526 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1527 4e338533 Michael Hanselmann

1528 4e338533 Michael Hanselmann
    """
1529 4e338533 Michael Hanselmann
    if status is None:
1530 4e338533 Michael Hanselmann
      return
1531 4e338533 Michael Hanselmann
1532 4e338533 Michael Hanselmann
    if status == constants.JOB_STATUS_QUEUED and not self.notified_queued:
1533 4e338533 Michael Hanselmann
      ToStderr("Job %s is waiting in queue", job_id)
1534 4e338533 Michael Hanselmann
      self.notified_queued = True
1535 4e338533 Michael Hanselmann
1536 4e338533 Michael Hanselmann
    elif status == constants.JOB_STATUS_WAITLOCK and not self.notified_waitlock:
1537 4e338533 Michael Hanselmann
      ToStderr("Job %s is trying to acquire all necessary locks", job_id)
1538 4e338533 Michael Hanselmann
      self.notified_waitlock = True
1539 4e338533 Michael Hanselmann
1540 4e338533 Michael Hanselmann
1541 8a7f1c61 Michael Hanselmann
def FormatLogMessage(log_type, log_msg):
1542 8a7f1c61 Michael Hanselmann
  """Formats a job message according to its type.
1543 8a7f1c61 Michael Hanselmann

1544 8a7f1c61 Michael Hanselmann
  """
1545 8a7f1c61 Michael Hanselmann
  if log_type != constants.ELOG_MESSAGE:
1546 8a7f1c61 Michael Hanselmann
    log_msg = str(log_msg)
1547 8a7f1c61 Michael Hanselmann
1548 8a7f1c61 Michael Hanselmann
  return utils.SafeEncode(log_msg)
1549 8a7f1c61 Michael Hanselmann
1550 8a7f1c61 Michael Hanselmann
1551 583163a6 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None, reporter=None):
1552 4e338533 Michael Hanselmann
  """Function to poll for the result of a job.
1553 4e338533 Michael Hanselmann

1554 4e338533 Michael Hanselmann
  @type job_id: job identified
1555 4e338533 Michael Hanselmann
  @param job_id: the job to poll for results
1556 4e338533 Michael Hanselmann
  @type cl: luxi.Client
1557 4e338533 Michael Hanselmann
  @param cl: the luxi client to use for communicating with the master;
1558 4e338533 Michael Hanselmann
             if None, a new client will be created
1559 4e338533 Michael Hanselmann

1560 4e338533 Michael Hanselmann
  """
1561 4e338533 Michael Hanselmann
  if cl is None:
1562 4e338533 Michael Hanselmann
    cl = GetClient()
1563 4e338533 Michael Hanselmann
1564 583163a6 Michael Hanselmann
  if reporter is None:
1565 583163a6 Michael Hanselmann
    if feedback_fn:
1566 583163a6 Michael Hanselmann
      reporter = FeedbackFnJobPollReportCb(feedback_fn)
1567 583163a6 Michael Hanselmann
    else:
1568 583163a6 Michael Hanselmann
      reporter = StdioJobPollReportCb()
1569 583163a6 Michael Hanselmann
  elif feedback_fn:
1570 583163a6 Michael Hanselmann
    raise errors.ProgrammerError("Can't specify reporter and feedback function")
1571 4e338533 Michael Hanselmann
1572 4e338533 Michael Hanselmann
  return GenericPollJob(job_id, _LuxiJobPollCb(cl), reporter)
1573 ceab32dd Iustin Pop
1574 ceab32dd Iustin Pop
1575 583163a6 Michael Hanselmann
def SubmitOpCode(op, cl=None, feedback_fn=None, opts=None, reporter=None):
1576 0a1e74d9 Iustin Pop
  """Legacy function to submit an opcode.
1577 0a1e74d9 Iustin Pop

1578 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1579 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1580 0a1e74d9 Iustin Pop
  interaction functions.
1581 0a1e74d9 Iustin Pop

1582 0a1e74d9 Iustin Pop
  """
1583 0a1e74d9 Iustin Pop
  if cl is None:
1584 0a1e74d9 Iustin Pop
    cl = GetClient()
1585 0a1e74d9 Iustin Pop
1586 293ba2d8 Iustin Pop
  SetGenericOpcodeOpts([op], opts)
1587 293ba2d8 Iustin Pop
1588 5d297d8a Michael Hanselmann
  job_id = SendJob([op], cl=cl)
1589 0a1e74d9 Iustin Pop
1590 583163a6 Michael Hanselmann
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn,
1591 583163a6 Michael Hanselmann
                       reporter=reporter)
1592 53c04d04 Iustin Pop
1593 53c04d04 Iustin Pop
  return op_results[0]
1594 0a1e74d9 Iustin Pop
1595 0a1e74d9 Iustin Pop
1596 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1597 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1598 94428652 Iustin Pop

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

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

1607 94428652 Iustin Pop
  """
1608 94428652 Iustin Pop
  if opts and opts.submit_only:
1609 293ba2d8 Iustin Pop
    job = [op]
1610 293ba2d8 Iustin Pop
    SetGenericOpcodeOpts(job, opts)
1611 293ba2d8 Iustin Pop
    job_id = SendJob(job, cl=cl)
1612 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
1613 94428652 Iustin Pop
  else:
1614 293ba2d8 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
1615 293ba2d8 Iustin Pop
1616 293ba2d8 Iustin Pop
1617 293ba2d8 Iustin Pop
def SetGenericOpcodeOpts(opcode_list, options):
1618 293ba2d8 Iustin Pop
  """Processor for generic options.
1619 293ba2d8 Iustin Pop

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

1623 293ba2d8 Iustin Pop
  @param opcode_list: list of opcodes
1624 293ba2d8 Iustin Pop
  @param options: command line options or None
1625 293ba2d8 Iustin Pop
  @return: None (in-place modification)
1626 293ba2d8 Iustin Pop

1627 293ba2d8 Iustin Pop
  """
1628 293ba2d8 Iustin Pop
  if not options:
1629 293ba2d8 Iustin Pop
    return
1630 293ba2d8 Iustin Pop
  for op in opcode_list:
1631 a0a6ff34 Iustin Pop
    if hasattr(options, "dry_run"):
1632 a0a6ff34 Iustin Pop
      op.dry_run = options.dry_run
1633 293ba2d8 Iustin Pop
    op.debug_level = options.debug
1634 94428652 Iustin Pop
1635 94428652 Iustin Pop
1636 af30b2fd Michael Hanselmann
def GetClient():
1637 af30b2fd Michael Hanselmann
  # TODO: Cache object?
1638 b33e986b Iustin Pop
  try:
1639 b33e986b Iustin Pop
    client = luxi.Client()
1640 b33e986b Iustin Pop
  except luxi.NoMasterError:
1641 d9a51679 Michael Hanselmann
    ss = ssconf.SimpleStore()
1642 d9a51679 Michael Hanselmann
1643 d9a51679 Michael Hanselmann
    # Try to read ssconf file
1644 d9a51679 Michael Hanselmann
    try:
1645 d9a51679 Michael Hanselmann
      ss.GetMasterNode()
1646 d9a51679 Michael Hanselmann
    except errors.ConfigurationError:
1647 d9a51679 Michael Hanselmann
      raise errors.OpPrereqError("Cluster not initialized or this machine is"
1648 d9a51679 Michael Hanselmann
                                 " not part of a cluster")
1649 d9a51679 Michael Hanselmann
1650 d9a51679 Michael Hanselmann
    master, myself = ssconf.GetMasterAndMyself(ss=ss)
1651 b33e986b Iustin Pop
    if master != myself:
1652 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
1653 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
1654 b33e986b Iustin Pop
                                 master)
1655 d9a51679 Michael Hanselmann
    raise
1656 b33e986b Iustin Pop
  return client
1657 af30b2fd Michael Hanselmann
1658 af30b2fd Michael Hanselmann
1659 73702ee7 Iustin Pop
def FormatError(err):
1660 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
1661 73702ee7 Iustin Pop

1662 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
1663 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
1664 73702ee7 Iustin Pop
  second, a string describing the error message (not
1665 73702ee7 Iustin Pop
  newline-terminated).
1666 73702ee7 Iustin Pop

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

1744 334d1483 Iustin Pop
  Arguments:
1745 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
1746 334d1483 Iustin Pop
                for command line handling.
1747 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
1748 334d1483 Iustin Pop
                override command line options; this can be used to pass
1749 334d1483 Iustin Pop
                options from the scripts to generic functions
1750 de47cf8f Guido Trotter
    - aliases: dictionary with command aliases {'alias': 'target, ...}
1751 a8083063 Iustin Pop

1752 a8083063 Iustin Pop
  """
1753 a8083063 Iustin Pop
  # save the program name and the entire command line for later logging
1754 a8083063 Iustin Pop
  if sys.argv:
1755 a8083063 Iustin Pop
    binary = os.path.basename(sys.argv[0]) or sys.argv[0]
1756 a8083063 Iustin Pop
    if len(sys.argv) >= 2:
1757 a8083063 Iustin Pop
      binary += " " + sys.argv[1]
1758 a8083063 Iustin Pop
      old_cmdline = " ".join(sys.argv[2:])
1759 a8083063 Iustin Pop
    else:
1760 a8083063 Iustin Pop
      old_cmdline = ""
1761 a8083063 Iustin Pop
  else:
1762 a8083063 Iustin Pop
    binary = "<unknown program>"
1763 a8083063 Iustin Pop
    old_cmdline = ""
1764 a8083063 Iustin Pop
1765 de47cf8f Guido Trotter
  if aliases is None:
1766 de47cf8f Guido Trotter
    aliases = {}
1767 de47cf8f Guido Trotter
1768 3126878d Guido Trotter
  try:
1769 3126878d Guido Trotter
    func, options, args = _ParseArgs(sys.argv, commands, aliases)
1770 3126878d Guido Trotter
  except errors.ParameterError, err:
1771 3126878d Guido Trotter
    result, err_msg = FormatError(err)
1772 3126878d Guido Trotter
    ToStderr(err_msg)
1773 3126878d Guido Trotter
    return 1
1774 3126878d Guido Trotter
1775 a8083063 Iustin Pop
  if func is None: # parse error
1776 a8083063 Iustin Pop
    return 1
1777 a8083063 Iustin Pop
1778 334d1483 Iustin Pop
  if override is not None:
1779 334d1483 Iustin Pop
    for key, val in override.iteritems():
1780 334d1483 Iustin Pop
      setattr(options, key, val)
1781 334d1483 Iustin Pop
1782 82d9caef Iustin Pop
  utils.SetupLogging(constants.LOG_COMMANDS, debug=options.debug,
1783 82d9caef Iustin Pop
                     stderr_logging=True, program=binary)
1784 a8083063 Iustin Pop
1785 a8083063 Iustin Pop
  if old_cmdline:
1786 46fbdd04 Iustin Pop
    logging.info("run with arguments '%s'", old_cmdline)
1787 a8083063 Iustin Pop
  else:
1788 46fbdd04 Iustin Pop
    logging.info("run with no arguments")
1789 a8083063 Iustin Pop
1790 a8083063 Iustin Pop
  try:
1791 a4af651e Iustin Pop
    result = func(options, args)
1792 d8353c3a Iustin Pop
  except (errors.GenericError, luxi.ProtocolError,
1793 d8353c3a Iustin Pop
          JobSubmittedException), err:
1794 a4af651e Iustin Pop
    result, err_msg = FormatError(err)
1795 5bbd3f7f Michael Hanselmann
    logging.exception("Error during command processing")
1796 46fbdd04 Iustin Pop
    ToStderr(err_msg)
1797 a8083063 Iustin Pop
1798 a8083063 Iustin Pop
  return result
1799 137161c9 Michael Hanselmann
1800 137161c9 Michael Hanselmann
1801 d77490c5 Iustin Pop
def GenericInstanceCreate(mode, opts, args):
1802 d77490c5 Iustin Pop
  """Add an instance to the cluster via either creation or import.
1803 d77490c5 Iustin Pop

1804 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
1805 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
1806 d77490c5 Iustin Pop
  @type args: list
1807 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
1808 d77490c5 Iustin Pop
  @rtype: int
1809 d77490c5 Iustin Pop
  @return: the desired exit code
1810 d77490c5 Iustin Pop

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

1943 7e49b6ce Michael Hanselmann
  """
1944 7e49b6ce Michael Hanselmann
  def __init__(self, feedback_fn, cluster_name, master_node, online_nodes):
1945 7e49b6ce Michael Hanselmann
    """Initializes this class.
1946 7e49b6ce Michael Hanselmann

1947 7e49b6ce Michael Hanselmann
    @type feedback_fn: callable
1948 7e49b6ce Michael Hanselmann
    @param feedback_fn: Feedback function
1949 7e49b6ce Michael Hanselmann
    @type cluster_name: string
1950 7e49b6ce Michael Hanselmann
    @param cluster_name: Cluster name
1951 7e49b6ce Michael Hanselmann
    @type master_node: string
1952 7e49b6ce Michael Hanselmann
    @param master_node Master node name
1953 7e49b6ce Michael Hanselmann
    @type online_nodes: list
1954 7e49b6ce Michael Hanselmann
    @param online_nodes: List of names of online nodes
1955 7e49b6ce Michael Hanselmann

1956 7e49b6ce Michael Hanselmann
    """
1957 7e49b6ce Michael Hanselmann
    self.feedback_fn = feedback_fn
1958 7e49b6ce Michael Hanselmann
    self.cluster_name = cluster_name
1959 7e49b6ce Michael Hanselmann
    self.master_node = master_node
1960 7e49b6ce Michael Hanselmann
    self.online_nodes = online_nodes
1961 7e49b6ce Michael Hanselmann
1962 7e49b6ce Michael Hanselmann
    self.ssh = ssh.SshRunner(self.cluster_name)
1963 7e49b6ce Michael Hanselmann
1964 7e49b6ce Michael Hanselmann
    self.nonmaster_nodes = [name for name in online_nodes
1965 7e49b6ce Michael Hanselmann
                            if name != master_node]
1966 7e49b6ce Michael Hanselmann
1967 7e49b6ce Michael Hanselmann
    assert self.master_node not in self.nonmaster_nodes
1968 7e49b6ce Michael Hanselmann
1969 7e49b6ce Michael Hanselmann
  def _RunCmd(self, node_name, cmd):
1970 7e49b6ce Michael Hanselmann
    """Runs a command on the local or a remote machine.
1971 7e49b6ce Michael Hanselmann

1972 7e49b6ce Michael Hanselmann
    @type node_name: string
1973 7e49b6ce Michael Hanselmann
    @param node_name: Machine name
1974 7e49b6ce Michael Hanselmann
    @type cmd: list
1975 7e49b6ce Michael Hanselmann
    @param cmd: Command
1976 7e49b6ce Michael Hanselmann

1977 7e49b6ce Michael Hanselmann
    """
1978 7e49b6ce Michael Hanselmann
    if node_name is None or node_name == self.master_node:
1979 7e49b6ce Michael Hanselmann
      # No need to use SSH
1980 7e49b6ce Michael Hanselmann
      result = utils.RunCmd(cmd)
1981 7e49b6ce Michael Hanselmann
    else:
1982 7e49b6ce Michael Hanselmann
      result = self.ssh.Run(node_name, "root", utils.ShellQuoteArgs(cmd))
1983 7e49b6ce Michael Hanselmann
1984 7e49b6ce Michael Hanselmann
    if result.failed:
1985 7e49b6ce Michael Hanselmann
      errmsg = ["Failed to run command %s" % result.cmd]
1986 7e49b6ce Michael Hanselmann
      if node_name:
1987 7e49b6ce Michael Hanselmann
        errmsg.append("on node %s" % node_name)
1988 7e49b6ce Michael Hanselmann
      errmsg.append(": exitcode %s and error %s" %
1989 7e49b6ce Michael Hanselmann
                    (result.exit_code, result.output))
1990 7e49b6ce Michael Hanselmann
      raise errors.OpExecError(" ".join(errmsg))
1991 7e49b6ce Michael Hanselmann
1992 7e49b6ce Michael Hanselmann
  def Call(self, fn, *args):
1993 7e49b6ce Michael Hanselmann
    """Call function while all daemons are stopped.
1994 7e49b6ce Michael Hanselmann

1995 7e49b6ce Michael Hanselmann
    @type fn: callable
1996 7e49b6ce Michael Hanselmann
    @param fn: Function to be called
1997 7e49b6ce Michael Hanselmann

1998 7e49b6ce Michael Hanselmann
    """
1999 7e49b6ce Michael Hanselmann
    # Pause watcher by acquiring an exclusive lock on watcher state file
2000 7e49b6ce Michael Hanselmann
    self.feedback_fn("Blocking watcher")
2001 7e49b6ce Michael Hanselmann
    watcher_block = utils.FileLock.Open(constants.WATCHER_STATEFILE)
2002 7e49b6ce Michael Hanselmann
    try:
2003 7e49b6ce Michael Hanselmann
      # TODO: Currently, this just blocks. There's no timeout.
2004 7e49b6ce Michael Hanselmann
      # TODO: Should it be a shared lock?
2005 7e49b6ce Michael Hanselmann
      watcher_block.Exclusive(blocking=True)
2006 7e49b6ce Michael Hanselmann
2007 7e49b6ce Michael Hanselmann
      # Stop master daemons, so that no new jobs can come in and all running
2008 7e49b6ce Michael Hanselmann
      # ones are finished
2009 7e49b6ce Michael Hanselmann
      self.feedback_fn("Stopping master daemons")
2010 7e49b6ce Michael Hanselmann
      self._RunCmd(None, [constants.DAEMON_UTIL, "stop-master"])
2011 7e49b6ce Michael Hanselmann
      try:
2012 7e49b6ce Michael Hanselmann
        # Stop daemons on all nodes
2013 7e49b6ce Michael Hanselmann
        for node_name in self.online_nodes:
2014 7e49b6ce Michael Hanselmann
          self.feedback_fn("Stopping daemons on %s" % node_name)
2015 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "stop-all"])
2016 7e49b6ce Michael Hanselmann
2017 7e49b6ce Michael Hanselmann
        # All daemons are shut down now
2018 7e49b6ce Michael Hanselmann
        try:
2019 7e49b6ce Michael Hanselmann
          return fn(self, *args)
2020 d512e84b Michael Hanselmann
        except Exception, err:
2021 d512e84b Michael Hanselmann
          _, errmsg = FormatError(err)
2022 7e49b6ce Michael Hanselmann
          logging.exception("Caught exception")
2023 d512e84b Michael Hanselmann
          self.feedback_fn(errmsg)
2024 7e49b6ce Michael Hanselmann
          raise
2025 7e49b6ce Michael Hanselmann
      finally:
2026 7e49b6ce Michael Hanselmann
        # Start cluster again, master node last
2027 7e49b6ce Michael Hanselmann
        for node_name in self.nonmaster_nodes + [self.master_node]:
2028 7e49b6ce Michael Hanselmann
          self.feedback_fn("Starting daemons on %s" % node_name)
2029 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "start-all"])
2030 7e49b6ce Michael Hanselmann
    finally:
2031 7e49b6ce Michael Hanselmann
      # Resume watcher
2032 7e49b6ce Michael Hanselmann
      watcher_block.Close()
2033 7e49b6ce Michael Hanselmann
2034 7e49b6ce Michael Hanselmann
2035 7e49b6ce Michael Hanselmann
def RunWhileClusterStopped(feedback_fn, fn, *args):
2036 7e49b6ce Michael Hanselmann
  """Calls a function while all cluster daemons are stopped.
2037 7e49b6ce Michael Hanselmann

2038 7e49b6ce Michael Hanselmann
  @type feedback_fn: callable
2039 7e49b6ce Michael Hanselmann
  @param feedback_fn: Feedback function
2040 7e49b6ce Michael Hanselmann
  @type fn: callable
2041 7e49b6ce Michael Hanselmann
  @param fn: Function to be called when daemons are stopped
2042 7e49b6ce Michael Hanselmann

2043 7e49b6ce Michael Hanselmann
  """
2044 7e49b6ce Michael Hanselmann
  feedback_fn("Gathering cluster information")
2045 7e49b6ce Michael Hanselmann
2046 7e49b6ce Michael Hanselmann
  # This ensures we're running on the master daemon
2047 7e49b6ce Michael Hanselmann
  cl = GetClient()
2048 7e49b6ce Michael Hanselmann
2049 7e49b6ce Michael Hanselmann
  (cluster_name, master_node) = \
2050 7e49b6ce Michael Hanselmann
    cl.QueryConfigValues(["cluster_name", "master_node"])
2051 7e49b6ce Michael Hanselmann
2052 7e49b6ce Michael Hanselmann
  online_nodes = GetOnlineNodes([], cl=cl)
2053 7e49b6ce Michael Hanselmann
2054 7e49b6ce Michael Hanselmann
  # Don't keep a reference to the client. The master daemon will go away.
2055 7e49b6ce Michael Hanselmann
  del cl
2056 7e49b6ce Michael Hanselmann
2057 7e49b6ce Michael Hanselmann
  assert master_node in online_nodes
2058 7e49b6ce Michael Hanselmann
2059 7e49b6ce Michael Hanselmann
  return _RunWhileClusterStoppedHelper(feedback_fn, cluster_name, master_node,
2060 7e49b6ce Michael Hanselmann
                                       online_nodes).Call(fn, *args)
2061 7e49b6ce Michael Hanselmann
2062 7e49b6ce Michael Hanselmann
2063 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
2064 9fbfbb7b Iustin Pop
                  numfields=None, unitfields=None,
2065 9fbfbb7b Iustin Pop
                  units=None):
2066 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
2067 137161c9 Michael Hanselmann

2068 9fbfbb7b Iustin Pop
  @type headers: dict
2069 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
2070 9fbfbb7b Iustin Pop
      the table
2071 9fbfbb7b Iustin Pop
  @type fields: list
2072 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
2073 9fbfbb7b Iustin Pop
      the data field
2074 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
2075 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
2076 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
2077 9fbfbb7b Iustin Pop
      each field
2078 9fbfbb7b Iustin Pop
  @type data: list
2079 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
2080 9fbfbb7b Iustin Pop
  @type numfields: list
2081 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
2082 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
2083 9fbfbb7b Iustin Pop
  @type unitfields: list
2084 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
2085 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
2086 9fbfbb7b Iustin Pop
  @type units: string or None
2087 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
2088 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
2089 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
2090 137161c9 Michael Hanselmann

2091 137161c9 Michael Hanselmann
  """
2092 9fbfbb7b Iustin Pop
  if units is None:
2093 9fbfbb7b Iustin Pop
    if separator:
2094 9fbfbb7b Iustin Pop
      units = "m"
2095 9fbfbb7b Iustin Pop
    else:
2096 9fbfbb7b Iustin Pop
      units = "h"
2097 9fbfbb7b Iustin Pop
2098 137161c9 Michael Hanselmann
  if numfields is None:
2099 137161c9 Michael Hanselmann
    numfields = []
2100 137161c9 Michael Hanselmann
  if unitfields is None:
2101 137161c9 Michael Hanselmann
    unitfields = []
2102 137161c9 Michael Hanselmann
2103 fe267188 Iustin Pop
  numfields = utils.FieldSet(*numfields)   # pylint: disable-msg=W0142
2104 fe267188 Iustin Pop
  unitfields = utils.FieldSet(*unitfields) # pylint: disable-msg=W0142
2105 00430f8e Iustin Pop
2106 137161c9 Michael Hanselmann
  format_fields = []
2107 137161c9 Michael Hanselmann
  for field in fields:
2108 01ca31ae Iustin Pop
    if headers and field not in headers:
2109 ea5a5b74 Guido Trotter
      # TODO: handle better unknown fields (either revert to old
2110 71c1af58 Iustin Pop
      # style of raising exception, or deal more intelligently with
2111 71c1af58 Iustin Pop
      # variable fields)
2112 71c1af58 Iustin Pop
      headers[field] = field
2113 137161c9 Michael Hanselmann
    if separator is not None:
2114 137161c9 Michael Hanselmann
      format_fields.append("%s")
2115 00430f8e Iustin Pop
    elif numfields.Matches(field):
2116 137161c9 Michael Hanselmann
      format_fields.append("%*s")
2117 137161c9 Michael Hanselmann
    else:
2118 137161c9 Michael Hanselmann
      format_fields.append("%-*s")
2119 137161c9 Michael Hanselmann
2120 137161c9 Michael Hanselmann
  if separator is None:
2121 137161c9 Michael Hanselmann
    mlens = [0 for name in fields]
2122 c04bc777 Iustin Pop
    format_str = ' '.join(format_fields)
2123 137161c9 Michael Hanselmann
  else:
2124 c04bc777 Iustin Pop
    format_str = separator.replace("%", "%%").join(format_fields)
2125 137161c9 Michael Hanselmann
2126 137161c9 Michael Hanselmann
  for row in data:
2127 dcbd6288 Guido Trotter
    if row is None:
2128 dcbd6288 Guido Trotter
      continue
2129 137161c9 Michael Hanselmann
    for idx, val in enumerate(row):
2130 00430f8e Iustin Pop
      if unitfields.Matches(fields[idx]):
2131 137161c9 Michael Hanselmann
        try:
2132 137161c9 Michael Hanselmann
          val = int(val)
2133 691744c4 Iustin Pop
        except (TypeError, ValueError):
2134 137161c9 Michael Hanselmann
          pass
2135 137161c9 Michael Hanselmann
        else:
2136 9fbfbb7b Iustin Pop
          val = row[idx] = utils.FormatUnit(val, units)
2137 01ca31ae Iustin Pop
      val = row[idx] = str(val)
2138 137161c9 Michael Hanselmann
      if separator is None:
2139 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(val))
2140 137161c9 Michael Hanselmann
2141 16be8703 Iustin Pop
  result = []
2142 137161c9 Michael Hanselmann
  if headers:
2143 137161c9 Michael Hanselmann
    args = []
2144 137161c9 Michael Hanselmann
    for idx, name in enumerate(fields):
2145 137161c9 Michael Hanselmann
      hdr = headers[name]
2146 137161c9 Michael Hanselmann
      if separator is None:
2147 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(hdr))
2148 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2149 137161c9 Michael Hanselmann
      args.append(hdr)
2150 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2151 137161c9 Michael Hanselmann
2152 ec39d63c Michael Hanselmann
  if separator is None:
2153 ec39d63c Michael Hanselmann
    assert len(mlens) == len(fields)
2154 ec39d63c Michael Hanselmann
2155 ec39d63c Michael Hanselmann
    if fields and not numfields.Matches(fields[-1]):
2156 ec39d63c Michael Hanselmann
      mlens[-1] = 0
2157 ec39d63c Michael Hanselmann
2158 137161c9 Michael Hanselmann
  for line in data:
2159 137161c9 Michael Hanselmann
    args = []
2160 dcbd6288 Guido Trotter
    if line is None:
2161 dcbd6288 Guido Trotter
      line = ['-' for _ in fields]
2162 f1501b3f Michael Hanselmann
    for idx in range(len(fields)):
2163 137161c9 Michael Hanselmann
      if separator is None:
2164 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2165 137161c9 Michael Hanselmann
      args.append(line[idx])
2166 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2167 16be8703 Iustin Pop
2168 16be8703 Iustin Pop
  return result
2169 3386e7a9 Iustin Pop
2170 3386e7a9 Iustin Pop
2171 3386e7a9 Iustin Pop
def FormatTimestamp(ts):
2172 3386e7a9 Iustin Pop
  """Formats a given timestamp.
2173 3386e7a9 Iustin Pop

2174 3386e7a9 Iustin Pop
  @type ts: timestamp
2175 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
2176 3386e7a9 Iustin Pop

2177 3386e7a9 Iustin Pop
  @rtype: string
2178 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
2179 3386e7a9 Iustin Pop

2180 3386e7a9 Iustin Pop
  """
2181 e0ec0ff6 Iustin Pop
  if not isinstance (ts, (tuple, list)) or len(ts) != 2:
2182 e0ec0ff6 Iustin Pop
    return '?'
2183 3386e7a9 Iustin Pop
  sec, usec = ts
2184 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
2185 2241e2b9 Iustin Pop
2186 2241e2b9 Iustin Pop
2187 2241e2b9 Iustin Pop
def ParseTimespec(value):
2188 2241e2b9 Iustin Pop
  """Parse a time specification.
2189 2241e2b9 Iustin Pop

2190 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
2191 2241e2b9 Iustin Pop

2192 2241e2b9 Iustin Pop
    - s: seconds
2193 2241e2b9 Iustin Pop
    - m: minutes
2194 2241e2b9 Iustin Pop
    - h: hours
2195 2241e2b9 Iustin Pop
    - d: day
2196 2241e2b9 Iustin Pop
    - w: weeks
2197 2241e2b9 Iustin Pop

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

2200 2241e2b9 Iustin Pop
  """
2201 2241e2b9 Iustin Pop
  value = str(value)
2202 2241e2b9 Iustin Pop
  if not value:
2203 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
2204 2241e2b9 Iustin Pop
  suffix_map = {
2205 2241e2b9 Iustin Pop
    's': 1,
2206 2241e2b9 Iustin Pop
    'm': 60,
2207 2241e2b9 Iustin Pop
    'h': 3600,
2208 2241e2b9 Iustin Pop
    'd': 86400,
2209 2241e2b9 Iustin Pop
    'w': 604800,
2210 2241e2b9 Iustin Pop
    }
2211 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
2212 2241e2b9 Iustin Pop
    try:
2213 2241e2b9 Iustin Pop
      value = int(value)
2214 691744c4 Iustin Pop
    except (TypeError, ValueError):
2215 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2216 2241e2b9 Iustin Pop
  else:
2217 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
2218 2241e2b9 Iustin Pop
    value = value[:-1]
2219 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
2220 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
2221 2241e2b9 Iustin Pop
                                 " suffix passed)")
2222 2241e2b9 Iustin Pop
    try:
2223 2241e2b9 Iustin Pop
      value = int(value) * multiplier
2224 691744c4 Iustin Pop
    except (TypeError, ValueError):
2225 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2226 2241e2b9 Iustin Pop
  return value
2227 46fbdd04 Iustin Pop
2228 46fbdd04 Iustin Pop
2229 e9e26bb3 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False, secondary_ips=False,
2230 e9e26bb3 Iustin Pop
                   filter_master=False):
2231 4040a784 Iustin Pop
  """Returns the names of online nodes.
2232 4040a784 Iustin Pop

2233 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
2234 4040a784 Iustin Pop
  the online nodes.
2235 4040a784 Iustin Pop

2236 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
2237 4040a784 Iustin Pop
      offline ones)
2238 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
2239 4040a784 Iustin Pop
  @type nowarn: boolean
2240 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
2241 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
2242 4040a784 Iustin Pop
      note is not displayed
2243 e9e26bb3 Iustin Pop
  @type secondary_ips: boolean
2244 e9e26bb3 Iustin Pop
  @param secondary_ips: if True, return the secondary IPs instead of the
2245 e9e26bb3 Iustin Pop
      names, useful for doing network traffic over the replication interface
2246 e9e26bb3 Iustin Pop
      (if any)
2247 e9e26bb3 Iustin Pop
  @type filter_master: boolean
2248 e9e26bb3 Iustin Pop
  @param filter_master: if True, do not return the master node in the list
2249 e9e26bb3 Iustin Pop
      (useful in coordination with secondary_ips where we cannot check our
2250 e9e26bb3 Iustin Pop
      node name against the list)
2251 4040a784 Iustin Pop

2252 4040a784 Iustin Pop
  """
2253 4040a784 Iustin Pop
  if cl is None:
2254 4040a784 Iustin Pop
    cl = GetClient()
2255 4040a784 Iustin Pop
2256 e9e26bb3 Iustin Pop
  if secondary_ips:
2257 e9e26bb3 Iustin Pop
    name_idx = 2
2258 e9e26bb3 Iustin Pop
  else:
2259 e9e26bb3 Iustin Pop
    name_idx = 0
2260 e9e26bb3 Iustin Pop
2261 e9e26bb3 Iustin Pop
  if filter_master:
2262 e9e26bb3 Iustin Pop
    master_node = cl.QueryConfigValues(["master_node"])[0]
2263 e9e26bb3 Iustin Pop
    filter_fn = lambda x: x != master_node
2264 e9e26bb3 Iustin Pop
  else:
2265 e9e26bb3 Iustin Pop
    filter_fn = lambda _: True
2266 e9e26bb3 Iustin Pop
2267 e9e26bb3 Iustin Pop
  result = cl.QueryNodes(names=nodes, fields=["name", "offline", "sip"],
2268 2e7b8369 Iustin Pop
                         use_locking=False)
2269 4040a784 Iustin Pop
  offline = [row[0] for row in result if row[1]]
2270 4040a784 Iustin Pop
  if offline and not nowarn:
2271 1f864b60 Iustin Pop
    ToStderr("Note: skipping offline node(s): %s" % utils.CommaJoin(offline))
2272 e9e26bb3 Iustin Pop
  return [row[name_idx] for row in result if not row[1] and filter_fn(row[0])]
2273 4040a784 Iustin Pop
2274 4040a784 Iustin Pop
2275 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
2276 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
2277 46fbdd04 Iustin Pop

2278 46fbdd04 Iustin Pop
  @type stream: file object
2279 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
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
  if args:
2285 46fbdd04 Iustin Pop
    args = tuple(args)
2286 46fbdd04 Iustin Pop
    stream.write(txt % args)
2287 46fbdd04 Iustin Pop
  else:
2288 46fbdd04 Iustin Pop
    stream.write(txt)
2289 46fbdd04 Iustin Pop
  stream.write('\n')
2290 46fbdd04 Iustin Pop
  stream.flush()
2291 46fbdd04 Iustin Pop
2292 46fbdd04 Iustin Pop
2293 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
2294 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
2295 46fbdd04 Iustin Pop

2296 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2297 46fbdd04 Iustin Pop

2298 46fbdd04 Iustin Pop
  @type txt: str
2299 46fbdd04 Iustin Pop
  @param txt: the message
2300 46fbdd04 Iustin Pop

2301 46fbdd04 Iustin Pop
  """
2302 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
2303 46fbdd04 Iustin Pop
2304 46fbdd04 Iustin Pop
2305 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
2306 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
2307 46fbdd04 Iustin Pop

2308 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2309 46fbdd04 Iustin Pop

2310 46fbdd04 Iustin Pop
  @type txt: str
2311 46fbdd04 Iustin Pop
  @param txt: the message
2312 46fbdd04 Iustin Pop

2313 46fbdd04 Iustin Pop
  """
2314 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
2315 479636a3 Iustin Pop
2316 479636a3 Iustin Pop
2317 479636a3 Iustin Pop
class JobExecutor(object):
2318 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
2319 479636a3 Iustin Pop

2320 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
2321 479636a3 Iustin Pop
  GetResults() calls.
2322 479636a3 Iustin Pop

2323 479636a3 Iustin Pop
  """
2324 919ca415 Iustin Pop
  def __init__(self, cl=None, verbose=True, opts=None, feedback_fn=None):
2325 479636a3 Iustin Pop
    self.queue = []
2326 479636a3 Iustin Pop
    if cl is None:
2327 479636a3 Iustin Pop
      cl = GetClient()
2328 479636a3 Iustin Pop
    self.cl = cl
2329 479636a3 Iustin Pop
    self.verbose = verbose
2330 23b4b983 Iustin Pop
    self.jobs = []
2331 cff5fa7f Iustin Pop
    self.opts = opts
2332 919ca415 Iustin Pop
    self.feedback_fn = feedback_fn
2333 479636a3 Iustin Pop
2334 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
2335 23b4b983 Iustin Pop
    """Record a job for later submit.
2336 479636a3 Iustin Pop

2337 479636a3 Iustin Pop
    @type name: string
2338 479636a3 Iustin Pop
    @param name: a description of the job, will be used in WaitJobSet
2339 479636a3 Iustin Pop
    """
2340 cff5fa7f Iustin Pop
    SetGenericOpcodeOpts(ops, self.opts)
2341 23b4b983 Iustin Pop
    self.queue.append((name, ops))
2342 23b4b983 Iustin Pop
2343 66ecc479 Guido Trotter
  def SubmitPending(self, each=False):
2344 23b4b983 Iustin Pop
    """Submit all pending jobs.
2345 23b4b983 Iustin Pop

2346 23b4b983 Iustin Pop
    """
2347 66ecc479 Guido Trotter
    if each:
2348 66ecc479 Guido Trotter
      results = []
2349 66ecc479 Guido Trotter
      for row in self.queue:
2350 66ecc479 Guido Trotter
        # SubmitJob will remove the success status, but raise an exception if
2351 66ecc479 Guido Trotter
        # the submission fails, so we'll notice that anyway.
2352 66ecc479 Guido Trotter
        results.append([True, self.cl.SubmitJob(row[1])])
2353 66ecc479 Guido Trotter
    else:
2354 66ecc479 Guido Trotter
      results = self.cl.SubmitManyJobs([row[1] for row in self.queue])
2355 5299e61f Iustin Pop
    for (idx, ((status, data), (name, _))) in enumerate(zip(results,
2356 5299e61f Iustin Pop
                                                            self.queue)):
2357 5299e61f Iustin Pop
      self.jobs.append((idx, status, data, name))
2358 5299e61f Iustin Pop
2359 5299e61f Iustin Pop
  def _ChooseJob(self):
2360 5299e61f Iustin Pop
    """Choose a non-waiting/queued job to poll next.
2361 5299e61f Iustin Pop

2362 5299e61f Iustin Pop
    """
2363 5299e61f Iustin Pop
    assert self.jobs, "_ChooseJob called with empty job list"
2364 5299e61f Iustin Pop
2365 5299e61f Iustin Pop
    result = self.cl.QueryJobs([i[2] for i in self.jobs], ["status"])
2366 5299e61f Iustin Pop
    assert result
2367 5299e61f Iustin Pop
2368 5299e61f Iustin Pop
    for job_data, status in zip(self.jobs, result):
2369 91c622a8 Iustin Pop
      if (isinstance(status, list) and status and
2370 91c622a8 Iustin Pop
          status[0] in (constants.JOB_STATUS_QUEUED,
2371 91c622a8 Iustin Pop
                        constants.JOB_STATUS_WAITLOCK,
2372 91c622a8 Iustin Pop
                        constants.JOB_STATUS_CANCELING)):
2373 91c622a8 Iustin Pop
        # job is still present and waiting
2374 5299e61f Iustin Pop
        continue
2375 91c622a8 Iustin Pop
      # good candidate found (either running job or lost job)
2376 5299e61f Iustin Pop
      self.jobs.remove(job_data)
2377 5299e61f Iustin Pop
      return job_data
2378 5299e61f Iustin Pop
2379 5299e61f Iustin Pop
    # no job found
2380 5299e61f Iustin Pop
    return self.jobs.pop(0)
2381 479636a3 Iustin Pop
2382 479636a3 Iustin Pop
  def GetResults(self):
2383 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
2384 479636a3 Iustin Pop

2385 479636a3 Iustin Pop
    @rtype: list
2386 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
2387 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
2388 479636a3 Iustin Pop
        there will be the error message
2389 479636a3 Iustin Pop

2390 479636a3 Iustin Pop
    """
2391 23b4b983 Iustin Pop
    if not self.jobs:
2392 23b4b983 Iustin Pop
      self.SubmitPending()
2393 479636a3 Iustin Pop
    results = []
2394 479636a3 Iustin Pop
    if self.verbose:
2395 5299e61f Iustin Pop
      ok_jobs = [row[2] for row in self.jobs if row[1]]
2396 23b4b983 Iustin Pop
      if ok_jobs:
2397 1f864b60 Iustin Pop
        ToStdout("Submitted jobs %s", utils.CommaJoin(ok_jobs))
2398 5299e61f Iustin Pop
2399 5299e61f Iustin Pop
    # first, remove any non-submitted jobs
2400 cea881e5 Michael Hanselmann
    self.jobs, failures = compat.partition(self.jobs, lambda x: x[1])
2401 5299e61f Iustin Pop
    for idx, _, jid, name in failures:
2402 c63355f2 Iustin Pop
      ToStderr("Failed to submit job for %s: %s", name, jid)
2403 c63355f2 Iustin Pop
      results.append((idx, False, jid))
2404 5299e61f Iustin Pop
2405 5299e61f Iustin Pop
    while self.jobs:
2406 5299e61f Iustin Pop
      (idx, _, jid, name) = self._ChooseJob()
2407 5299e61f Iustin Pop
      ToStdout("Waiting for job %s for %s...", jid, name)
2408 479636a3 Iustin Pop
      try:
2409 919ca415 Iustin Pop
        job_result = PollJob(jid, cl=self.cl, feedback_fn=self.feedback_fn)
2410 479636a3 Iustin Pop
        success = True
2411 91c622a8 Iustin Pop
      except errors.JobLost, err:
2412 91c622a8 Iustin Pop
        _, job_result = FormatError(err)
2413 91c622a8 Iustin Pop
        ToStderr("Job %s for %s has been archived, cannot check its result",
2414 91c622a8 Iustin Pop
                 jid, name)
2415 91c622a8 Iustin Pop
        success = False
2416 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
2417 479636a3 Iustin Pop
        _, job_result = FormatError(err)
2418 479636a3 Iustin Pop
        success = False
2419 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
2420 479636a3 Iustin Pop
        ToStderr("Job %s for %s has failed: %s", jid, name, job_result)
2421 479636a3 Iustin Pop
2422 5299e61f Iustin Pop
      results.append((idx, success, job_result))
2423 5299e61f Iustin Pop
2424 5299e61f Iustin Pop
    # sort based on the index, then drop it
2425 5299e61f Iustin Pop
    results.sort()
2426 5299e61f Iustin Pop
    results = [i[1:] for i in results]
2427 5299e61f Iustin Pop
2428 479636a3 Iustin Pop
    return results
2429 479636a3 Iustin Pop
2430 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
2431 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
2432 479636a3 Iustin Pop

2433 479636a3 Iustin Pop
    @type wait: boolean
2434 479636a3 Iustin Pop
    @param wait: whether to wait or not
2435 479636a3 Iustin Pop

2436 479636a3 Iustin Pop
    """
2437 479636a3 Iustin Pop
    if wait:
2438 479636a3 Iustin Pop
      return self.GetResults()
2439 479636a3 Iustin Pop
    else:
2440 23b4b983 Iustin Pop
      if not self.jobs:
2441 23b4b983 Iustin Pop
        self.SubmitPending()
2442 71834b2a Guido Trotter
      for _, status, result, name in self.jobs:
2443 23b4b983 Iustin Pop
        if status:
2444 23b4b983 Iustin Pop
          ToStdout("%s: %s", result, name)
2445 23b4b983 Iustin Pop
        else:
2446 23b4b983 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)
2447 53a8a54d Iustin Pop
      return [row[1:3] for row in self.jobs]