Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ 36e247e1

History | View | Annotate | Download (80 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 84a5b33c Michael Hanselmann
  "PRIORITY_OPT",
126 6d4a1656 Michael Hanselmann
  "RAPI_CERT_OPT",
127 b8d0f938 Iustin Pop
  "READD_OPT",
128 12054861 Iustin Pop
  "REBOOT_TYPE_OPT",
129 8d8d650c Michael Hanselmann
  "REMOVE_INSTANCE_OPT",
130 fdad8c4d Balazs Lecz
  "REMOVE_UIDS_OPT",
131 f38ea602 Iustin Pop
  "RESERVED_LVS_OPT",
132 31d97b2a Guido Trotter
  "ROMAN_OPT",
133 8d823629 Iustin Pop
  "SECONDARY_IP_OPT",
134 67840b40 Iustin Pop
  "SELECT_OS_OPT",
135 4abc4f1e Iustin Pop
  "SEP_OPT",
136 fdcf4d84 Iustin Pop
  "SHOWCMD_OPT",
137 7e5eaaa8 Guido Trotter
  "SHUTDOWN_TIMEOUT_OPT",
138 f36d7d81 Iustin Pop
  "SINGLE_NODE_OPT",
139 df62e5db Iustin Pop
  "SRC_DIR_OPT",
140 df62e5db Iustin Pop
  "SRC_NODE_OPT",
141 4abc4f1e Iustin Pop
  "SUBMIT_OPT",
142 99a8c799 Iustin Pop
  "STATIC_OPT",
143 4abc4f1e Iustin Pop
  "SYNC_OPT",
144 4abc4f1e Iustin Pop
  "TAG_SRC_OPT",
145 b5762e2a Guido Trotter
  "TIMEOUT_OPT",
146 1338f2b4 Balazs Lecz
  "UIDPOOL_OPT",
147 4abc4f1e Iustin Pop
  "USEUNITS_OPT",
148 74adc100 Iustin Pop
  "USE_REPL_NET_OPT",
149 9cdb9578 Iustin Pop
  "VERBOSE_OPT",
150 b58726e8 Iustin Pop
  "VG_NAME_OPT",
151 1f587d3d Iustin Pop
  "YES_DOIT_OPT",
152 4abc4f1e Iustin Pop
  # Generic functions for CLI programs
153 4abc4f1e Iustin Pop
  "GenericMain",
154 d77490c5 Iustin Pop
  "GenericInstanceCreate",
155 4abc4f1e Iustin Pop
  "GetClient",
156 4abc4f1e Iustin Pop
  "GetOnlineNodes",
157 4abc4f1e Iustin Pop
  "JobExecutor",
158 4abc4f1e Iustin Pop
  "JobSubmittedException",
159 4abc4f1e Iustin Pop
  "ParseTimespec",
160 7e49b6ce Michael Hanselmann
  "RunWhileClusterStopped",
161 4abc4f1e Iustin Pop
  "SubmitOpCode",
162 4abc4f1e Iustin Pop
  "SubmitOrSend",
163 4abc4f1e Iustin Pop
  "UsesRPC",
164 4abc4f1e Iustin Pop
  # Formatting functions
165 4abc4f1e Iustin Pop
  "ToStderr", "ToStdout",
166 4abc4f1e Iustin Pop
  "FormatError",
167 4abc4f1e Iustin Pop
  "GenerateTable",
168 4abc4f1e Iustin Pop
  "AskUser",
169 4abc4f1e Iustin Pop
  "FormatTimestamp",
170 8a7f1c61 Michael Hanselmann
  "FormatLogMessage",
171 4abc4f1e Iustin Pop
  # Tags functions
172 4abc4f1e Iustin Pop
  "ListTags",
173 4abc4f1e Iustin Pop
  "AddTags",
174 4abc4f1e Iustin Pop
  "RemoveTags",
175 4abc4f1e Iustin Pop
  # command line options support infrastructure
176 4abc4f1e Iustin Pop
  "ARGS_MANY_INSTANCES",
177 4abc4f1e Iustin Pop
  "ARGS_MANY_NODES",
178 4abc4f1e Iustin Pop
  "ARGS_NONE",
179 4abc4f1e Iustin Pop
  "ARGS_ONE_INSTANCE",
180 4abc4f1e Iustin Pop
  "ARGS_ONE_NODE",
181 f9faf9c3 René Nussbaumer
  "ARGS_ONE_OS",
182 4abc4f1e Iustin Pop
  "ArgChoice",
183 4abc4f1e Iustin Pop
  "ArgCommand",
184 4abc4f1e Iustin Pop
  "ArgFile",
185 4abc4f1e Iustin Pop
  "ArgHost",
186 4abc4f1e Iustin Pop
  "ArgInstance",
187 4abc4f1e Iustin Pop
  "ArgJobId",
188 4abc4f1e Iustin Pop
  "ArgNode",
189 f9faf9c3 René Nussbaumer
  "ArgOs",
190 4abc4f1e Iustin Pop
  "ArgSuggest",
191 4abc4f1e Iustin Pop
  "ArgUnknown",
192 4abc4f1e Iustin Pop
  "OPT_COMPL_INST_ADD_NODES",
193 4abc4f1e Iustin Pop
  "OPT_COMPL_MANY_NODES",
194 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_IALLOCATOR",
195 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_INSTANCE",
196 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_NODE",
197 36e247e1 Guido Trotter
  "OPT_COMPL_ONE_NODEGROUP",
198 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_OS",
199 4abc4f1e Iustin Pop
  "cli_option",
200 4abc4f1e Iustin Pop
  "SplitNodeOption",
201 07150497 Guido Trotter
  "CalculateOSNames",
202 a4ebd726 Michael Hanselmann
  "ParseFields",
203 4abc4f1e Iustin Pop
  ]
204 846baef9 Iustin Pop
205 8b46606c Guido Trotter
NO_PREFIX = "no_"
206 8b46606c Guido Trotter
UN_PREFIX = "-"
207 846baef9 Iustin Pop
208 84a5b33c Michael Hanselmann
#: Priorities (sorted)
209 84a5b33c Michael Hanselmann
_PRIORITY_NAMES = [
210 84a5b33c Michael Hanselmann
  ("low", constants.OP_PRIO_LOW),
211 84a5b33c Michael Hanselmann
  ("normal", constants.OP_PRIO_NORMAL),
212 84a5b33c Michael Hanselmann
  ("high", constants.OP_PRIO_HIGH),
213 84a5b33c Michael Hanselmann
  ]
214 84a5b33c Michael Hanselmann
215 84a5b33c Michael Hanselmann
#: Priority dictionary for easier lookup
216 84a5b33c Michael Hanselmann
# TODO: Replace this and _PRIORITY_NAMES with a single sorted dictionary once
217 84a5b33c Michael Hanselmann
# we migrate to Python 2.6
218 84a5b33c Michael Hanselmann
_PRIONAME_TO_VALUE = dict(_PRIORITY_NAMES)
219 84a5b33c Michael Hanselmann
220 03298ebe Michael Hanselmann
221 863d7f46 Michael Hanselmann
class _Argument:
222 7260cfbe Iustin Pop
  def __init__(self, min=0, max=None): # pylint: disable-msg=W0622
223 863d7f46 Michael Hanselmann
    self.min = min
224 863d7f46 Michael Hanselmann
    self.max = max
225 863d7f46 Michael Hanselmann
226 863d7f46 Michael Hanselmann
  def __repr__(self):
227 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s>" %
228 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max))
229 863d7f46 Michael Hanselmann
230 863d7f46 Michael Hanselmann
231 863d7f46 Michael Hanselmann
class ArgSuggest(_Argument):
232 863d7f46 Michael Hanselmann
  """Suggesting argument.
233 863d7f46 Michael Hanselmann

234 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor.
235 863d7f46 Michael Hanselmann

236 863d7f46 Michael Hanselmann
  """
237 7260cfbe Iustin Pop
  # pylint: disable-msg=W0622
238 863d7f46 Michael Hanselmann
  def __init__(self, min=0, max=None, choices=None):
239 863d7f46 Michael Hanselmann
    _Argument.__init__(self, min=min, max=max)
240 863d7f46 Michael Hanselmann
    self.choices = choices
241 863d7f46 Michael Hanselmann
242 863d7f46 Michael Hanselmann
  def __repr__(self):
243 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s choices=%r>" %
244 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max, self.choices))
245 863d7f46 Michael Hanselmann
246 863d7f46 Michael Hanselmann
247 863d7f46 Michael Hanselmann
class ArgChoice(ArgSuggest):
248 863d7f46 Michael Hanselmann
  """Choice argument.
249 863d7f46 Michael Hanselmann

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

253 863d7f46 Michael Hanselmann
  """
254 863d7f46 Michael Hanselmann
255 863d7f46 Michael Hanselmann
256 863d7f46 Michael Hanselmann
class ArgUnknown(_Argument):
257 863d7f46 Michael Hanselmann
  """Unknown argument to program (e.g. determined at runtime).
258 863d7f46 Michael Hanselmann

259 863d7f46 Michael Hanselmann
  """
260 863d7f46 Michael Hanselmann
261 863d7f46 Michael Hanselmann
262 863d7f46 Michael Hanselmann
class ArgInstance(_Argument):
263 863d7f46 Michael Hanselmann
  """Instances argument.
264 863d7f46 Michael Hanselmann

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

271 863d7f46 Michael Hanselmann
  """
272 863d7f46 Michael Hanselmann
273 863d7f46 Michael Hanselmann
class ArgJobId(_Argument):
274 863d7f46 Michael Hanselmann
  """Job ID argument.
275 863d7f46 Michael Hanselmann

276 863d7f46 Michael Hanselmann
  """
277 863d7f46 Michael Hanselmann
278 863d7f46 Michael Hanselmann
279 863d7f46 Michael Hanselmann
class ArgFile(_Argument):
280 863d7f46 Michael Hanselmann
  """File path argument.
281 863d7f46 Michael Hanselmann

282 863d7f46 Michael Hanselmann
  """
283 863d7f46 Michael Hanselmann
284 863d7f46 Michael Hanselmann
285 863d7f46 Michael Hanselmann
class ArgCommand(_Argument):
286 863d7f46 Michael Hanselmann
  """Command argument.
287 863d7f46 Michael Hanselmann

288 863d7f46 Michael Hanselmann
  """
289 863d7f46 Michael Hanselmann
290 863d7f46 Michael Hanselmann
291 83ec7961 Michael Hanselmann
class ArgHost(_Argument):
292 83ec7961 Michael Hanselmann
  """Host argument.
293 83ec7961 Michael Hanselmann

294 83ec7961 Michael Hanselmann
  """
295 83ec7961 Michael Hanselmann
296 83ec7961 Michael Hanselmann
297 f9faf9c3 René Nussbaumer
class ArgOs(_Argument):
298 f9faf9c3 René Nussbaumer
  """OS argument.
299 f9faf9c3 René Nussbaumer

300 f9faf9c3 René Nussbaumer
  """
301 f9faf9c3 René Nussbaumer
302 f9faf9c3 René Nussbaumer
303 4a265c08 Michael Hanselmann
ARGS_NONE = []
304 4a265c08 Michael Hanselmann
ARGS_MANY_INSTANCES = [ArgInstance()]
305 4a265c08 Michael Hanselmann
ARGS_MANY_NODES = [ArgNode()]
306 4a265c08 Michael Hanselmann
ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
307 4a265c08 Michael Hanselmann
ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
308 f9faf9c3 René Nussbaumer
ARGS_ONE_OS = [ArgOs(min=1, max=1)]
309 4a265c08 Michael Hanselmann
310 4a265c08 Michael Hanselmann
311 846baef9 Iustin Pop
def _ExtractTagsObject(opts, args):
312 846baef9 Iustin Pop
  """Extract the tag type object.
313 846baef9 Iustin Pop

314 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
315 846baef9 Iustin Pop

316 846baef9 Iustin Pop
  """
317 846baef9 Iustin Pop
  if not hasattr(opts, "tag_type"):
318 846baef9 Iustin Pop
    raise errors.ProgrammerError("tag_type not passed to _ExtractTagsObject")
319 846baef9 Iustin Pop
  kind = opts.tag_type
320 846baef9 Iustin Pop
  if kind == constants.TAG_CLUSTER:
321 846baef9 Iustin Pop
    retval = kind, kind
322 846baef9 Iustin Pop
  elif kind == constants.TAG_NODE or kind == constants.TAG_INSTANCE:
323 846baef9 Iustin Pop
    if not args:
324 0c434948 Iustin Pop
      raise errors.OpPrereqError("no arguments passed to the command")
325 846baef9 Iustin Pop
    name = args.pop(0)
326 846baef9 Iustin Pop
    retval = kind, name
327 846baef9 Iustin Pop
  else:
328 846baef9 Iustin Pop
    raise errors.ProgrammerError("Unhandled tag type '%s'" % kind)
329 846baef9 Iustin Pop
  return retval
330 846baef9 Iustin Pop
331 846baef9 Iustin Pop
332 810c50b7 Iustin Pop
def _ExtendTags(opts, args):
333 810c50b7 Iustin Pop
  """Extend the args if a source file has been given.
334 810c50b7 Iustin Pop

335 810c50b7 Iustin Pop
  This function will extend the tags with the contents of the file
336 810c50b7 Iustin Pop
  passed in the 'tags_source' attribute of the opts parameter. A file
337 810c50b7 Iustin Pop
  named '-' will be replaced by stdin.
338 810c50b7 Iustin Pop

339 810c50b7 Iustin Pop
  """
340 810c50b7 Iustin Pop
  fname = opts.tags_source
341 810c50b7 Iustin Pop
  if fname is None:
342 810c50b7 Iustin Pop
    return
343 810c50b7 Iustin Pop
  if fname == "-":
344 810c50b7 Iustin Pop
    new_fh = sys.stdin
345 810c50b7 Iustin Pop
  else:
346 810c50b7 Iustin Pop
    new_fh = open(fname, "r")
347 810c50b7 Iustin Pop
  new_data = []
348 810c50b7 Iustin Pop
  try:
349 810c50b7 Iustin Pop
    # we don't use the nice 'new_data = [line.strip() for line in fh]'
350 810c50b7 Iustin Pop
    # because of python bug 1633941
351 810c50b7 Iustin Pop
    while True:
352 810c50b7 Iustin Pop
      line = new_fh.readline()
353 810c50b7 Iustin Pop
      if not line:
354 810c50b7 Iustin Pop
        break
355 810c50b7 Iustin Pop
      new_data.append(line.strip())
356 810c50b7 Iustin Pop
  finally:
357 810c50b7 Iustin Pop
    new_fh.close()
358 810c50b7 Iustin Pop
  args.extend(new_data)
359 810c50b7 Iustin Pop
360 810c50b7 Iustin Pop
361 846baef9 Iustin Pop
def ListTags(opts, args):
362 846baef9 Iustin Pop
  """List the tags on a given object.
363 846baef9 Iustin Pop

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

369 846baef9 Iustin Pop
  """
370 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
371 7699c3af Iustin Pop
  cl = GetClient()
372 7699c3af Iustin Pop
  result = cl.QueryTags(kind, name)
373 846baef9 Iustin Pop
  result = list(result)
374 846baef9 Iustin Pop
  result.sort()
375 846baef9 Iustin Pop
  for tag in result:
376 03298ebe Michael Hanselmann
    ToStdout(tag)
377 846baef9 Iustin Pop
378 846baef9 Iustin Pop
379 846baef9 Iustin Pop
def AddTags(opts, args):
380 846baef9 Iustin Pop
  """Add tags on a given object.
381 846baef9 Iustin Pop

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

387 846baef9 Iustin Pop
  """
388 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
389 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
390 846baef9 Iustin Pop
  if not args:
391 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be added")
392 846baef9 Iustin Pop
  op = opcodes.OpAddTags(kind=kind, name=name, tags=args)
393 846baef9 Iustin Pop
  SubmitOpCode(op)
394 846baef9 Iustin Pop
395 846baef9 Iustin Pop
396 846baef9 Iustin Pop
def RemoveTags(opts, args):
397 846baef9 Iustin Pop
  """Remove tags from a given object.
398 846baef9 Iustin Pop

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

404 846baef9 Iustin Pop
  """
405 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
406 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
407 846baef9 Iustin Pop
  if not args:
408 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be removed")
409 846baef9 Iustin Pop
  op = opcodes.OpDelTags(kind=kind, name=name, tags=args)
410 846baef9 Iustin Pop
  SubmitOpCode(op)
411 846baef9 Iustin Pop
412 a8083063 Iustin Pop
413 8929d28c Iustin Pop
def check_unit(option, opt, value): # pylint: disable-msg=W0613
414 65fe4693 Iustin Pop
  """OptParsers custom converter for units.
415 65fe4693 Iustin Pop

416 65fe4693 Iustin Pop
  """
417 a8083063 Iustin Pop
  try:
418 a8083063 Iustin Pop
    return utils.ParseUnit(value)
419 a8083063 Iustin Pop
  except errors.UnitParseError, err:
420 3ecf6786 Iustin Pop
    raise OptionValueError("option %s: %s" % (opt, err))
421 a8083063 Iustin Pop
422 a8083063 Iustin Pop
423 a8469393 Iustin Pop
def _SplitKeyVal(opt, data):
424 a8469393 Iustin Pop
  """Convert a KeyVal string into a dict.
425 a8469393 Iustin Pop

426 a8469393 Iustin Pop
  This function will convert a key=val[,...] string into a dict. Empty
427 a8469393 Iustin Pop
  values will be converted specially: keys which have the prefix 'no_'
428 a8469393 Iustin Pop
  will have the value=False and the prefix stripped, the others will
429 a8469393 Iustin Pop
  have value=True.
430 a8469393 Iustin Pop

431 a8469393 Iustin Pop
  @type opt: string
432 a8469393 Iustin Pop
  @param opt: a string holding the option name for which we process the
433 a8469393 Iustin Pop
      data, used in building error messages
434 a8469393 Iustin Pop
  @type data: string
435 a8469393 Iustin Pop
  @param data: a string of the format key=val,key=val,...
436 a8469393 Iustin Pop
  @rtype: dict
437 a8469393 Iustin Pop
  @return: {key=val, key=val}
438 a8469393 Iustin Pop
  @raises errors.ParameterError: if there are duplicate keys
439 a8469393 Iustin Pop

440 a8469393 Iustin Pop
  """
441 a8469393 Iustin Pop
  kv_dict = {}
442 4f31882e Guido Trotter
  if data:
443 1b3a7656 Iustin Pop
    for elem in utils.UnescapeAndSplit(data, sep=","):
444 4f31882e Guido Trotter
      if "=" in elem:
445 4f31882e Guido Trotter
        key, val = elem.split("=", 1)
446 a8469393 Iustin Pop
      else:
447 4f31882e Guido Trotter
        if elem.startswith(NO_PREFIX):
448 4f31882e Guido Trotter
          key, val = elem[len(NO_PREFIX):], False
449 4f31882e Guido Trotter
        elif elem.startswith(UN_PREFIX):
450 4f31882e Guido Trotter
          key, val = elem[len(UN_PREFIX):], None
451 4f31882e Guido Trotter
        else:
452 4f31882e Guido Trotter
          key, val = elem, True
453 4f31882e Guido Trotter
      if key in kv_dict:
454 4f31882e Guido Trotter
        raise errors.ParameterError("Duplicate key '%s' in option %s" %
455 4f31882e Guido Trotter
                                    (key, opt))
456 4f31882e Guido Trotter
      kv_dict[key] = val
457 a8469393 Iustin Pop
  return kv_dict
458 a8469393 Iustin Pop
459 a8469393 Iustin Pop
460 8929d28c Iustin Pop
def check_ident_key_val(option, opt, value):  # pylint: disable-msg=W0613
461 552c8dff Michael Hanselmann
  """Custom parser for ident:key=val,key=val options.
462 552c8dff Michael Hanselmann

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

466 a8469393 Iustin Pop
  """
467 a8469393 Iustin Pop
  if ":" not in value:
468 8b46606c Guido Trotter
    ident, rest = value, ''
469 a8469393 Iustin Pop
  else:
470 a8469393 Iustin Pop
    ident, rest = value.split(":", 1)
471 8b46606c Guido Trotter
472 8b46606c Guido Trotter
  if ident.startswith(NO_PREFIX):
473 8b46606c Guido Trotter
    if rest:
474 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
475 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
476 8b46606c Guido Trotter
    retval = (ident[len(NO_PREFIX):], False)
477 8b46606c Guido Trotter
  elif ident.startswith(UN_PREFIX):
478 8b46606c Guido Trotter
    if rest:
479 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
480 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
481 8b46606c Guido Trotter
    retval = (ident[len(UN_PREFIX):], None)
482 8b46606c Guido Trotter
  else:
483 a8469393 Iustin Pop
    kv_dict = _SplitKeyVal(opt, rest)
484 a8469393 Iustin Pop
    retval = (ident, kv_dict)
485 a8469393 Iustin Pop
  return retval
486 a8469393 Iustin Pop
487 a8469393 Iustin Pop
488 8929d28c Iustin Pop
def check_key_val(option, opt, value):  # pylint: disable-msg=W0613
489 552c8dff Michael Hanselmann
  """Custom parser class for key=val,key=val options.
490 552c8dff Michael Hanselmann

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

493 a8469393 Iustin Pop
  """
494 a8469393 Iustin Pop
  return _SplitKeyVal(opt, value)
495 a8469393 Iustin Pop
496 a8469393 Iustin Pop
497 e7b61bb0 Iustin Pop
def check_bool(option, opt, value): # pylint: disable-msg=W0613
498 e7b61bb0 Iustin Pop
  """Custom parser for yes/no options.
499 e7b61bb0 Iustin Pop

500 e7b61bb0 Iustin Pop
  This will store the parsed value as either True or False.
501 e7b61bb0 Iustin Pop

502 e7b61bb0 Iustin Pop
  """
503 e7b61bb0 Iustin Pop
  value = value.lower()
504 e7b61bb0 Iustin Pop
  if value == constants.VALUE_FALSE or value == "no":
505 e7b61bb0 Iustin Pop
    return False
506 e7b61bb0 Iustin Pop
  elif value == constants.VALUE_TRUE or value == "yes":
507 e7b61bb0 Iustin Pop
    return True
508 e7b61bb0 Iustin Pop
  else:
509 e7b61bb0 Iustin Pop
    raise errors.ParameterError("Invalid boolean value '%s'" % value)
510 e7b61bb0 Iustin Pop
511 e7b61bb0 Iustin Pop
512 63d44c55 Michael Hanselmann
# completion_suggestion is normally a list. Using numeric values not evaluating
513 63d44c55 Michael Hanselmann
# to False for dynamic completion.
514 63d44c55 Michael Hanselmann
(OPT_COMPL_MANY_NODES,
515 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_NODE,
516 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_INSTANCE,
517 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_OS,
518 2d3ed64b Michael Hanselmann
 OPT_COMPL_ONE_IALLOCATOR,
519 36e247e1 Guido Trotter
 OPT_COMPL_INST_ADD_NODES,
520 36e247e1 Guido Trotter
 OPT_COMPL_ONE_NODEGROUP) = range(100, 107)
521 63d44c55 Michael Hanselmann
522 63d44c55 Michael Hanselmann
OPT_COMPL_ALL = frozenset([
523 63d44c55 Michael Hanselmann
  OPT_COMPL_MANY_NODES,
524 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_NODE,
525 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_INSTANCE,
526 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_OS,
527 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_IALLOCATOR,
528 2d3ed64b Michael Hanselmann
  OPT_COMPL_INST_ADD_NODES,
529 36e247e1 Guido Trotter
  OPT_COMPL_ONE_NODEGROUP,
530 63d44c55 Michael Hanselmann
  ])
531 63d44c55 Michael Hanselmann
532 63d44c55 Michael Hanselmann
533 552c8dff Michael Hanselmann
class CliOption(Option):
534 552c8dff Michael Hanselmann
  """Custom option class for optparse.
535 a8469393 Iustin Pop

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

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

1071 c41eea6e Iustin Pop
  @param argv: the command line
1072 c41eea6e Iustin Pop
  @param commands: dictionary with special contents, see the design
1073 c41eea6e Iustin Pop
      doc for cmdline handling
1074 c41eea6e Iustin Pop
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
1075 098c0958 Michael Hanselmann

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

1147 a8005e17 Michael Hanselmann
  Algorithm:
1148 a8005e17 Michael Hanselmann

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

1151 a8005e17 Michael Hanselmann
    1. For each argument in definition
1152 a8005e17 Michael Hanselmann

1153 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
1154 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
1155 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
1156 a8005e17 Michael Hanselmann

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

1159 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
1160 a8005e17 Michael Hanselmann

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

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

1165 a8005e17 Michael Hanselmann
  """
1166 a8005e17 Michael Hanselmann
  if args and not args_def:
1167 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects no arguments", cmd)
1168 a8005e17 Michael Hanselmann
    return False
1169 a8005e17 Michael Hanselmann
1170 a8005e17 Michael Hanselmann
  min_count = None
1171 a8005e17 Michael Hanselmann
  max_count = None
1172 a8005e17 Michael Hanselmann
  check_max = None
1173 a8005e17 Michael Hanselmann
1174 a8005e17 Michael Hanselmann
  last_idx = len(args_def) - 1
1175 a8005e17 Michael Hanselmann
1176 a8005e17 Michael Hanselmann
  for idx, arg in enumerate(args_def):
1177 a8005e17 Michael Hanselmann
    if min_count is None:
1178 a8005e17 Michael Hanselmann
      min_count = arg.min
1179 a8005e17 Michael Hanselmann
    elif arg.min is not None:
1180 a8005e17 Michael Hanselmann
      min_count += arg.min
1181 a8005e17 Michael Hanselmann
1182 a8005e17 Michael Hanselmann
    if max_count is None:
1183 a8005e17 Michael Hanselmann
      max_count = arg.max
1184 a8005e17 Michael Hanselmann
    elif arg.max is not None:
1185 a8005e17 Michael Hanselmann
      max_count += arg.max
1186 a8005e17 Michael Hanselmann
1187 a8005e17 Michael Hanselmann
    if idx == last_idx:
1188 a8005e17 Michael Hanselmann
      check_max = (arg.max is not None)
1189 a8005e17 Michael Hanselmann
1190 a8005e17 Michael Hanselmann
    elif arg.max is None:
1191 a8005e17 Michael Hanselmann
      raise errors.ProgrammerError("Only the last argument can have max=None")
1192 a8005e17 Michael Hanselmann
1193 a8005e17 Michael Hanselmann
  if check_max:
1194 a8005e17 Michael Hanselmann
    # Command with exact number of arguments
1195 a8005e17 Michael Hanselmann
    if (min_count is not None and max_count is not None and
1196 a8005e17 Michael Hanselmann
        min_count == max_count and len(args) != min_count):
1197 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects %d argument(s)", cmd, min_count)
1198 a8005e17 Michael Hanselmann
      return False
1199 a8005e17 Michael Hanselmann
1200 a8005e17 Michael Hanselmann
    # Command with limited number of arguments
1201 a8005e17 Michael Hanselmann
    if max_count is not None and len(args) > max_count:
1202 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects only %d argument(s)",
1203 a8005e17 Michael Hanselmann
               cmd, max_count)
1204 a8005e17 Michael Hanselmann
      return False
1205 a8005e17 Michael Hanselmann
1206 a8005e17 Michael Hanselmann
  # Command with some required arguments
1207 a8005e17 Michael Hanselmann
  if min_count is not None and len(args) < min_count:
1208 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects at least %d argument(s)",
1209 a8005e17 Michael Hanselmann
             cmd, min_count)
1210 a8005e17 Michael Hanselmann
    return False
1211 a8005e17 Michael Hanselmann
1212 a8005e17 Michael Hanselmann
  return True
1213 a8005e17 Michael Hanselmann
1214 a8005e17 Michael Hanselmann
1215 60d49723 Michael Hanselmann
def SplitNodeOption(value):
1216 60d49723 Michael Hanselmann
  """Splits the value of a --node option.
1217 60d49723 Michael Hanselmann

1218 60d49723 Michael Hanselmann
  """
1219 60d49723 Michael Hanselmann
  if value and ':' in value:
1220 60d49723 Michael Hanselmann
    return value.split(':', 1)
1221 60d49723 Michael Hanselmann
  else:
1222 60d49723 Michael Hanselmann
    return (value, None)
1223 60d49723 Michael Hanselmann
1224 60d49723 Michael Hanselmann
1225 07150497 Guido Trotter
def CalculateOSNames(os_name, os_variants):
1226 07150497 Guido Trotter
  """Calculates all the names an OS can be called, according to its variants.
1227 07150497 Guido Trotter

1228 07150497 Guido Trotter
  @type os_name: string
1229 07150497 Guido Trotter
  @param os_name: base name of the os
1230 07150497 Guido Trotter
  @type os_variants: list or None
1231 07150497 Guido Trotter
  @param os_variants: list of supported variants
1232 07150497 Guido Trotter
  @rtype: list
1233 07150497 Guido Trotter
  @return: list of valid names
1234 07150497 Guido Trotter

1235 07150497 Guido Trotter
  """
1236 07150497 Guido Trotter
  if os_variants:
1237 07150497 Guido Trotter
    return ['%s+%s' % (os_name, v) for v in os_variants]
1238 07150497 Guido Trotter
  else:
1239 07150497 Guido Trotter
    return [os_name]
1240 07150497 Guido Trotter
1241 07150497 Guido Trotter
1242 a4ebd726 Michael Hanselmann
def ParseFields(selected, default):
1243 a4ebd726 Michael Hanselmann
  """Parses the values of "--field"-like options.
1244 a4ebd726 Michael Hanselmann

1245 a4ebd726 Michael Hanselmann
  @type selected: string or None
1246 a4ebd726 Michael Hanselmann
  @param selected: User-selected options
1247 a4ebd726 Michael Hanselmann
  @type default: list
1248 a4ebd726 Michael Hanselmann
  @param default: Default fields
1249 a4ebd726 Michael Hanselmann

1250 a4ebd726 Michael Hanselmann
  """
1251 a4ebd726 Michael Hanselmann
  if selected is None:
1252 a4ebd726 Michael Hanselmann
    return default
1253 a4ebd726 Michael Hanselmann
1254 a4ebd726 Michael Hanselmann
  if selected.startswith("+"):
1255 a4ebd726 Michael Hanselmann
    return default + selected[1:].split(",")
1256 a4ebd726 Michael Hanselmann
1257 a4ebd726 Michael Hanselmann
  return selected.split(",")
1258 a4ebd726 Michael Hanselmann
1259 a4ebd726 Michael Hanselmann
1260 e0e916fe Iustin Pop
UsesRPC = rpc.RunWithRPC
1261 4331f6cd Michael Hanselmann
1262 4331f6cd Michael Hanselmann
1263 47988778 Iustin Pop
def AskUser(text, choices=None):
1264 47988778 Iustin Pop
  """Ask the user a question.
1265 a8083063 Iustin Pop

1266 c41eea6e Iustin Pop
  @param text: the question to ask
1267 a8083063 Iustin Pop

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

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

1277 a8083063 Iustin Pop
  """
1278 47988778 Iustin Pop
  if choices is None:
1279 47988778 Iustin Pop
    choices = [('y', True, 'Perform the operation'),
1280 47988778 Iustin Pop
               ('n', False, 'Do not perform the operation')]
1281 47988778 Iustin Pop
  if not choices or not isinstance(choices, list):
1282 5bbd3f7f Michael Hanselmann
    raise errors.ProgrammerError("Invalid choices argument to AskUser")
1283 47988778 Iustin Pop
  for entry in choices:
1284 47988778 Iustin Pop
    if not isinstance(entry, tuple) or len(entry) < 3 or entry[0] == '?':
1285 5bbd3f7f Michael Hanselmann
      raise errors.ProgrammerError("Invalid choices element to AskUser")
1286 47988778 Iustin Pop
1287 47988778 Iustin Pop
  answer = choices[-1][1]
1288 47988778 Iustin Pop
  new_text = []
1289 47988778 Iustin Pop
  for line in text.splitlines():
1290 47988778 Iustin Pop
    new_text.append(textwrap.fill(line, 70, replace_whitespace=False))
1291 47988778 Iustin Pop
  text = "\n".join(new_text)
1292 a8083063 Iustin Pop
  try:
1293 3023170f Iustin Pop
    f = file("/dev/tty", "a+")
1294 a8083063 Iustin Pop
  except IOError:
1295 47988778 Iustin Pop
    return answer
1296 a8083063 Iustin Pop
  try:
1297 47988778 Iustin Pop
    chars = [entry[0] for entry in choices]
1298 47988778 Iustin Pop
    chars[-1] = "[%s]" % chars[-1]
1299 47988778 Iustin Pop
    chars.append('?')
1300 47988778 Iustin Pop
    maps = dict([(entry[0], entry[1]) for entry in choices])
1301 47988778 Iustin Pop
    while True:
1302 47988778 Iustin Pop
      f.write(text)
1303 47988778 Iustin Pop
      f.write('\n')
1304 47988778 Iustin Pop
      f.write("/".join(chars))
1305 47988778 Iustin Pop
      f.write(": ")
1306 47988778 Iustin Pop
      line = f.readline(2).strip().lower()
1307 47988778 Iustin Pop
      if line in maps:
1308 47988778 Iustin Pop
        answer = maps[line]
1309 47988778 Iustin Pop
        break
1310 47988778 Iustin Pop
      elif line == '?':
1311 47988778 Iustin Pop
        for entry in choices:
1312 47988778 Iustin Pop
          f.write(" %s - %s\n" % (entry[0], entry[2]))
1313 47988778 Iustin Pop
        f.write("\n")
1314 47988778 Iustin Pop
        continue
1315 a8083063 Iustin Pop
  finally:
1316 a8083063 Iustin Pop
    f.close()
1317 a8083063 Iustin Pop
  return answer
1318 a8083063 Iustin Pop
1319 a8083063 Iustin Pop
1320 e9d741b6 Iustin Pop
class JobSubmittedException(Exception):
1321 e9d741b6 Iustin Pop
  """Job was submitted, client should exit.
1322 e9d741b6 Iustin Pop

1323 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1324 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1325 e9d741b6 Iustin Pop

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

1328 e9d741b6 Iustin Pop
  """
1329 e9d741b6 Iustin Pop
1330 e9d741b6 Iustin Pop
1331 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1332 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1333 a8083063 Iustin Pop

1334 0a1e74d9 Iustin Pop
  @type ops: list
1335 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1336 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1337 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1338 0a1e74d9 Iustin Pop
             if None, a new client will be created
1339 a8083063 Iustin Pop

1340 a8083063 Iustin Pop
  """
1341 e2212007 Iustin Pop
  if cl is None:
1342 b33e986b Iustin Pop
    cl = GetClient()
1343 685ee993 Iustin Pop
1344 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1345 0a1e74d9 Iustin Pop
1346 0a1e74d9 Iustin Pop
  return job_id
1347 0a1e74d9 Iustin Pop
1348 0a1e74d9 Iustin Pop
1349 4e338533 Michael Hanselmann
def GenericPollJob(job_id, cbs, report_cbs):
1350 4e338533 Michael Hanselmann
  """Generic job-polling function.
1351 0a1e74d9 Iustin Pop

1352 4e338533 Michael Hanselmann
  @type job_id: number
1353 4e338533 Michael Hanselmann
  @param job_id: Job ID
1354 4e338533 Michael Hanselmann
  @type cbs: Instance of L{JobPollCbBase}
1355 4e338533 Michael Hanselmann
  @param cbs: Data callbacks
1356 4e338533 Michael Hanselmann
  @type report_cbs: Instance of L{JobPollReportCbBase}
1357 4e338533 Michael Hanselmann
  @param report_cbs: Reporting callbacks
1358 0a1e74d9 Iustin Pop

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

1430 4e338533 Michael Hanselmann
  """
1431 4e338533 Michael Hanselmann
  def __init__(self):
1432 4e338533 Michael Hanselmann
    """Initializes this class.
1433 4e338533 Michael Hanselmann

1434 4e338533 Michael Hanselmann
    """
1435 4e338533 Michael Hanselmann
1436 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1437 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1438 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1439 4e338533 Michael Hanselmann

1440 4e338533 Michael Hanselmann
    """
1441 4e338533 Michael Hanselmann
    raise NotImplementedError()
1442 4e338533 Michael Hanselmann
1443 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1444 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1445 4e338533 Michael Hanselmann

1446 4e338533 Michael Hanselmann
    @type job_ids: list of numbers
1447 4e338533 Michael Hanselmann
    @param job_ids: Job IDs
1448 4e338533 Michael Hanselmann
    @type fields: list of strings
1449 4e338533 Michael Hanselmann
    @param fields: Fields
1450 4e338533 Michael Hanselmann

1451 4e338533 Michael Hanselmann
    """
1452 4e338533 Michael Hanselmann
    raise NotImplementedError()
1453 4e338533 Michael Hanselmann
1454 4e338533 Michael Hanselmann
1455 4e338533 Michael Hanselmann
class JobPollReportCbBase:
1456 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} reporting callbacks.
1457 4e338533 Michael Hanselmann

1458 4e338533 Michael Hanselmann
  """
1459 4e338533 Michael Hanselmann
  def __init__(self):
1460 4e338533 Michael Hanselmann
    """Initializes this class.
1461 4e338533 Michael Hanselmann

1462 4e338533 Michael Hanselmann
    """
1463 4e338533 Michael Hanselmann
1464 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1465 4e338533 Michael Hanselmann
    """Handles a log message.
1466 4e338533 Michael Hanselmann

1467 4e338533 Michael Hanselmann
    """
1468 4e338533 Michael Hanselmann
    raise NotImplementedError()
1469 4e338533 Michael Hanselmann
1470 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1471 4e338533 Michael Hanselmann
    """Called for if a job hasn't changed in a while.
1472 4e338533 Michael Hanselmann

1473 4e338533 Michael Hanselmann
    @type job_id: number
1474 4e338533 Michael Hanselmann
    @param job_id: Job ID
1475 4e338533 Michael Hanselmann
    @type status: string or None
1476 4e338533 Michael Hanselmann
    @param status: Job status if available
1477 4e338533 Michael Hanselmann

1478 4e338533 Michael Hanselmann
    """
1479 4e338533 Michael Hanselmann
    raise NotImplementedError()
1480 4e338533 Michael Hanselmann
1481 4e338533 Michael Hanselmann
1482 4e338533 Michael Hanselmann
class _LuxiJobPollCb(JobPollCbBase):
1483 4e338533 Michael Hanselmann
  def __init__(self, cl):
1484 4e338533 Michael Hanselmann
    """Initializes this class.
1485 4e338533 Michael Hanselmann

1486 4e338533 Michael Hanselmann
    """
1487 4e338533 Michael Hanselmann
    JobPollCbBase.__init__(self)
1488 4e338533 Michael Hanselmann
    self.cl = cl
1489 4e338533 Michael Hanselmann
1490 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1491 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1492 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1493 4e338533 Michael Hanselmann

1494 4e338533 Michael Hanselmann
    """
1495 4e338533 Michael Hanselmann
    return self.cl.WaitForJobChangeOnce(job_id, fields,
1496 4e338533 Michael Hanselmann
                                        prev_job_info, prev_log_serial)
1497 4e338533 Michael Hanselmann
1498 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1499 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1500 4e338533 Michael Hanselmann

1501 4e338533 Michael Hanselmann
    """
1502 4e338533 Michael Hanselmann
    return self.cl.QueryJobs(job_ids, fields)
1503 4e338533 Michael Hanselmann
1504 4e338533 Michael Hanselmann
1505 4e338533 Michael Hanselmann
class FeedbackFnJobPollReportCb(JobPollReportCbBase):
1506 4e338533 Michael Hanselmann
  def __init__(self, feedback_fn):
1507 4e338533 Michael Hanselmann
    """Initializes this class.
1508 4e338533 Michael Hanselmann

1509 4e338533 Michael Hanselmann
    """
1510 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1511 4e338533 Michael Hanselmann
1512 4e338533 Michael Hanselmann
    self.feedback_fn = feedback_fn
1513 4e338533 Michael Hanselmann
1514 4e338533 Michael Hanselmann
    assert callable(feedback_fn)
1515 4e338533 Michael Hanselmann
1516 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1517 4e338533 Michael Hanselmann
    """Handles a log message.
1518 4e338533 Michael Hanselmann

1519 4e338533 Michael Hanselmann
    """
1520 4e338533 Michael Hanselmann
    self.feedback_fn((timestamp, log_type, log_msg))
1521 4e338533 Michael Hanselmann
1522 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1523 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1524 4e338533 Michael Hanselmann

1525 4e338533 Michael Hanselmann
    """
1526 4e338533 Michael Hanselmann
    # Ignore
1527 4e338533 Michael Hanselmann
1528 4e338533 Michael Hanselmann
1529 4e338533 Michael Hanselmann
class StdioJobPollReportCb(JobPollReportCbBase):
1530 4e338533 Michael Hanselmann
  def __init__(self):
1531 4e338533 Michael Hanselmann
    """Initializes this class.
1532 4e338533 Michael Hanselmann

1533 4e338533 Michael Hanselmann
    """
1534 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1535 4e338533 Michael Hanselmann
1536 4e338533 Michael Hanselmann
    self.notified_queued = False
1537 4e338533 Michael Hanselmann
    self.notified_waitlock = False
1538 4e338533 Michael Hanselmann
1539 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1540 4e338533 Michael Hanselmann
    """Handles a log message.
1541 4e338533 Michael Hanselmann

1542 4e338533 Michael Hanselmann
    """
1543 4e338533 Michael Hanselmann
    ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)),
1544 8a7f1c61 Michael Hanselmann
             FormatLogMessage(log_type, log_msg))
1545 4e338533 Michael Hanselmann
1546 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1547 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1548 4e338533 Michael Hanselmann

1549 4e338533 Michael Hanselmann
    """
1550 4e338533 Michael Hanselmann
    if status is None:
1551 4e338533 Michael Hanselmann
      return
1552 4e338533 Michael Hanselmann
1553 4e338533 Michael Hanselmann
    if status == constants.JOB_STATUS_QUEUED and not self.notified_queued:
1554 4e338533 Michael Hanselmann
      ToStderr("Job %s is waiting in queue", job_id)
1555 4e338533 Michael Hanselmann
      self.notified_queued = True
1556 4e338533 Michael Hanselmann
1557 4e338533 Michael Hanselmann
    elif status == constants.JOB_STATUS_WAITLOCK and not self.notified_waitlock:
1558 4e338533 Michael Hanselmann
      ToStderr("Job %s is trying to acquire all necessary locks", job_id)
1559 4e338533 Michael Hanselmann
      self.notified_waitlock = True
1560 4e338533 Michael Hanselmann
1561 4e338533 Michael Hanselmann
1562 8a7f1c61 Michael Hanselmann
def FormatLogMessage(log_type, log_msg):
1563 8a7f1c61 Michael Hanselmann
  """Formats a job message according to its type.
1564 8a7f1c61 Michael Hanselmann

1565 8a7f1c61 Michael Hanselmann
  """
1566 8a7f1c61 Michael Hanselmann
  if log_type != constants.ELOG_MESSAGE:
1567 8a7f1c61 Michael Hanselmann
    log_msg = str(log_msg)
1568 8a7f1c61 Michael Hanselmann
1569 8a7f1c61 Michael Hanselmann
  return utils.SafeEncode(log_msg)
1570 8a7f1c61 Michael Hanselmann
1571 8a7f1c61 Michael Hanselmann
1572 583163a6 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None, reporter=None):
1573 4e338533 Michael Hanselmann
  """Function to poll for the result of a job.
1574 4e338533 Michael Hanselmann

1575 4e338533 Michael Hanselmann
  @type job_id: job identified
1576 4e338533 Michael Hanselmann
  @param job_id: the job to poll for results
1577 4e338533 Michael Hanselmann
  @type cl: luxi.Client
1578 4e338533 Michael Hanselmann
  @param cl: the luxi client to use for communicating with the master;
1579 4e338533 Michael Hanselmann
             if None, a new client will be created
1580 4e338533 Michael Hanselmann

1581 4e338533 Michael Hanselmann
  """
1582 4e338533 Michael Hanselmann
  if cl is None:
1583 4e338533 Michael Hanselmann
    cl = GetClient()
1584 4e338533 Michael Hanselmann
1585 583163a6 Michael Hanselmann
  if reporter is None:
1586 583163a6 Michael Hanselmann
    if feedback_fn:
1587 583163a6 Michael Hanselmann
      reporter = FeedbackFnJobPollReportCb(feedback_fn)
1588 583163a6 Michael Hanselmann
    else:
1589 583163a6 Michael Hanselmann
      reporter = StdioJobPollReportCb()
1590 583163a6 Michael Hanselmann
  elif feedback_fn:
1591 583163a6 Michael Hanselmann
    raise errors.ProgrammerError("Can't specify reporter and feedback function")
1592 4e338533 Michael Hanselmann
1593 4e338533 Michael Hanselmann
  return GenericPollJob(job_id, _LuxiJobPollCb(cl), reporter)
1594 ceab32dd Iustin Pop
1595 ceab32dd Iustin Pop
1596 583163a6 Michael Hanselmann
def SubmitOpCode(op, cl=None, feedback_fn=None, opts=None, reporter=None):
1597 0a1e74d9 Iustin Pop
  """Legacy function to submit an opcode.
1598 0a1e74d9 Iustin Pop

1599 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1600 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1601 0a1e74d9 Iustin Pop
  interaction functions.
1602 0a1e74d9 Iustin Pop

1603 0a1e74d9 Iustin Pop
  """
1604 0a1e74d9 Iustin Pop
  if cl is None:
1605 0a1e74d9 Iustin Pop
    cl = GetClient()
1606 0a1e74d9 Iustin Pop
1607 293ba2d8 Iustin Pop
  SetGenericOpcodeOpts([op], opts)
1608 293ba2d8 Iustin Pop
1609 5d297d8a Michael Hanselmann
  job_id = SendJob([op], cl=cl)
1610 0a1e74d9 Iustin Pop
1611 583163a6 Michael Hanselmann
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn,
1612 583163a6 Michael Hanselmann
                       reporter=reporter)
1613 53c04d04 Iustin Pop
1614 53c04d04 Iustin Pop
  return op_results[0]
1615 0a1e74d9 Iustin Pop
1616 0a1e74d9 Iustin Pop
1617 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1618 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1619 94428652 Iustin Pop

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

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

1628 94428652 Iustin Pop
  """
1629 94428652 Iustin Pop
  if opts and opts.submit_only:
1630 293ba2d8 Iustin Pop
    job = [op]
1631 293ba2d8 Iustin Pop
    SetGenericOpcodeOpts(job, opts)
1632 293ba2d8 Iustin Pop
    job_id = SendJob(job, cl=cl)
1633 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
1634 94428652 Iustin Pop
  else:
1635 293ba2d8 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
1636 293ba2d8 Iustin Pop
1637 293ba2d8 Iustin Pop
1638 293ba2d8 Iustin Pop
def SetGenericOpcodeOpts(opcode_list, options):
1639 293ba2d8 Iustin Pop
  """Processor for generic options.
1640 293ba2d8 Iustin Pop

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

1644 293ba2d8 Iustin Pop
  @param opcode_list: list of opcodes
1645 293ba2d8 Iustin Pop
  @param options: command line options or None
1646 293ba2d8 Iustin Pop
  @return: None (in-place modification)
1647 293ba2d8 Iustin Pop

1648 293ba2d8 Iustin Pop
  """
1649 293ba2d8 Iustin Pop
  if not options:
1650 293ba2d8 Iustin Pop
    return
1651 293ba2d8 Iustin Pop
  for op in opcode_list:
1652 a0a6ff34 Iustin Pop
    if hasattr(options, "dry_run"):
1653 a0a6ff34 Iustin Pop
      op.dry_run = options.dry_run
1654 293ba2d8 Iustin Pop
    op.debug_level = options.debug
1655 94428652 Iustin Pop
1656 94428652 Iustin Pop
1657 af30b2fd Michael Hanselmann
def GetClient():
1658 af30b2fd Michael Hanselmann
  # TODO: Cache object?
1659 b33e986b Iustin Pop
  try:
1660 b33e986b Iustin Pop
    client = luxi.Client()
1661 b33e986b Iustin Pop
  except luxi.NoMasterError:
1662 d9a51679 Michael Hanselmann
    ss = ssconf.SimpleStore()
1663 d9a51679 Michael Hanselmann
1664 d9a51679 Michael Hanselmann
    # Try to read ssconf file
1665 d9a51679 Michael Hanselmann
    try:
1666 d9a51679 Michael Hanselmann
      ss.GetMasterNode()
1667 d9a51679 Michael Hanselmann
    except errors.ConfigurationError:
1668 d9a51679 Michael Hanselmann
      raise errors.OpPrereqError("Cluster not initialized or this machine is"
1669 d9a51679 Michael Hanselmann
                                 " not part of a cluster")
1670 d9a51679 Michael Hanselmann
1671 d9a51679 Michael Hanselmann
    master, myself = ssconf.GetMasterAndMyself(ss=ss)
1672 b33e986b Iustin Pop
    if master != myself:
1673 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
1674 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
1675 b33e986b Iustin Pop
                                 master)
1676 d9a51679 Michael Hanselmann
    raise
1677 b33e986b Iustin Pop
  return client
1678 af30b2fd Michael Hanselmann
1679 af30b2fd Michael Hanselmann
1680 73702ee7 Iustin Pop
def FormatError(err):
1681 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
1682 73702ee7 Iustin Pop

1683 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
1684 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
1685 73702ee7 Iustin Pop
  second, a string describing the error message (not
1686 73702ee7 Iustin Pop
  newline-terminated).
1687 73702ee7 Iustin Pop

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

1765 334d1483 Iustin Pop
  Arguments:
1766 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
1767 334d1483 Iustin Pop
                for command line handling.
1768 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
1769 334d1483 Iustin Pop
                override command line options; this can be used to pass
1770 334d1483 Iustin Pop
                options from the scripts to generic functions
1771 de47cf8f Guido Trotter
    - aliases: dictionary with command aliases {'alias': 'target, ...}
1772 a8083063 Iustin Pop

1773 a8083063 Iustin Pop
  """
1774 a8083063 Iustin Pop
  # save the program name and the entire command line for later logging
1775 a8083063 Iustin Pop
  if sys.argv:
1776 a8083063 Iustin Pop
    binary = os.path.basename(sys.argv[0]) or sys.argv[0]
1777 a8083063 Iustin Pop
    if len(sys.argv) >= 2:
1778 a8083063 Iustin Pop
      binary += " " + sys.argv[1]
1779 a8083063 Iustin Pop
      old_cmdline = " ".join(sys.argv[2:])
1780 a8083063 Iustin Pop
    else:
1781 a8083063 Iustin Pop
      old_cmdline = ""
1782 a8083063 Iustin Pop
  else:
1783 a8083063 Iustin Pop
    binary = "<unknown program>"
1784 a8083063 Iustin Pop
    old_cmdline = ""
1785 a8083063 Iustin Pop
1786 de47cf8f Guido Trotter
  if aliases is None:
1787 de47cf8f Guido Trotter
    aliases = {}
1788 de47cf8f Guido Trotter
1789 3126878d Guido Trotter
  try:
1790 3126878d Guido Trotter
    func, options, args = _ParseArgs(sys.argv, commands, aliases)
1791 3126878d Guido Trotter
  except errors.ParameterError, err:
1792 3126878d Guido Trotter
    result, err_msg = FormatError(err)
1793 3126878d Guido Trotter
    ToStderr(err_msg)
1794 3126878d Guido Trotter
    return 1
1795 3126878d Guido Trotter
1796 a8083063 Iustin Pop
  if func is None: # parse error
1797 a8083063 Iustin Pop
    return 1
1798 a8083063 Iustin Pop
1799 334d1483 Iustin Pop
  if override is not None:
1800 334d1483 Iustin Pop
    for key, val in override.iteritems():
1801 334d1483 Iustin Pop
      setattr(options, key, val)
1802 334d1483 Iustin Pop
1803 82d9caef Iustin Pop
  utils.SetupLogging(constants.LOG_COMMANDS, debug=options.debug,
1804 82d9caef Iustin Pop
                     stderr_logging=True, program=binary)
1805 a8083063 Iustin Pop
1806 a8083063 Iustin Pop
  if old_cmdline:
1807 46fbdd04 Iustin Pop
    logging.info("run with arguments '%s'", old_cmdline)
1808 a8083063 Iustin Pop
  else:
1809 46fbdd04 Iustin Pop
    logging.info("run with no arguments")
1810 a8083063 Iustin Pop
1811 a8083063 Iustin Pop
  try:
1812 a4af651e Iustin Pop
    result = func(options, args)
1813 d8353c3a Iustin Pop
  except (errors.GenericError, luxi.ProtocolError,
1814 d8353c3a Iustin Pop
          JobSubmittedException), err:
1815 a4af651e Iustin Pop
    result, err_msg = FormatError(err)
1816 5bbd3f7f Michael Hanselmann
    logging.exception("Error during command processing")
1817 46fbdd04 Iustin Pop
    ToStderr(err_msg)
1818 a8083063 Iustin Pop
1819 a8083063 Iustin Pop
  return result
1820 137161c9 Michael Hanselmann
1821 137161c9 Michael Hanselmann
1822 d77490c5 Iustin Pop
def GenericInstanceCreate(mode, opts, args):
1823 d77490c5 Iustin Pop
  """Add an instance to the cluster via either creation or import.
1824 d77490c5 Iustin Pop

1825 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
1826 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
1827 d77490c5 Iustin Pop
  @type args: list
1828 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
1829 d77490c5 Iustin Pop
  @rtype: int
1830 d77490c5 Iustin Pop
  @return: the desired exit code
1831 d77490c5 Iustin Pop

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

1964 7e49b6ce Michael Hanselmann
  """
1965 7e49b6ce Michael Hanselmann
  def __init__(self, feedback_fn, cluster_name, master_node, online_nodes):
1966 7e49b6ce Michael Hanselmann
    """Initializes this class.
1967 7e49b6ce Michael Hanselmann

1968 7e49b6ce Michael Hanselmann
    @type feedback_fn: callable
1969 7e49b6ce Michael Hanselmann
    @param feedback_fn: Feedback function
1970 7e49b6ce Michael Hanselmann
    @type cluster_name: string
1971 7e49b6ce Michael Hanselmann
    @param cluster_name: Cluster name
1972 7e49b6ce Michael Hanselmann
    @type master_node: string
1973 7e49b6ce Michael Hanselmann
    @param master_node Master node name
1974 7e49b6ce Michael Hanselmann
    @type online_nodes: list
1975 7e49b6ce Michael Hanselmann
    @param online_nodes: List of names of online nodes
1976 7e49b6ce Michael Hanselmann

1977 7e49b6ce Michael Hanselmann
    """
1978 7e49b6ce Michael Hanselmann
    self.feedback_fn = feedback_fn
1979 7e49b6ce Michael Hanselmann
    self.cluster_name = cluster_name
1980 7e49b6ce Michael Hanselmann
    self.master_node = master_node
1981 7e49b6ce Michael Hanselmann
    self.online_nodes = online_nodes
1982 7e49b6ce Michael Hanselmann
1983 7e49b6ce Michael Hanselmann
    self.ssh = ssh.SshRunner(self.cluster_name)
1984 7e49b6ce Michael Hanselmann
1985 7e49b6ce Michael Hanselmann
    self.nonmaster_nodes = [name for name in online_nodes
1986 7e49b6ce Michael Hanselmann
                            if name != master_node]
1987 7e49b6ce Michael Hanselmann
1988 7e49b6ce Michael Hanselmann
    assert self.master_node not in self.nonmaster_nodes
1989 7e49b6ce Michael Hanselmann
1990 7e49b6ce Michael Hanselmann
  def _RunCmd(self, node_name, cmd):
1991 7e49b6ce Michael Hanselmann
    """Runs a command on the local or a remote machine.
1992 7e49b6ce Michael Hanselmann

1993 7e49b6ce Michael Hanselmann
    @type node_name: string
1994 7e49b6ce Michael Hanselmann
    @param node_name: Machine name
1995 7e49b6ce Michael Hanselmann
    @type cmd: list
1996 7e49b6ce Michael Hanselmann
    @param cmd: Command
1997 7e49b6ce Michael Hanselmann

1998 7e49b6ce Michael Hanselmann
    """
1999 7e49b6ce Michael Hanselmann
    if node_name is None or node_name == self.master_node:
2000 7e49b6ce Michael Hanselmann
      # No need to use SSH
2001 7e49b6ce Michael Hanselmann
      result = utils.RunCmd(cmd)
2002 7e49b6ce Michael Hanselmann
    else:
2003 7e49b6ce Michael Hanselmann
      result = self.ssh.Run(node_name, "root", utils.ShellQuoteArgs(cmd))
2004 7e49b6ce Michael Hanselmann
2005 7e49b6ce Michael Hanselmann
    if result.failed:
2006 7e49b6ce Michael Hanselmann
      errmsg = ["Failed to run command %s" % result.cmd]
2007 7e49b6ce Michael Hanselmann
      if node_name:
2008 7e49b6ce Michael Hanselmann
        errmsg.append("on node %s" % node_name)
2009 7e49b6ce Michael Hanselmann
      errmsg.append(": exitcode %s and error %s" %
2010 7e49b6ce Michael Hanselmann
                    (result.exit_code, result.output))
2011 7e49b6ce Michael Hanselmann
      raise errors.OpExecError(" ".join(errmsg))
2012 7e49b6ce Michael Hanselmann
2013 7e49b6ce Michael Hanselmann
  def Call(self, fn, *args):
2014 7e49b6ce Michael Hanselmann
    """Call function while all daemons are stopped.
2015 7e49b6ce Michael Hanselmann

2016 7e49b6ce Michael Hanselmann
    @type fn: callable
2017 7e49b6ce Michael Hanselmann
    @param fn: Function to be called
2018 7e49b6ce Michael Hanselmann

2019 7e49b6ce Michael Hanselmann
    """
2020 7e49b6ce Michael Hanselmann
    # Pause watcher by acquiring an exclusive lock on watcher state file
2021 7e49b6ce Michael Hanselmann
    self.feedback_fn("Blocking watcher")
2022 7e49b6ce Michael Hanselmann
    watcher_block = utils.FileLock.Open(constants.WATCHER_STATEFILE)
2023 7e49b6ce Michael Hanselmann
    try:
2024 7e49b6ce Michael Hanselmann
      # TODO: Currently, this just blocks. There's no timeout.
2025 7e49b6ce Michael Hanselmann
      # TODO: Should it be a shared lock?
2026 7e49b6ce Michael Hanselmann
      watcher_block.Exclusive(blocking=True)
2027 7e49b6ce Michael Hanselmann
2028 7e49b6ce Michael Hanselmann
      # Stop master daemons, so that no new jobs can come in and all running
2029 7e49b6ce Michael Hanselmann
      # ones are finished
2030 7e49b6ce Michael Hanselmann
      self.feedback_fn("Stopping master daemons")
2031 7e49b6ce Michael Hanselmann
      self._RunCmd(None, [constants.DAEMON_UTIL, "stop-master"])
2032 7e49b6ce Michael Hanselmann
      try:
2033 7e49b6ce Michael Hanselmann
        # Stop daemons on all nodes
2034 7e49b6ce Michael Hanselmann
        for node_name in self.online_nodes:
2035 7e49b6ce Michael Hanselmann
          self.feedback_fn("Stopping daemons on %s" % node_name)
2036 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "stop-all"])
2037 7e49b6ce Michael Hanselmann
2038 7e49b6ce Michael Hanselmann
        # All daemons are shut down now
2039 7e49b6ce Michael Hanselmann
        try:
2040 7e49b6ce Michael Hanselmann
          return fn(self, *args)
2041 d512e84b Michael Hanselmann
        except Exception, err:
2042 d512e84b Michael Hanselmann
          _, errmsg = FormatError(err)
2043 7e49b6ce Michael Hanselmann
          logging.exception("Caught exception")
2044 d512e84b Michael Hanselmann
          self.feedback_fn(errmsg)
2045 7e49b6ce Michael Hanselmann
          raise
2046 7e49b6ce Michael Hanselmann
      finally:
2047 7e49b6ce Michael Hanselmann
        # Start cluster again, master node last
2048 7e49b6ce Michael Hanselmann
        for node_name in self.nonmaster_nodes + [self.master_node]:
2049 7e49b6ce Michael Hanselmann
          self.feedback_fn("Starting daemons on %s" % node_name)
2050 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "start-all"])
2051 7e49b6ce Michael Hanselmann
    finally:
2052 7e49b6ce Michael Hanselmann
      # Resume watcher
2053 7e49b6ce Michael Hanselmann
      watcher_block.Close()
2054 7e49b6ce Michael Hanselmann
2055 7e49b6ce Michael Hanselmann
2056 7e49b6ce Michael Hanselmann
def RunWhileClusterStopped(feedback_fn, fn, *args):
2057 7e49b6ce Michael Hanselmann
  """Calls a function while all cluster daemons are stopped.
2058 7e49b6ce Michael Hanselmann

2059 7e49b6ce Michael Hanselmann
  @type feedback_fn: callable
2060 7e49b6ce Michael Hanselmann
  @param feedback_fn: Feedback function
2061 7e49b6ce Michael Hanselmann
  @type fn: callable
2062 7e49b6ce Michael Hanselmann
  @param fn: Function to be called when daemons are stopped
2063 7e49b6ce Michael Hanselmann

2064 7e49b6ce Michael Hanselmann
  """
2065 7e49b6ce Michael Hanselmann
  feedback_fn("Gathering cluster information")
2066 7e49b6ce Michael Hanselmann
2067 7e49b6ce Michael Hanselmann
  # This ensures we're running on the master daemon
2068 7e49b6ce Michael Hanselmann
  cl = GetClient()
2069 7e49b6ce Michael Hanselmann
2070 7e49b6ce Michael Hanselmann
  (cluster_name, master_node) = \
2071 7e49b6ce Michael Hanselmann
    cl.QueryConfigValues(["cluster_name", "master_node"])
2072 7e49b6ce Michael Hanselmann
2073 7e49b6ce Michael Hanselmann
  online_nodes = GetOnlineNodes([], cl=cl)
2074 7e49b6ce Michael Hanselmann
2075 7e49b6ce Michael Hanselmann
  # Don't keep a reference to the client. The master daemon will go away.
2076 7e49b6ce Michael Hanselmann
  del cl
2077 7e49b6ce Michael Hanselmann
2078 7e49b6ce Michael Hanselmann
  assert master_node in online_nodes
2079 7e49b6ce Michael Hanselmann
2080 7e49b6ce Michael Hanselmann
  return _RunWhileClusterStoppedHelper(feedback_fn, cluster_name, master_node,
2081 7e49b6ce Michael Hanselmann
                                       online_nodes).Call(fn, *args)
2082 7e49b6ce Michael Hanselmann
2083 7e49b6ce Michael Hanselmann
2084 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
2085 9fbfbb7b Iustin Pop
                  numfields=None, unitfields=None,
2086 9fbfbb7b Iustin Pop
                  units=None):
2087 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
2088 137161c9 Michael Hanselmann

2089 9fbfbb7b Iustin Pop
  @type headers: dict
2090 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
2091 9fbfbb7b Iustin Pop
      the table
2092 9fbfbb7b Iustin Pop
  @type fields: list
2093 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
2094 9fbfbb7b Iustin Pop
      the data field
2095 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
2096 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
2097 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
2098 9fbfbb7b Iustin Pop
      each field
2099 9fbfbb7b Iustin Pop
  @type data: list
2100 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
2101 9fbfbb7b Iustin Pop
  @type numfields: list
2102 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
2103 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
2104 9fbfbb7b Iustin Pop
  @type unitfields: list
2105 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
2106 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
2107 9fbfbb7b Iustin Pop
  @type units: string or None
2108 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
2109 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
2110 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
2111 137161c9 Michael Hanselmann

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

2195 3386e7a9 Iustin Pop
  @type ts: timestamp
2196 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
2197 3386e7a9 Iustin Pop

2198 3386e7a9 Iustin Pop
  @rtype: string
2199 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
2200 3386e7a9 Iustin Pop

2201 3386e7a9 Iustin Pop
  """
2202 e0ec0ff6 Iustin Pop
  if not isinstance (ts, (tuple, list)) or len(ts) != 2:
2203 e0ec0ff6 Iustin Pop
    return '?'
2204 3386e7a9 Iustin Pop
  sec, usec = ts
2205 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
2206 2241e2b9 Iustin Pop
2207 2241e2b9 Iustin Pop
2208 2241e2b9 Iustin Pop
def ParseTimespec(value):
2209 2241e2b9 Iustin Pop
  """Parse a time specification.
2210 2241e2b9 Iustin Pop

2211 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
2212 2241e2b9 Iustin Pop

2213 2241e2b9 Iustin Pop
    - s: seconds
2214 2241e2b9 Iustin Pop
    - m: minutes
2215 2241e2b9 Iustin Pop
    - h: hours
2216 2241e2b9 Iustin Pop
    - d: day
2217 2241e2b9 Iustin Pop
    - w: weeks
2218 2241e2b9 Iustin Pop

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

2221 2241e2b9 Iustin Pop
  """
2222 2241e2b9 Iustin Pop
  value = str(value)
2223 2241e2b9 Iustin Pop
  if not value:
2224 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
2225 2241e2b9 Iustin Pop
  suffix_map = {
2226 2241e2b9 Iustin Pop
    's': 1,
2227 2241e2b9 Iustin Pop
    'm': 60,
2228 2241e2b9 Iustin Pop
    'h': 3600,
2229 2241e2b9 Iustin Pop
    'd': 86400,
2230 2241e2b9 Iustin Pop
    'w': 604800,
2231 2241e2b9 Iustin Pop
    }
2232 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
2233 2241e2b9 Iustin Pop
    try:
2234 2241e2b9 Iustin Pop
      value = int(value)
2235 691744c4 Iustin Pop
    except (TypeError, ValueError):
2236 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2237 2241e2b9 Iustin Pop
  else:
2238 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
2239 2241e2b9 Iustin Pop
    value = value[:-1]
2240 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
2241 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
2242 2241e2b9 Iustin Pop
                                 " suffix passed)")
2243 2241e2b9 Iustin Pop
    try:
2244 2241e2b9 Iustin Pop
      value = int(value) * multiplier
2245 691744c4 Iustin Pop
    except (TypeError, ValueError):
2246 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2247 2241e2b9 Iustin Pop
  return value
2248 46fbdd04 Iustin Pop
2249 46fbdd04 Iustin Pop
2250 e9e26bb3 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False, secondary_ips=False,
2251 e9e26bb3 Iustin Pop
                   filter_master=False):
2252 4040a784 Iustin Pop
  """Returns the names of online nodes.
2253 4040a784 Iustin Pop

2254 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
2255 4040a784 Iustin Pop
  the online nodes.
2256 4040a784 Iustin Pop

2257 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
2258 4040a784 Iustin Pop
      offline ones)
2259 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
2260 4040a784 Iustin Pop
  @type nowarn: boolean
2261 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
2262 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
2263 4040a784 Iustin Pop
      note is not displayed
2264 e9e26bb3 Iustin Pop
  @type secondary_ips: boolean
2265 e9e26bb3 Iustin Pop
  @param secondary_ips: if True, return the secondary IPs instead of the
2266 e9e26bb3 Iustin Pop
      names, useful for doing network traffic over the replication interface
2267 e9e26bb3 Iustin Pop
      (if any)
2268 e9e26bb3 Iustin Pop
  @type filter_master: boolean
2269 e9e26bb3 Iustin Pop
  @param filter_master: if True, do not return the master node in the list
2270 e9e26bb3 Iustin Pop
      (useful in coordination with secondary_ips where we cannot check our
2271 e9e26bb3 Iustin Pop
      node name against the list)
2272 4040a784 Iustin Pop

2273 4040a784 Iustin Pop
  """
2274 4040a784 Iustin Pop
  if cl is None:
2275 4040a784 Iustin Pop
    cl = GetClient()
2276 4040a784 Iustin Pop
2277 e9e26bb3 Iustin Pop
  if secondary_ips:
2278 e9e26bb3 Iustin Pop
    name_idx = 2
2279 e9e26bb3 Iustin Pop
  else:
2280 e9e26bb3 Iustin Pop
    name_idx = 0
2281 e9e26bb3 Iustin Pop
2282 e9e26bb3 Iustin Pop
  if filter_master:
2283 e9e26bb3 Iustin Pop
    master_node = cl.QueryConfigValues(["master_node"])[0]
2284 e9e26bb3 Iustin Pop
    filter_fn = lambda x: x != master_node
2285 e9e26bb3 Iustin Pop
  else:
2286 e9e26bb3 Iustin Pop
    filter_fn = lambda _: True
2287 e9e26bb3 Iustin Pop
2288 e9e26bb3 Iustin Pop
  result = cl.QueryNodes(names=nodes, fields=["name", "offline", "sip"],
2289 2e7b8369 Iustin Pop
                         use_locking=False)
2290 4040a784 Iustin Pop
  offline = [row[0] for row in result if row[1]]
2291 4040a784 Iustin Pop
  if offline and not nowarn:
2292 1f864b60 Iustin Pop
    ToStderr("Note: skipping offline node(s): %s" % utils.CommaJoin(offline))
2293 e9e26bb3 Iustin Pop
  return [row[name_idx] for row in result if not row[1] and filter_fn(row[0])]
2294 4040a784 Iustin Pop
2295 4040a784 Iustin Pop
2296 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
2297 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
2298 46fbdd04 Iustin Pop

2299 46fbdd04 Iustin Pop
  @type stream: file object
2300 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
2301 46fbdd04 Iustin Pop
  @type txt: str
2302 46fbdd04 Iustin Pop
  @param txt: the message
2303 46fbdd04 Iustin Pop

2304 46fbdd04 Iustin Pop
  """
2305 46fbdd04 Iustin Pop
  if args:
2306 46fbdd04 Iustin Pop
    args = tuple(args)
2307 46fbdd04 Iustin Pop
    stream.write(txt % args)
2308 46fbdd04 Iustin Pop
  else:
2309 46fbdd04 Iustin Pop
    stream.write(txt)
2310 46fbdd04 Iustin Pop
  stream.write('\n')
2311 46fbdd04 Iustin Pop
  stream.flush()
2312 46fbdd04 Iustin Pop
2313 46fbdd04 Iustin Pop
2314 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
2315 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
2316 46fbdd04 Iustin Pop

2317 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2318 46fbdd04 Iustin Pop

2319 46fbdd04 Iustin Pop
  @type txt: str
2320 46fbdd04 Iustin Pop
  @param txt: the message
2321 46fbdd04 Iustin Pop

2322 46fbdd04 Iustin Pop
  """
2323 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
2324 46fbdd04 Iustin Pop
2325 46fbdd04 Iustin Pop
2326 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
2327 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
2328 46fbdd04 Iustin Pop

2329 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2330 46fbdd04 Iustin Pop

2331 46fbdd04 Iustin Pop
  @type txt: str
2332 46fbdd04 Iustin Pop
  @param txt: the message
2333 46fbdd04 Iustin Pop

2334 46fbdd04 Iustin Pop
  """
2335 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
2336 479636a3 Iustin Pop
2337 479636a3 Iustin Pop
2338 479636a3 Iustin Pop
class JobExecutor(object):
2339 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
2340 479636a3 Iustin Pop

2341 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
2342 479636a3 Iustin Pop
  GetResults() calls.
2343 479636a3 Iustin Pop

2344 479636a3 Iustin Pop
  """
2345 919ca415 Iustin Pop
  def __init__(self, cl=None, verbose=True, opts=None, feedback_fn=None):
2346 479636a3 Iustin Pop
    self.queue = []
2347 479636a3 Iustin Pop
    if cl is None:
2348 479636a3 Iustin Pop
      cl = GetClient()
2349 479636a3 Iustin Pop
    self.cl = cl
2350 479636a3 Iustin Pop
    self.verbose = verbose
2351 23b4b983 Iustin Pop
    self.jobs = []
2352 cff5fa7f Iustin Pop
    self.opts = opts
2353 919ca415 Iustin Pop
    self.feedback_fn = feedback_fn
2354 479636a3 Iustin Pop
2355 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
2356 23b4b983 Iustin Pop
    """Record a job for later submit.
2357 479636a3 Iustin Pop

2358 479636a3 Iustin Pop
    @type name: string
2359 479636a3 Iustin Pop
    @param name: a description of the job, will be used in WaitJobSet
2360 479636a3 Iustin Pop
    """
2361 cff5fa7f Iustin Pop
    SetGenericOpcodeOpts(ops, self.opts)
2362 23b4b983 Iustin Pop
    self.queue.append((name, ops))
2363 23b4b983 Iustin Pop
2364 66ecc479 Guido Trotter
  def SubmitPending(self, each=False):
2365 23b4b983 Iustin Pop
    """Submit all pending jobs.
2366 23b4b983 Iustin Pop

2367 23b4b983 Iustin Pop
    """
2368 66ecc479 Guido Trotter
    if each:
2369 66ecc479 Guido Trotter
      results = []
2370 66ecc479 Guido Trotter
      for row in self.queue:
2371 66ecc479 Guido Trotter
        # SubmitJob will remove the success status, but raise an exception if
2372 66ecc479 Guido Trotter
        # the submission fails, so we'll notice that anyway.
2373 66ecc479 Guido Trotter
        results.append([True, self.cl.SubmitJob(row[1])])
2374 66ecc479 Guido Trotter
    else:
2375 66ecc479 Guido Trotter
      results = self.cl.SubmitManyJobs([row[1] for row in self.queue])
2376 5299e61f Iustin Pop
    for (idx, ((status, data), (name, _))) in enumerate(zip(results,
2377 5299e61f Iustin Pop
                                                            self.queue)):
2378 5299e61f Iustin Pop
      self.jobs.append((idx, status, data, name))
2379 5299e61f Iustin Pop
2380 5299e61f Iustin Pop
  def _ChooseJob(self):
2381 5299e61f Iustin Pop
    """Choose a non-waiting/queued job to poll next.
2382 5299e61f Iustin Pop

2383 5299e61f Iustin Pop
    """
2384 5299e61f Iustin Pop
    assert self.jobs, "_ChooseJob called with empty job list"
2385 5299e61f Iustin Pop
2386 5299e61f Iustin Pop
    result = self.cl.QueryJobs([i[2] for i in self.jobs], ["status"])
2387 5299e61f Iustin Pop
    assert result
2388 5299e61f Iustin Pop
2389 5299e61f Iustin Pop
    for job_data, status in zip(self.jobs, result):
2390 91c622a8 Iustin Pop
      if (isinstance(status, list) and status and
2391 91c622a8 Iustin Pop
          status[0] in (constants.JOB_STATUS_QUEUED,
2392 91c622a8 Iustin Pop
                        constants.JOB_STATUS_WAITLOCK,
2393 91c622a8 Iustin Pop
                        constants.JOB_STATUS_CANCELING)):
2394 91c622a8 Iustin Pop
        # job is still present and waiting
2395 5299e61f Iustin Pop
        continue
2396 91c622a8 Iustin Pop
      # good candidate found (either running job or lost job)
2397 5299e61f Iustin Pop
      self.jobs.remove(job_data)
2398 5299e61f Iustin Pop
      return job_data
2399 5299e61f Iustin Pop
2400 5299e61f Iustin Pop
    # no job found
2401 5299e61f Iustin Pop
    return self.jobs.pop(0)
2402 479636a3 Iustin Pop
2403 479636a3 Iustin Pop
  def GetResults(self):
2404 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
2405 479636a3 Iustin Pop

2406 479636a3 Iustin Pop
    @rtype: list
2407 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
2408 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
2409 479636a3 Iustin Pop
        there will be the error message
2410 479636a3 Iustin Pop

2411 479636a3 Iustin Pop
    """
2412 23b4b983 Iustin Pop
    if not self.jobs:
2413 23b4b983 Iustin Pop
      self.SubmitPending()
2414 479636a3 Iustin Pop
    results = []
2415 479636a3 Iustin Pop
    if self.verbose:
2416 5299e61f Iustin Pop
      ok_jobs = [row[2] for row in self.jobs if row[1]]
2417 23b4b983 Iustin Pop
      if ok_jobs:
2418 1f864b60 Iustin Pop
        ToStdout("Submitted jobs %s", utils.CommaJoin(ok_jobs))
2419 5299e61f Iustin Pop
2420 5299e61f Iustin Pop
    # first, remove any non-submitted jobs
2421 cea881e5 Michael Hanselmann
    self.jobs, failures = compat.partition(self.jobs, lambda x: x[1])
2422 5299e61f Iustin Pop
    for idx, _, jid, name in failures:
2423 c63355f2 Iustin Pop
      ToStderr("Failed to submit job for %s: %s", name, jid)
2424 c63355f2 Iustin Pop
      results.append((idx, False, jid))
2425 5299e61f Iustin Pop
2426 5299e61f Iustin Pop
    while self.jobs:
2427 5299e61f Iustin Pop
      (idx, _, jid, name) = self._ChooseJob()
2428 5299e61f Iustin Pop
      ToStdout("Waiting for job %s for %s...", jid, name)
2429 479636a3 Iustin Pop
      try:
2430 919ca415 Iustin Pop
        job_result = PollJob(jid, cl=self.cl, feedback_fn=self.feedback_fn)
2431 479636a3 Iustin Pop
        success = True
2432 91c622a8 Iustin Pop
      except errors.JobLost, err:
2433 91c622a8 Iustin Pop
        _, job_result = FormatError(err)
2434 91c622a8 Iustin Pop
        ToStderr("Job %s for %s has been archived, cannot check its result",
2435 91c622a8 Iustin Pop
                 jid, name)
2436 91c622a8 Iustin Pop
        success = False
2437 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
2438 479636a3 Iustin Pop
        _, job_result = FormatError(err)
2439 479636a3 Iustin Pop
        success = False
2440 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
2441 479636a3 Iustin Pop
        ToStderr("Job %s for %s has failed: %s", jid, name, job_result)
2442 479636a3 Iustin Pop
2443 5299e61f Iustin Pop
      results.append((idx, success, job_result))
2444 5299e61f Iustin Pop
2445 5299e61f Iustin Pop
    # sort based on the index, then drop it
2446 5299e61f Iustin Pop
    results.sort()
2447 5299e61f Iustin Pop
    results = [i[1:] for i in results]
2448 5299e61f Iustin Pop
2449 479636a3 Iustin Pop
    return results
2450 479636a3 Iustin Pop
2451 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
2452 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
2453 479636a3 Iustin Pop

2454 479636a3 Iustin Pop
    @type wait: boolean
2455 479636a3 Iustin Pop
    @param wait: whether to wait or not
2456 479636a3 Iustin Pop

2457 479636a3 Iustin Pop
    """
2458 479636a3 Iustin Pop
    if wait:
2459 479636a3 Iustin Pop
      return self.GetResults()
2460 479636a3 Iustin Pop
    else:
2461 23b4b983 Iustin Pop
      if not self.jobs:
2462 23b4b983 Iustin Pop
        self.SubmitPending()
2463 71834b2a Guido Trotter
      for _, status, result, name in self.jobs:
2464 23b4b983 Iustin Pop
        if status:
2465 23b4b983 Iustin Pop
          ToStdout("%s: %s", result, name)
2466 23b4b983 Iustin Pop
        else:
2467 23b4b983 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)
2468 53a8a54d Iustin Pop
      return [row[1:3] for row in self.jobs]