Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ a298fd5a

History | View | Annotate | Download (82.5 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 783a6c0b Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 a8083063 Iustin Pop
"""Module dealing with command line parsing"""
23 a8083063 Iustin Pop
24 a8083063 Iustin Pop
25 a8083063 Iustin Pop
import sys
26 a8083063 Iustin Pop
import textwrap
27 a8083063 Iustin Pop
import os.path
28 685ee993 Iustin Pop
import time
29 46fbdd04 Iustin Pop
import logging
30 73702ee7 Iustin Pop
from cStringIO import StringIO
31 a8083063 Iustin Pop
32 a8083063 Iustin Pop
from ganeti import utils
33 a8083063 Iustin Pop
from ganeti import errors
34 a8083063 Iustin Pop
from ganeti import constants
35 846baef9 Iustin Pop
from ganeti import opcodes
36 ceab32dd Iustin Pop
from ganeti import luxi
37 b33e986b Iustin Pop
from ganeti import ssconf
38 4331f6cd Michael Hanselmann
from ganeti import rpc
39 7e49b6ce Michael Hanselmann
from ganeti import ssh
40 cea881e5 Michael Hanselmann
from ganeti import compat
41 a744b676 Manuel Franceschini
from ganeti import netutils
42 a8083063 Iustin Pop
43 c38c44ad Michael Hanselmann
from optparse import (OptionParser, TitledHelpFormatter,
44 38206f3c Iustin Pop
                      Option, OptionValueError)
45 a8083063 Iustin Pop
46 03298ebe Michael Hanselmann
47 4abc4f1e Iustin Pop
__all__ = [
48 4abc4f1e Iustin Pop
  # Command line options
49 fdad8c4d Balazs Lecz
  "ADD_UIDS_OPT",
50 e7e09483 Iustin Pop
  "ALLOCATABLE_OPT",
51 2d5e7ae1 Iustin Pop
  "ALL_OPT",
52 4c61d894 Iustin Pop
  "AUTO_PROMOTE_OPT",
53 e00f7a05 Iustin Pop
  "AUTO_REPLACE_OPT",
54 087ed2ed Iustin Pop
  "BACKEND_OPT",
55 61a14bb3 Iustin Pop
  "BLK_OS_OPT",
56 f91e255a Iustin Pop
  "CAPAB_MASTER_OPT",
57 53919782 Iustin Pop
  "CAPAB_VM_OPT",
58 baef337d Iustin Pop
  "CLEANUP_OPT",
59 3db3eb2a Michael Hanselmann
  "CLUSTER_DOMAIN_SECRET_OPT",
60 4abc4f1e Iustin Pop
  "CONFIRM_OPT",
61 e32df528 Iustin Pop
  "CP_SIZE_OPT",
62 4abc4f1e Iustin Pop
  "DEBUG_OPT",
63 a0c9776a Iustin Pop
  "DEBUG_SIMERR_OPT",
64 4b038a1e Iustin Pop
  "DISKIDX_OPT",
65 e3876ccb Iustin Pop
  "DISK_OPT",
66 4b038a1e Iustin Pop
  "DISK_TEMPLATE_OPT",
67 771734c9 Iustin Pop
  "DRAINED_OPT",
68 a0a6ff34 Iustin Pop
  "DRY_RUN_OPT",
69 26591bfd Luca Bigliardi
  "DRBD_HELPER_OPT",
70 7ea7bcf6 Iustin Pop
  "EARLY_RELEASE_OPT",
71 383a3591 Iustin Pop
  "ENABLED_HV_OPT",
72 14e9e7f3 Iustin Pop
  "ERROR_CODES_OPT",
73 4abc4f1e Iustin Pop
  "FIELDS_OPT",
74 4a25828c Iustin Pop
  "FILESTORE_DIR_OPT",
75 0f87c43e Iustin Pop
  "FILESTORE_DRIVER_OPT",
76 06073e85 Guido Trotter
  "FORCE_OPT",
77 06073e85 Guido Trotter
  "FORCE_VARIANT_OPT",
78 29392516 Iustin Pop
  "GLOBAL_FILEDIR_OPT",
79 61a14bb3 Iustin Pop
  "HID_OS_OPT",
80 073271f6 Iustin Pop
  "HVLIST_OPT",
81 48f212d7 Iustin Pop
  "HVOPTS_OPT",
82 236fd9c4 Iustin Pop
  "HYPERVISOR_OPT",
83 4eb62659 Iustin Pop
  "IALLOCATOR_OPT",
84 bf4af505 Apollon Oikonomopoulos
  "DEFAULT_IALLOCATOR_OPT",
85 e588764d Iustin Pop
  "IDENTIFY_DEFAULTS_OPT",
86 82a786d5 Iustin Pop
  "IGNORE_CONSIST_OPT",
87 b6e841a8 Iustin Pop
  "IGNORE_FAILURES_OPT",
88 b44bd844 Michael Hanselmann
  "IGNORE_OFFLINE_OPT",
89 8d8d650c Michael Hanselmann
  "IGNORE_REMOVE_FAILURES_OPT",
90 ee3f9578 Iustin Pop
  "IGNORE_SECONDARIES_OPT",
91 05586c90 Iustin Pop
  "IGNORE_SIZE_OPT",
92 19b9ba9a Michael Hanselmann
  "INTERVAL_OPT",
93 e3646f22 Iustin Pop
  "MAC_PREFIX_OPT",
94 3953242f Iustin Pop
  "MAINTAIN_NODE_HEALTH_OPT",
95 29392516 Iustin Pop
  "MASTER_NETDEV_OPT",
96 771734c9 Iustin Pop
  "MC_OPT",
97 783a6c0b Iustin Pop
  "MIGRATION_MODE_OPT",
98 7d3a9fab Iustin Pop
  "NET_OPT",
99 6d4a1656 Michael Hanselmann
  "NEW_CLUSTER_CERT_OPT",
100 3db3eb2a Michael Hanselmann
  "NEW_CLUSTER_DOMAIN_SECRET_OPT",
101 6b7d5878 Michael Hanselmann
  "NEW_CONFD_HMAC_KEY_OPT",
102 6d4a1656 Michael Hanselmann
  "NEW_RAPI_CERT_OPT",
103 a14db5ff Iustin Pop
  "NEW_SECONDARY_OPT",
104 4fbc93dd Iustin Pop
  "NIC_PARAMS_OPT",
105 7edc4637 Iustin Pop
  "NODE_LIST_OPT",
106 990b7886 Iustin Pop
  "NODE_PLACEMENT_OPT",
107 5fbbd028 Guido Trotter
  "NODEGROUP_OPT",
108 26591bfd Luca Bigliardi
  "NODRBD_STORAGE_OPT",
109 4abc4f1e Iustin Pop
  "NOHDR_OPT",
110 91e0748c Iustin Pop
  "NOIPCHECK_OPT",
111 25a8792c Iustin Pop
  "NO_INSTALL_OPT",
112 460d22be Iustin Pop
  "NONAMECHECK_OPT",
113 831040bf Iustin Pop
  "NOLVM_STORAGE_OPT",
114 29392516 Iustin Pop
  "NOMODIFY_ETCHOSTS_OPT",
115 b989b9d9 Ken Wehr
  "NOMODIFY_SSH_SETUP_OPT",
116 26023ecd Iustin Pop
  "NONICS_OPT",
117 f2a0828c Iustin Pop
  "NONLIVE_OPT",
118 14e9e7f3 Iustin Pop
  "NONPLUS1_OPT",
119 44c44832 Iustin Pop
  "NOSHUTDOWN_OPT",
120 edeb878a Iustin Pop
  "NOSTART_OPT",
121 fcdde7f2 Iustin Pop
  "NOSSH_KEYCHECK_OPT",
122 58371861 Iustin Pop
  "NOVOTING_OPT",
123 3f75b4f3 Iustin Pop
  "NWSYNC_OPT",
124 a72d0a79 Iustin Pop
  "ON_PRIMARY_OPT",
125 feb09e6a Iustin Pop
  "ON_SECONDARY_OPT",
126 771734c9 Iustin Pop
  "OFFLINE_OPT",
127 062a7100 Iustin Pop
  "OSPARAMS_OPT",
128 d3ed23ff Iustin Pop
  "OS_OPT",
129 ff00c1a7 Iustin Pop
  "OS_SIZE_OPT",
130 b883637f Renรฉ Nussbaumer
  "PREALLOC_WIPE_DISKS_OPT",
131 e7323b5e Manuel Franceschini
  "PRIMARY_IP_VERSION_OPT",
132 84a5b33c Michael Hanselmann
  "PRIORITY_OPT",
133 6d4a1656 Michael Hanselmann
  "RAPI_CERT_OPT",
134 b8d0f938 Iustin Pop
  "READD_OPT",
135 12054861 Iustin Pop
  "REBOOT_TYPE_OPT",
136 8d8d650c Michael Hanselmann
  "REMOVE_INSTANCE_OPT",
137 fdad8c4d Balazs Lecz
  "REMOVE_UIDS_OPT",
138 f38ea602 Iustin Pop
  "RESERVED_LVS_OPT",
139 31d97b2a Guido Trotter
  "ROMAN_OPT",
140 8d823629 Iustin Pop
  "SECONDARY_IP_OPT",
141 67840b40 Iustin Pop
  "SELECT_OS_OPT",
142 4abc4f1e Iustin Pop
  "SEP_OPT",
143 fdcf4d84 Iustin Pop
  "SHOWCMD_OPT",
144 7e5eaaa8 Guido Trotter
  "SHUTDOWN_TIMEOUT_OPT",
145 f36d7d81 Iustin Pop
  "SINGLE_NODE_OPT",
146 df62e5db Iustin Pop
  "SRC_DIR_OPT",
147 df62e5db Iustin Pop
  "SRC_NODE_OPT",
148 4abc4f1e Iustin Pop
  "SUBMIT_OPT",
149 99a8c799 Iustin Pop
  "STATIC_OPT",
150 4abc4f1e Iustin Pop
  "SYNC_OPT",
151 4abc4f1e Iustin Pop
  "TAG_SRC_OPT",
152 b5762e2a Guido Trotter
  "TIMEOUT_OPT",
153 1338f2b4 Balazs Lecz
  "UIDPOOL_OPT",
154 4abc4f1e Iustin Pop
  "USEUNITS_OPT",
155 74adc100 Iustin Pop
  "USE_REPL_NET_OPT",
156 9cdb9578 Iustin Pop
  "VERBOSE_OPT",
157 b58726e8 Iustin Pop
  "VG_NAME_OPT",
158 1f587d3d Iustin Pop
  "YES_DOIT_OPT",
159 4abc4f1e Iustin Pop
  # Generic functions for CLI programs
160 4abc4f1e Iustin Pop
  "GenericMain",
161 d77490c5 Iustin Pop
  "GenericInstanceCreate",
162 4abc4f1e Iustin Pop
  "GetClient",
163 4abc4f1e Iustin Pop
  "GetOnlineNodes",
164 4abc4f1e Iustin Pop
  "JobExecutor",
165 4abc4f1e Iustin Pop
  "JobSubmittedException",
166 4abc4f1e Iustin Pop
  "ParseTimespec",
167 7e49b6ce Michael Hanselmann
  "RunWhileClusterStopped",
168 4abc4f1e Iustin Pop
  "SubmitOpCode",
169 4abc4f1e Iustin Pop
  "SubmitOrSend",
170 4abc4f1e Iustin Pop
  "UsesRPC",
171 4abc4f1e Iustin Pop
  # Formatting functions
172 4abc4f1e Iustin Pop
  "ToStderr", "ToStdout",
173 4abc4f1e Iustin Pop
  "FormatError",
174 4abc4f1e Iustin Pop
  "GenerateTable",
175 4abc4f1e Iustin Pop
  "AskUser",
176 4abc4f1e Iustin Pop
  "FormatTimestamp",
177 8a7f1c61 Michael Hanselmann
  "FormatLogMessage",
178 4abc4f1e Iustin Pop
  # Tags functions
179 4abc4f1e Iustin Pop
  "ListTags",
180 4abc4f1e Iustin Pop
  "AddTags",
181 4abc4f1e Iustin Pop
  "RemoveTags",
182 4abc4f1e Iustin Pop
  # command line options support infrastructure
183 4abc4f1e Iustin Pop
  "ARGS_MANY_INSTANCES",
184 4abc4f1e Iustin Pop
  "ARGS_MANY_NODES",
185 4abc4f1e Iustin Pop
  "ARGS_NONE",
186 4abc4f1e Iustin Pop
  "ARGS_ONE_INSTANCE",
187 4abc4f1e Iustin Pop
  "ARGS_ONE_NODE",
188 f9faf9c3 Renรฉ Nussbaumer
  "ARGS_ONE_OS",
189 4abc4f1e Iustin Pop
  "ArgChoice",
190 4abc4f1e Iustin Pop
  "ArgCommand",
191 4abc4f1e Iustin Pop
  "ArgFile",
192 4abc4f1e Iustin Pop
  "ArgHost",
193 4abc4f1e Iustin Pop
  "ArgInstance",
194 4abc4f1e Iustin Pop
  "ArgJobId",
195 4abc4f1e Iustin Pop
  "ArgNode",
196 f9faf9c3 Renรฉ Nussbaumer
  "ArgOs",
197 4abc4f1e Iustin Pop
  "ArgSuggest",
198 4abc4f1e Iustin Pop
  "ArgUnknown",
199 4abc4f1e Iustin Pop
  "OPT_COMPL_INST_ADD_NODES",
200 4abc4f1e Iustin Pop
  "OPT_COMPL_MANY_NODES",
201 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_IALLOCATOR",
202 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_INSTANCE",
203 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_NODE",
204 36e247e1 Guido Trotter
  "OPT_COMPL_ONE_NODEGROUP",
205 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_OS",
206 4abc4f1e Iustin Pop
  "cli_option",
207 4abc4f1e Iustin Pop
  "SplitNodeOption",
208 07150497 Guido Trotter
  "CalculateOSNames",
209 a4ebd726 Michael Hanselmann
  "ParseFields",
210 eb28ecf6 Guido Trotter
  "COMMON_CREATE_OPTS",
211 4abc4f1e Iustin Pop
  ]
212 846baef9 Iustin Pop
213 8b46606c Guido Trotter
NO_PREFIX = "no_"
214 8b46606c Guido Trotter
UN_PREFIX = "-"
215 846baef9 Iustin Pop
216 84a5b33c Michael Hanselmann
#: Priorities (sorted)
217 84a5b33c Michael Hanselmann
_PRIORITY_NAMES = [
218 84a5b33c Michael Hanselmann
  ("low", constants.OP_PRIO_LOW),
219 84a5b33c Michael Hanselmann
  ("normal", constants.OP_PRIO_NORMAL),
220 84a5b33c Michael Hanselmann
  ("high", constants.OP_PRIO_HIGH),
221 84a5b33c Michael Hanselmann
  ]
222 84a5b33c Michael Hanselmann
223 84a5b33c Michael Hanselmann
#: Priority dictionary for easier lookup
224 84a5b33c Michael Hanselmann
# TODO: Replace this and _PRIORITY_NAMES with a single sorted dictionary once
225 84a5b33c Michael Hanselmann
# we migrate to Python 2.6
226 84a5b33c Michael Hanselmann
_PRIONAME_TO_VALUE = dict(_PRIORITY_NAMES)
227 84a5b33c Michael Hanselmann
228 03298ebe Michael Hanselmann
229 863d7f46 Michael Hanselmann
class _Argument:
230 7260cfbe Iustin Pop
  def __init__(self, min=0, max=None): # pylint: disable-msg=W0622
231 863d7f46 Michael Hanselmann
    self.min = min
232 863d7f46 Michael Hanselmann
    self.max = max
233 863d7f46 Michael Hanselmann
234 863d7f46 Michael Hanselmann
  def __repr__(self):
235 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s>" %
236 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max))
237 863d7f46 Michael Hanselmann
238 863d7f46 Michael Hanselmann
239 863d7f46 Michael Hanselmann
class ArgSuggest(_Argument):
240 863d7f46 Michael Hanselmann
  """Suggesting argument.
241 863d7f46 Michael Hanselmann

242 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor.
243 863d7f46 Michael Hanselmann

244 863d7f46 Michael Hanselmann
  """
245 7260cfbe Iustin Pop
  # pylint: disable-msg=W0622
246 863d7f46 Michael Hanselmann
  def __init__(self, min=0, max=None, choices=None):
247 863d7f46 Michael Hanselmann
    _Argument.__init__(self, min=min, max=max)
248 863d7f46 Michael Hanselmann
    self.choices = choices
249 863d7f46 Michael Hanselmann
250 863d7f46 Michael Hanselmann
  def __repr__(self):
251 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s choices=%r>" %
252 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max, self.choices))
253 863d7f46 Michael Hanselmann
254 863d7f46 Michael Hanselmann
255 863d7f46 Michael Hanselmann
class ArgChoice(ArgSuggest):
256 863d7f46 Michael Hanselmann
  """Choice argument.
257 863d7f46 Michael Hanselmann

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

261 863d7f46 Michael Hanselmann
  """
262 863d7f46 Michael Hanselmann
263 863d7f46 Michael Hanselmann
264 863d7f46 Michael Hanselmann
class ArgUnknown(_Argument):
265 863d7f46 Michael Hanselmann
  """Unknown argument to program (e.g. determined at runtime).
266 863d7f46 Michael Hanselmann

267 863d7f46 Michael Hanselmann
  """
268 863d7f46 Michael Hanselmann
269 863d7f46 Michael Hanselmann
270 863d7f46 Michael Hanselmann
class ArgInstance(_Argument):
271 863d7f46 Michael Hanselmann
  """Instances argument.
272 863d7f46 Michael Hanselmann

273 863d7f46 Michael Hanselmann
  """
274 863d7f46 Michael Hanselmann
275 863d7f46 Michael Hanselmann
276 863d7f46 Michael Hanselmann
class ArgNode(_Argument):
277 863d7f46 Michael Hanselmann
  """Node argument.
278 863d7f46 Michael Hanselmann

279 863d7f46 Michael Hanselmann
  """
280 863d7f46 Michael Hanselmann
281 863d7f46 Michael Hanselmann
class ArgJobId(_Argument):
282 863d7f46 Michael Hanselmann
  """Job ID argument.
283 863d7f46 Michael Hanselmann

284 863d7f46 Michael Hanselmann
  """
285 863d7f46 Michael Hanselmann
286 863d7f46 Michael Hanselmann
287 863d7f46 Michael Hanselmann
class ArgFile(_Argument):
288 863d7f46 Michael Hanselmann
  """File path argument.
289 863d7f46 Michael Hanselmann

290 863d7f46 Michael Hanselmann
  """
291 863d7f46 Michael Hanselmann
292 863d7f46 Michael Hanselmann
293 863d7f46 Michael Hanselmann
class ArgCommand(_Argument):
294 863d7f46 Michael Hanselmann
  """Command argument.
295 863d7f46 Michael Hanselmann

296 863d7f46 Michael Hanselmann
  """
297 863d7f46 Michael Hanselmann
298 863d7f46 Michael Hanselmann
299 83ec7961 Michael Hanselmann
class ArgHost(_Argument):
300 83ec7961 Michael Hanselmann
  """Host argument.
301 83ec7961 Michael Hanselmann

302 83ec7961 Michael Hanselmann
  """
303 83ec7961 Michael Hanselmann
304 83ec7961 Michael Hanselmann
305 f9faf9c3 Renรฉ Nussbaumer
class ArgOs(_Argument):
306 f9faf9c3 Renรฉ Nussbaumer
  """OS argument.
307 f9faf9c3 Renรฉ Nussbaumer

308 f9faf9c3 Renรฉ Nussbaumer
  """
309 f9faf9c3 Renรฉ Nussbaumer
310 f9faf9c3 Renรฉ Nussbaumer
311 4a265c08 Michael Hanselmann
ARGS_NONE = []
312 4a265c08 Michael Hanselmann
ARGS_MANY_INSTANCES = [ArgInstance()]
313 4a265c08 Michael Hanselmann
ARGS_MANY_NODES = [ArgNode()]
314 4a265c08 Michael Hanselmann
ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
315 4a265c08 Michael Hanselmann
ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
316 f9faf9c3 Renรฉ Nussbaumer
ARGS_ONE_OS = [ArgOs(min=1, max=1)]
317 4a265c08 Michael Hanselmann
318 4a265c08 Michael Hanselmann
319 846baef9 Iustin Pop
def _ExtractTagsObject(opts, args):
320 846baef9 Iustin Pop
  """Extract the tag type object.
321 846baef9 Iustin Pop

322 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
323 846baef9 Iustin Pop

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

343 810c50b7 Iustin Pop
  This function will extend the tags with the contents of the file
344 810c50b7 Iustin Pop
  passed in the 'tags_source' attribute of the opts parameter. A file
345 810c50b7 Iustin Pop
  named '-' will be replaced by stdin.
346 810c50b7 Iustin Pop

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

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

377 846baef9 Iustin Pop
  """
378 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
379 7699c3af Iustin Pop
  cl = GetClient()
380 7699c3af Iustin Pop
  result = cl.QueryTags(kind, name)
381 846baef9 Iustin Pop
  result = list(result)
382 846baef9 Iustin Pop
  result.sort()
383 846baef9 Iustin Pop
  for tag in result:
384 03298ebe Michael Hanselmann
    ToStdout(tag)
385 846baef9 Iustin Pop
386 846baef9 Iustin Pop
387 846baef9 Iustin Pop
def AddTags(opts, args):
388 846baef9 Iustin Pop
  """Add tags on a given object.
389 846baef9 Iustin Pop

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

395 846baef9 Iustin Pop
  """
396 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
397 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
398 846baef9 Iustin Pop
  if not args:
399 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be added")
400 846baef9 Iustin Pop
  op = opcodes.OpAddTags(kind=kind, name=name, tags=args)
401 af1a81d1 Michael Hanselmann
  SubmitOpCode(op, opts=opts)
402 846baef9 Iustin Pop
403 846baef9 Iustin Pop
404 846baef9 Iustin Pop
def RemoveTags(opts, args):
405 846baef9 Iustin Pop
  """Remove tags from a given object.
406 846baef9 Iustin Pop

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

412 846baef9 Iustin Pop
  """
413 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
414 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
415 846baef9 Iustin Pop
  if not args:
416 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be removed")
417 846baef9 Iustin Pop
  op = opcodes.OpDelTags(kind=kind, name=name, tags=args)
418 af1a81d1 Michael Hanselmann
  SubmitOpCode(op, opts=opts)
419 846baef9 Iustin Pop
420 a8083063 Iustin Pop
421 8929d28c Iustin Pop
def check_unit(option, opt, value): # pylint: disable-msg=W0613
422 65fe4693 Iustin Pop
  """OptParsers custom converter for units.
423 65fe4693 Iustin Pop

424 65fe4693 Iustin Pop
  """
425 a8083063 Iustin Pop
  try:
426 a8083063 Iustin Pop
    return utils.ParseUnit(value)
427 a8083063 Iustin Pop
  except errors.UnitParseError, err:
428 3ecf6786 Iustin Pop
    raise OptionValueError("option %s: %s" % (opt, err))
429 a8083063 Iustin Pop
430 a8083063 Iustin Pop
431 a8469393 Iustin Pop
def _SplitKeyVal(opt, data):
432 a8469393 Iustin Pop
  """Convert a KeyVal string into a dict.
433 a8469393 Iustin Pop

434 a8469393 Iustin Pop
  This function will convert a key=val[,...] string into a dict. Empty
435 a8469393 Iustin Pop
  values will be converted specially: keys which have the prefix 'no_'
436 a8469393 Iustin Pop
  will have the value=False and the prefix stripped, the others will
437 a8469393 Iustin Pop
  have value=True.
438 a8469393 Iustin Pop

439 a8469393 Iustin Pop
  @type opt: string
440 a8469393 Iustin Pop
  @param opt: a string holding the option name for which we process the
441 a8469393 Iustin Pop
      data, used in building error messages
442 a8469393 Iustin Pop
  @type data: string
443 a8469393 Iustin Pop
  @param data: a string of the format key=val,key=val,...
444 a8469393 Iustin Pop
  @rtype: dict
445 a8469393 Iustin Pop
  @return: {key=val, key=val}
446 a8469393 Iustin Pop
  @raises errors.ParameterError: if there are duplicate keys
447 a8469393 Iustin Pop

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

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

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

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

501 a8469393 Iustin Pop
  """
502 a8469393 Iustin Pop
  return _SplitKeyVal(opt, value)
503 a8469393 Iustin Pop
504 a8469393 Iustin Pop
505 e7b61bb0 Iustin Pop
def check_bool(option, opt, value): # pylint: disable-msg=W0613
506 e7b61bb0 Iustin Pop
  """Custom parser for yes/no options.
507 e7b61bb0 Iustin Pop

508 e7b61bb0 Iustin Pop
  This will store the parsed value as either True or False.
509 e7b61bb0 Iustin Pop

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

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

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

1137 c41eea6e Iustin Pop
  @param argv: the command line
1138 c41eea6e Iustin Pop
  @param commands: dictionary with special contents, see the design
1139 c41eea6e Iustin Pop
      doc for cmdline handling
1140 c41eea6e Iustin Pop
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
1141 098c0958 Michael Hanselmann

1142 a8083063 Iustin Pop
  """
1143 a8083063 Iustin Pop
  if len(argv) == 0:
1144 a8083063 Iustin Pop
    binary = "<command>"
1145 a8083063 Iustin Pop
  else:
1146 a8083063 Iustin Pop
    binary = argv[0].split("/")[-1]
1147 a8083063 Iustin Pop
1148 a8083063 Iustin Pop
  if len(argv) > 1 and argv[1] == "--version":
1149 84a12e40 Iustin Pop
    ToStdout("%s (ganeti %s) %s", binary, constants.VCS_VERSION,
1150 84a12e40 Iustin Pop
             constants.RELEASE_VERSION)
1151 a8083063 Iustin Pop
    # Quit right away. That way we don't have to care about this special
1152 a8083063 Iustin Pop
    # argument. optparse.py does it the same.
1153 a8083063 Iustin Pop
    sys.exit(0)
1154 a8083063 Iustin Pop
1155 de47cf8f Guido Trotter
  if len(argv) < 2 or not (argv[1] in commands or
1156 70a35b6f Guido Trotter
                           argv[1] in aliases):
1157 a8083063 Iustin Pop
    # let's do a nice thing
1158 a8083063 Iustin Pop
    sortedcmds = commands.keys()
1159 a8083063 Iustin Pop
    sortedcmds.sort()
1160 03298ebe Michael Hanselmann
1161 03298ebe Michael Hanselmann
    ToStdout("Usage: %s {command} [options...] [argument...]", binary)
1162 03298ebe Michael Hanselmann
    ToStdout("%s <command> --help to see details, or man %s", binary, binary)
1163 03298ebe Michael Hanselmann
    ToStdout("")
1164 03298ebe Michael Hanselmann
1165 a8083063 Iustin Pop
    # compute the max line length for cmd + usage
1166 4e713df6 Iustin Pop
    mlen = max([len(" %s" % cmd) for cmd in commands])
1167 a8083063 Iustin Pop
    mlen = min(60, mlen) # should not get here...
1168 03298ebe Michael Hanselmann
1169 a8083063 Iustin Pop
    # and format a nice command list
1170 03298ebe Michael Hanselmann
    ToStdout("Commands:")
1171 a8083063 Iustin Pop
    for cmd in sortedcmds:
1172 4e713df6 Iustin Pop
      cmdstr = " %s" % (cmd,)
1173 9a033156 Iustin Pop
      help_text = commands[cmd][4]
1174 03298ebe Michael Hanselmann
      help_lines = textwrap.wrap(help_text, 79 - 3 - mlen)
1175 03298ebe Michael Hanselmann
      ToStdout("%-*s - %s", mlen, cmdstr, help_lines.pop(0))
1176 a8083063 Iustin Pop
      for line in help_lines:
1177 03298ebe Michael Hanselmann
        ToStdout("%-*s   %s", mlen, "", line)
1178 03298ebe Michael Hanselmann
1179 03298ebe Michael Hanselmann
    ToStdout("")
1180 03298ebe Michael Hanselmann
1181 a8083063 Iustin Pop
    return None, None, None
1182 de47cf8f Guido Trotter
1183 de47cf8f Guido Trotter
  # get command, unalias it, and look it up in commands
1184 a8083063 Iustin Pop
  cmd = argv.pop(1)
1185 de47cf8f Guido Trotter
  if cmd in aliases:
1186 de47cf8f Guido Trotter
    if cmd in commands:
1187 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' overrides an existing"
1188 de47cf8f Guido Trotter
                                   " command" % cmd)
1189 de47cf8f Guido Trotter
1190 de47cf8f Guido Trotter
    if aliases[cmd] not in commands:
1191 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' maps to non-existing"
1192 de47cf8f Guido Trotter
                                   " command '%s'" % (cmd, aliases[cmd]))
1193 de47cf8f Guido Trotter
1194 de47cf8f Guido Trotter
    cmd = aliases[cmd]
1195 de47cf8f Guido Trotter
1196 a8005e17 Michael Hanselmann
  func, args_def, parser_opts, usage, description = commands[cmd]
1197 5786c087 Michael Hanselmann
  parser = OptionParser(option_list=parser_opts + COMMON_OPTS,
1198 a8083063 Iustin Pop
                        description=description,
1199 a8083063 Iustin Pop
                        formatter=TitledHelpFormatter(),
1200 a8083063 Iustin Pop
                        usage="%%prog %s %s" % (cmd, usage))
1201 a8083063 Iustin Pop
  parser.disable_interspersed_args()
1202 a8083063 Iustin Pop
  options, args = parser.parse_args()
1203 a8005e17 Michael Hanselmann
1204 a8005e17 Michael Hanselmann
  if not _CheckArguments(cmd, args_def, args):
1205 a8083063 Iustin Pop
    return None, None, None
1206 a8083063 Iustin Pop
1207 a8083063 Iustin Pop
  return func, options, args
1208 a8083063 Iustin Pop
1209 a8083063 Iustin Pop
1210 a8005e17 Michael Hanselmann
def _CheckArguments(cmd, args_def, args):
1211 a8005e17 Michael Hanselmann
  """Verifies the arguments using the argument definition.
1212 a8005e17 Michael Hanselmann

1213 a8005e17 Michael Hanselmann
  Algorithm:
1214 a8005e17 Michael Hanselmann

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

1217 a8005e17 Michael Hanselmann
    1. For each argument in definition
1218 a8005e17 Michael Hanselmann

1219 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
1220 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
1221 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
1222 a8005e17 Michael Hanselmann

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

1225 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
1226 a8005e17 Michael Hanselmann

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

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

1231 a8005e17 Michael Hanselmann
  """
1232 a8005e17 Michael Hanselmann
  if args and not args_def:
1233 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects no arguments", cmd)
1234 a8005e17 Michael Hanselmann
    return False
1235 a8005e17 Michael Hanselmann
1236 a8005e17 Michael Hanselmann
  min_count = None
1237 a8005e17 Michael Hanselmann
  max_count = None
1238 a8005e17 Michael Hanselmann
  check_max = None
1239 a8005e17 Michael Hanselmann
1240 a8005e17 Michael Hanselmann
  last_idx = len(args_def) - 1
1241 a8005e17 Michael Hanselmann
1242 a8005e17 Michael Hanselmann
  for idx, arg in enumerate(args_def):
1243 a8005e17 Michael Hanselmann
    if min_count is None:
1244 a8005e17 Michael Hanselmann
      min_count = arg.min
1245 a8005e17 Michael Hanselmann
    elif arg.min is not None:
1246 a8005e17 Michael Hanselmann
      min_count += arg.min
1247 a8005e17 Michael Hanselmann
1248 a8005e17 Michael Hanselmann
    if max_count is None:
1249 a8005e17 Michael Hanselmann
      max_count = arg.max
1250 a8005e17 Michael Hanselmann
    elif arg.max is not None:
1251 a8005e17 Michael Hanselmann
      max_count += arg.max
1252 a8005e17 Michael Hanselmann
1253 a8005e17 Michael Hanselmann
    if idx == last_idx:
1254 a8005e17 Michael Hanselmann
      check_max = (arg.max is not None)
1255 a8005e17 Michael Hanselmann
1256 a8005e17 Michael Hanselmann
    elif arg.max is None:
1257 a8005e17 Michael Hanselmann
      raise errors.ProgrammerError("Only the last argument can have max=None")
1258 a8005e17 Michael Hanselmann
1259 a8005e17 Michael Hanselmann
  if check_max:
1260 a8005e17 Michael Hanselmann
    # Command with exact number of arguments
1261 a8005e17 Michael Hanselmann
    if (min_count is not None and max_count is not None and
1262 a8005e17 Michael Hanselmann
        min_count == max_count and len(args) != min_count):
1263 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects %d argument(s)", cmd, min_count)
1264 a8005e17 Michael Hanselmann
      return False
1265 a8005e17 Michael Hanselmann
1266 a8005e17 Michael Hanselmann
    # Command with limited number of arguments
1267 a8005e17 Michael Hanselmann
    if max_count is not None and len(args) > max_count:
1268 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects only %d argument(s)",
1269 a8005e17 Michael Hanselmann
               cmd, max_count)
1270 a8005e17 Michael Hanselmann
      return False
1271 a8005e17 Michael Hanselmann
1272 a8005e17 Michael Hanselmann
  # Command with some required arguments
1273 a8005e17 Michael Hanselmann
  if min_count is not None and len(args) < min_count:
1274 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects at least %d argument(s)",
1275 a8005e17 Michael Hanselmann
             cmd, min_count)
1276 a8005e17 Michael Hanselmann
    return False
1277 a8005e17 Michael Hanselmann
1278 a8005e17 Michael Hanselmann
  return True
1279 a8005e17 Michael Hanselmann
1280 a8005e17 Michael Hanselmann
1281 60d49723 Michael Hanselmann
def SplitNodeOption(value):
1282 60d49723 Michael Hanselmann
  """Splits the value of a --node option.
1283 60d49723 Michael Hanselmann

1284 60d49723 Michael Hanselmann
  """
1285 60d49723 Michael Hanselmann
  if value and ':' in value:
1286 60d49723 Michael Hanselmann
    return value.split(':', 1)
1287 60d49723 Michael Hanselmann
  else:
1288 60d49723 Michael Hanselmann
    return (value, None)
1289 60d49723 Michael Hanselmann
1290 60d49723 Michael Hanselmann
1291 07150497 Guido Trotter
def CalculateOSNames(os_name, os_variants):
1292 07150497 Guido Trotter
  """Calculates all the names an OS can be called, according to its variants.
1293 07150497 Guido Trotter

1294 07150497 Guido Trotter
  @type os_name: string
1295 07150497 Guido Trotter
  @param os_name: base name of the os
1296 07150497 Guido Trotter
  @type os_variants: list or None
1297 07150497 Guido Trotter
  @param os_variants: list of supported variants
1298 07150497 Guido Trotter
  @rtype: list
1299 07150497 Guido Trotter
  @return: list of valid names
1300 07150497 Guido Trotter

1301 07150497 Guido Trotter
  """
1302 07150497 Guido Trotter
  if os_variants:
1303 07150497 Guido Trotter
    return ['%s+%s' % (os_name, v) for v in os_variants]
1304 07150497 Guido Trotter
  else:
1305 07150497 Guido Trotter
    return [os_name]
1306 07150497 Guido Trotter
1307 07150497 Guido Trotter
1308 a4ebd726 Michael Hanselmann
def ParseFields(selected, default):
1309 a4ebd726 Michael Hanselmann
  """Parses the values of "--field"-like options.
1310 a4ebd726 Michael Hanselmann

1311 a4ebd726 Michael Hanselmann
  @type selected: string or None
1312 a4ebd726 Michael Hanselmann
  @param selected: User-selected options
1313 a4ebd726 Michael Hanselmann
  @type default: list
1314 a4ebd726 Michael Hanselmann
  @param default: Default fields
1315 a4ebd726 Michael Hanselmann

1316 a4ebd726 Michael Hanselmann
  """
1317 a4ebd726 Michael Hanselmann
  if selected is None:
1318 a4ebd726 Michael Hanselmann
    return default
1319 a4ebd726 Michael Hanselmann
1320 a4ebd726 Michael Hanselmann
  if selected.startswith("+"):
1321 a4ebd726 Michael Hanselmann
    return default + selected[1:].split(",")
1322 a4ebd726 Michael Hanselmann
1323 a4ebd726 Michael Hanselmann
  return selected.split(",")
1324 a4ebd726 Michael Hanselmann
1325 a4ebd726 Michael Hanselmann
1326 e0e916fe Iustin Pop
UsesRPC = rpc.RunWithRPC
1327 4331f6cd Michael Hanselmann
1328 4331f6cd Michael Hanselmann
1329 47988778 Iustin Pop
def AskUser(text, choices=None):
1330 47988778 Iustin Pop
  """Ask the user a question.
1331 a8083063 Iustin Pop

1332 c41eea6e Iustin Pop
  @param text: the question to ask
1333 a8083063 Iustin Pop

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

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

1343 a8083063 Iustin Pop
  """
1344 47988778 Iustin Pop
  if choices is None:
1345 47988778 Iustin Pop
    choices = [('y', True, 'Perform the operation'),
1346 47988778 Iustin Pop
               ('n', False, 'Do not perform the operation')]
1347 47988778 Iustin Pop
  if not choices or not isinstance(choices, list):
1348 5bbd3f7f Michael Hanselmann
    raise errors.ProgrammerError("Invalid choices argument to AskUser")
1349 47988778 Iustin Pop
  for entry in choices:
1350 47988778 Iustin Pop
    if not isinstance(entry, tuple) or len(entry) < 3 or entry[0] == '?':
1351 5bbd3f7f Michael Hanselmann
      raise errors.ProgrammerError("Invalid choices element to AskUser")
1352 47988778 Iustin Pop
1353 47988778 Iustin Pop
  answer = choices[-1][1]
1354 47988778 Iustin Pop
  new_text = []
1355 47988778 Iustin Pop
  for line in text.splitlines():
1356 47988778 Iustin Pop
    new_text.append(textwrap.fill(line, 70, replace_whitespace=False))
1357 47988778 Iustin Pop
  text = "\n".join(new_text)
1358 a8083063 Iustin Pop
  try:
1359 3023170f Iustin Pop
    f = file("/dev/tty", "a+")
1360 a8083063 Iustin Pop
  except IOError:
1361 47988778 Iustin Pop
    return answer
1362 a8083063 Iustin Pop
  try:
1363 47988778 Iustin Pop
    chars = [entry[0] for entry in choices]
1364 47988778 Iustin Pop
    chars[-1] = "[%s]" % chars[-1]
1365 47988778 Iustin Pop
    chars.append('?')
1366 47988778 Iustin Pop
    maps = dict([(entry[0], entry[1]) for entry in choices])
1367 47988778 Iustin Pop
    while True:
1368 47988778 Iustin Pop
      f.write(text)
1369 47988778 Iustin Pop
      f.write('\n')
1370 47988778 Iustin Pop
      f.write("/".join(chars))
1371 47988778 Iustin Pop
      f.write(": ")
1372 47988778 Iustin Pop
      line = f.readline(2).strip().lower()
1373 47988778 Iustin Pop
      if line in maps:
1374 47988778 Iustin Pop
        answer = maps[line]
1375 47988778 Iustin Pop
        break
1376 47988778 Iustin Pop
      elif line == '?':
1377 47988778 Iustin Pop
        for entry in choices:
1378 47988778 Iustin Pop
          f.write(" %s - %s\n" % (entry[0], entry[2]))
1379 47988778 Iustin Pop
        f.write("\n")
1380 47988778 Iustin Pop
        continue
1381 a8083063 Iustin Pop
  finally:
1382 a8083063 Iustin Pop
    f.close()
1383 a8083063 Iustin Pop
  return answer
1384 a8083063 Iustin Pop
1385 a8083063 Iustin Pop
1386 e9d741b6 Iustin Pop
class JobSubmittedException(Exception):
1387 e9d741b6 Iustin Pop
  """Job was submitted, client should exit.
1388 e9d741b6 Iustin Pop

1389 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1390 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1391 e9d741b6 Iustin Pop

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

1394 e9d741b6 Iustin Pop
  """
1395 e9d741b6 Iustin Pop
1396 e9d741b6 Iustin Pop
1397 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1398 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1399 a8083063 Iustin Pop

1400 0a1e74d9 Iustin Pop
  @type ops: list
1401 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1402 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1403 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1404 0a1e74d9 Iustin Pop
             if None, a new client will be created
1405 a8083063 Iustin Pop

1406 a8083063 Iustin Pop
  """
1407 e2212007 Iustin Pop
  if cl is None:
1408 b33e986b Iustin Pop
    cl = GetClient()
1409 685ee993 Iustin Pop
1410 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1411 0a1e74d9 Iustin Pop
1412 0a1e74d9 Iustin Pop
  return job_id
1413 0a1e74d9 Iustin Pop
1414 0a1e74d9 Iustin Pop
1415 4e338533 Michael Hanselmann
def GenericPollJob(job_id, cbs, report_cbs):
1416 4e338533 Michael Hanselmann
  """Generic job-polling function.
1417 0a1e74d9 Iustin Pop

1418 4e338533 Michael Hanselmann
  @type job_id: number
1419 4e338533 Michael Hanselmann
  @param job_id: Job ID
1420 4e338533 Michael Hanselmann
  @type cbs: Instance of L{JobPollCbBase}
1421 4e338533 Michael Hanselmann
  @param cbs: Data callbacks
1422 4e338533 Michael Hanselmann
  @type report_cbs: Instance of L{JobPollReportCbBase}
1423 4e338533 Michael Hanselmann
  @param report_cbs: Reporting callbacks
1424 0a1e74d9 Iustin Pop

1425 0a1e74d9 Iustin Pop
  """
1426 6c5a7090 Michael Hanselmann
  prev_job_info = None
1427 6c5a7090 Michael Hanselmann
  prev_logmsg_serial = None
1428 6c5a7090 Michael Hanselmann
1429 f4484122 Michael Hanselmann
  status = None
1430 f4484122 Michael Hanselmann
1431 685ee993 Iustin Pop
  while True:
1432 4e338533 Michael Hanselmann
    result = cbs.WaitForJobChangeOnce(job_id, ["status"], prev_job_info,
1433 4e338533 Michael Hanselmann
                                      prev_logmsg_serial)
1434 6c5a7090 Michael Hanselmann
    if not result:
1435 685ee993 Iustin Pop
      # job not found, go away!
1436 0bbe448c Michael Hanselmann
      raise errors.JobLost("Job with id %s lost" % job_id)
1437 4e338533 Michael Hanselmann
1438 4e338533 Michael Hanselmann
    if result == constants.JOB_NOTCHANGED:
1439 4e338533 Michael Hanselmann
      report_cbs.ReportNotChanged(job_id, status)
1440 f4484122 Michael Hanselmann
1441 f4484122 Michael Hanselmann
      # Wait again
1442 f4484122 Michael Hanselmann
      continue
1443 685ee993 Iustin Pop
1444 6c5a7090 Michael Hanselmann
    # Split result, a tuple of (field values, log entries)
1445 6c5a7090 Michael Hanselmann
    (job_info, log_entries) = result
1446 6c5a7090 Michael Hanselmann
    (status, ) = job_info
1447 6c5a7090 Michael Hanselmann
1448 6c5a7090 Michael Hanselmann
    if log_entries:
1449 6c5a7090 Michael Hanselmann
      for log_entry in log_entries:
1450 4e338533 Michael Hanselmann
        (serial, timestamp, log_type, message) = log_entry
1451 4e338533 Michael Hanselmann
        report_cbs.ReportLogMessage(job_id, serial, timestamp,
1452 4e338533 Michael Hanselmann
                                    log_type, message)
1453 6c5a7090 Michael Hanselmann
        prev_logmsg_serial = max(prev_logmsg_serial, serial)
1454 6c5a7090 Michael Hanselmann
1455 0bbe448c Michael Hanselmann
    # TODO: Handle canceled and archived jobs
1456 fbf0262f Michael Hanselmann
    elif status in (constants.JOB_STATUS_SUCCESS,
1457 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_ERROR,
1458 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELING,
1459 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELED):
1460 685ee993 Iustin Pop
      break
1461 6c5a7090 Michael Hanselmann
1462 6c5a7090 Michael Hanselmann
    prev_job_info = job_info
1463 685ee993 Iustin Pop
1464 4e338533 Michael Hanselmann
  jobs = cbs.QueryJobs([job_id], ["status", "opstatus", "opresult"])
1465 0bbe448c Michael Hanselmann
  if not jobs:
1466 0bbe448c Michael Hanselmann
    raise errors.JobLost("Job with id %s lost" % job_id)
1467 685ee993 Iustin Pop
1468 0e050889 Iustin Pop
  status, opstatus, result = jobs[0]
1469 4e338533 Michael Hanselmann
1470 0bbe448c Michael Hanselmann
  if status == constants.JOB_STATUS_SUCCESS:
1471 53c04d04 Iustin Pop
    return result
1472 4e338533 Michael Hanselmann
1473 4e338533 Michael Hanselmann
  if status in (constants.JOB_STATUS_CANCELING, constants.JOB_STATUS_CANCELED):
1474 fbf0262f Michael Hanselmann
    raise errors.OpExecError("Job was canceled")
1475 4e338533 Michael Hanselmann
1476 4e338533 Michael Hanselmann
  has_ok = False
1477 4e338533 Michael Hanselmann
  for idx, (status, msg) in enumerate(zip(opstatus, result)):
1478 4e338533 Michael Hanselmann
    if status == constants.OP_STATUS_SUCCESS:
1479 4e338533 Michael Hanselmann
      has_ok = True
1480 4e338533 Michael Hanselmann
    elif status == constants.OP_STATUS_ERROR:
1481 4e338533 Michael Hanselmann
      errors.MaybeRaise(msg)
1482 4e338533 Michael Hanselmann
1483 4e338533 Michael Hanselmann
      if has_ok:
1484 4e338533 Michael Hanselmann
        raise errors.OpExecError("partial failure (opcode %d): %s" %
1485 4e338533 Michael Hanselmann
                                 (idx, msg))
1486 4e338533 Michael Hanselmann
1487 4e338533 Michael Hanselmann
      raise errors.OpExecError(str(msg))
1488 4e338533 Michael Hanselmann
1489 4e338533 Michael Hanselmann
  # default failure mode
1490 4e338533 Michael Hanselmann
  raise errors.OpExecError(result)
1491 4e338533 Michael Hanselmann
1492 4e338533 Michael Hanselmann
1493 4e338533 Michael Hanselmann
class JobPollCbBase:
1494 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} callbacks.
1495 4e338533 Michael Hanselmann

1496 4e338533 Michael Hanselmann
  """
1497 4e338533 Michael Hanselmann
  def __init__(self):
1498 4e338533 Michael Hanselmann
    """Initializes this class.
1499 4e338533 Michael Hanselmann

1500 4e338533 Michael Hanselmann
    """
1501 4e338533 Michael Hanselmann
1502 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1503 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1504 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1505 4e338533 Michael Hanselmann

1506 4e338533 Michael Hanselmann
    """
1507 4e338533 Michael Hanselmann
    raise NotImplementedError()
1508 4e338533 Michael Hanselmann
1509 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1510 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1511 4e338533 Michael Hanselmann

1512 4e338533 Michael Hanselmann
    @type job_ids: list of numbers
1513 4e338533 Michael Hanselmann
    @param job_ids: Job IDs
1514 4e338533 Michael Hanselmann
    @type fields: list of strings
1515 4e338533 Michael Hanselmann
    @param fields: Fields
1516 4e338533 Michael Hanselmann

1517 4e338533 Michael Hanselmann
    """
1518 4e338533 Michael Hanselmann
    raise NotImplementedError()
1519 4e338533 Michael Hanselmann
1520 4e338533 Michael Hanselmann
1521 4e338533 Michael Hanselmann
class JobPollReportCbBase:
1522 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} reporting callbacks.
1523 4e338533 Michael Hanselmann

1524 4e338533 Michael Hanselmann
  """
1525 4e338533 Michael Hanselmann
  def __init__(self):
1526 4e338533 Michael Hanselmann
    """Initializes this class.
1527 4e338533 Michael Hanselmann

1528 4e338533 Michael Hanselmann
    """
1529 4e338533 Michael Hanselmann
1530 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1531 4e338533 Michael Hanselmann
    """Handles a log message.
1532 4e338533 Michael Hanselmann

1533 4e338533 Michael Hanselmann
    """
1534 4e338533 Michael Hanselmann
    raise NotImplementedError()
1535 4e338533 Michael Hanselmann
1536 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1537 4e338533 Michael Hanselmann
    """Called for if a job hasn't changed in a while.
1538 4e338533 Michael Hanselmann

1539 4e338533 Michael Hanselmann
    @type job_id: number
1540 4e338533 Michael Hanselmann
    @param job_id: Job ID
1541 4e338533 Michael Hanselmann
    @type status: string or None
1542 4e338533 Michael Hanselmann
    @param status: Job status if available
1543 4e338533 Michael Hanselmann

1544 4e338533 Michael Hanselmann
    """
1545 4e338533 Michael Hanselmann
    raise NotImplementedError()
1546 4e338533 Michael Hanselmann
1547 4e338533 Michael Hanselmann
1548 4e338533 Michael Hanselmann
class _LuxiJobPollCb(JobPollCbBase):
1549 4e338533 Michael Hanselmann
  def __init__(self, cl):
1550 4e338533 Michael Hanselmann
    """Initializes this class.
1551 4e338533 Michael Hanselmann

1552 4e338533 Michael Hanselmann
    """
1553 4e338533 Michael Hanselmann
    JobPollCbBase.__init__(self)
1554 4e338533 Michael Hanselmann
    self.cl = cl
1555 4e338533 Michael Hanselmann
1556 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1557 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1558 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1559 4e338533 Michael Hanselmann

1560 4e338533 Michael Hanselmann
    """
1561 4e338533 Michael Hanselmann
    return self.cl.WaitForJobChangeOnce(job_id, fields,
1562 4e338533 Michael Hanselmann
                                        prev_job_info, prev_log_serial)
1563 4e338533 Michael Hanselmann
1564 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1565 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1566 4e338533 Michael Hanselmann

1567 4e338533 Michael Hanselmann
    """
1568 4e338533 Michael Hanselmann
    return self.cl.QueryJobs(job_ids, fields)
1569 4e338533 Michael Hanselmann
1570 4e338533 Michael Hanselmann
1571 4e338533 Michael Hanselmann
class FeedbackFnJobPollReportCb(JobPollReportCbBase):
1572 4e338533 Michael Hanselmann
  def __init__(self, feedback_fn):
1573 4e338533 Michael Hanselmann
    """Initializes this class.
1574 4e338533 Michael Hanselmann

1575 4e338533 Michael Hanselmann
    """
1576 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1577 4e338533 Michael Hanselmann
1578 4e338533 Michael Hanselmann
    self.feedback_fn = feedback_fn
1579 4e338533 Michael Hanselmann
1580 4e338533 Michael Hanselmann
    assert callable(feedback_fn)
1581 4e338533 Michael Hanselmann
1582 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1583 4e338533 Michael Hanselmann
    """Handles a log message.
1584 4e338533 Michael Hanselmann

1585 4e338533 Michael Hanselmann
    """
1586 4e338533 Michael Hanselmann
    self.feedback_fn((timestamp, log_type, log_msg))
1587 4e338533 Michael Hanselmann
1588 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1589 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1590 4e338533 Michael Hanselmann

1591 4e338533 Michael Hanselmann
    """
1592 4e338533 Michael Hanselmann
    # Ignore
1593 4e338533 Michael Hanselmann
1594 4e338533 Michael Hanselmann
1595 4e338533 Michael Hanselmann
class StdioJobPollReportCb(JobPollReportCbBase):
1596 4e338533 Michael Hanselmann
  def __init__(self):
1597 4e338533 Michael Hanselmann
    """Initializes this class.
1598 4e338533 Michael Hanselmann

1599 4e338533 Michael Hanselmann
    """
1600 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1601 4e338533 Michael Hanselmann
1602 4e338533 Michael Hanselmann
    self.notified_queued = False
1603 4e338533 Michael Hanselmann
    self.notified_waitlock = False
1604 4e338533 Michael Hanselmann
1605 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1606 4e338533 Michael Hanselmann
    """Handles a log message.
1607 4e338533 Michael Hanselmann

1608 4e338533 Michael Hanselmann
    """
1609 4e338533 Michael Hanselmann
    ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)),
1610 8a7f1c61 Michael Hanselmann
             FormatLogMessage(log_type, log_msg))
1611 4e338533 Michael Hanselmann
1612 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1613 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1614 4e338533 Michael Hanselmann

1615 4e338533 Michael Hanselmann
    """
1616 4e338533 Michael Hanselmann
    if status is None:
1617 4e338533 Michael Hanselmann
      return
1618 4e338533 Michael Hanselmann
1619 4e338533 Michael Hanselmann
    if status == constants.JOB_STATUS_QUEUED and not self.notified_queued:
1620 4e338533 Michael Hanselmann
      ToStderr("Job %s is waiting in queue", job_id)
1621 4e338533 Michael Hanselmann
      self.notified_queued = True
1622 4e338533 Michael Hanselmann
1623 4e338533 Michael Hanselmann
    elif status == constants.JOB_STATUS_WAITLOCK and not self.notified_waitlock:
1624 4e338533 Michael Hanselmann
      ToStderr("Job %s is trying to acquire all necessary locks", job_id)
1625 4e338533 Michael Hanselmann
      self.notified_waitlock = True
1626 4e338533 Michael Hanselmann
1627 4e338533 Michael Hanselmann
1628 8a7f1c61 Michael Hanselmann
def FormatLogMessage(log_type, log_msg):
1629 8a7f1c61 Michael Hanselmann
  """Formats a job message according to its type.
1630 8a7f1c61 Michael Hanselmann

1631 8a7f1c61 Michael Hanselmann
  """
1632 8a7f1c61 Michael Hanselmann
  if log_type != constants.ELOG_MESSAGE:
1633 8a7f1c61 Michael Hanselmann
    log_msg = str(log_msg)
1634 8a7f1c61 Michael Hanselmann
1635 8a7f1c61 Michael Hanselmann
  return utils.SafeEncode(log_msg)
1636 8a7f1c61 Michael Hanselmann
1637 8a7f1c61 Michael Hanselmann
1638 583163a6 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None, reporter=None):
1639 4e338533 Michael Hanselmann
  """Function to poll for the result of a job.
1640 4e338533 Michael Hanselmann

1641 4e338533 Michael Hanselmann
  @type job_id: job identified
1642 4e338533 Michael Hanselmann
  @param job_id: the job to poll for results
1643 4e338533 Michael Hanselmann
  @type cl: luxi.Client
1644 4e338533 Michael Hanselmann
  @param cl: the luxi client to use for communicating with the master;
1645 4e338533 Michael Hanselmann
             if None, a new client will be created
1646 4e338533 Michael Hanselmann

1647 4e338533 Michael Hanselmann
  """
1648 4e338533 Michael Hanselmann
  if cl is None:
1649 4e338533 Michael Hanselmann
    cl = GetClient()
1650 4e338533 Michael Hanselmann
1651 583163a6 Michael Hanselmann
  if reporter is None:
1652 583163a6 Michael Hanselmann
    if feedback_fn:
1653 583163a6 Michael Hanselmann
      reporter = FeedbackFnJobPollReportCb(feedback_fn)
1654 583163a6 Michael Hanselmann
    else:
1655 583163a6 Michael Hanselmann
      reporter = StdioJobPollReportCb()
1656 583163a6 Michael Hanselmann
  elif feedback_fn:
1657 583163a6 Michael Hanselmann
    raise errors.ProgrammerError("Can't specify reporter and feedback function")
1658 4e338533 Michael Hanselmann
1659 4e338533 Michael Hanselmann
  return GenericPollJob(job_id, _LuxiJobPollCb(cl), reporter)
1660 ceab32dd Iustin Pop
1661 ceab32dd Iustin Pop
1662 583163a6 Michael Hanselmann
def SubmitOpCode(op, cl=None, feedback_fn=None, opts=None, reporter=None):
1663 0a1e74d9 Iustin Pop
  """Legacy function to submit an opcode.
1664 0a1e74d9 Iustin Pop

1665 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1666 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1667 0a1e74d9 Iustin Pop
  interaction functions.
1668 0a1e74d9 Iustin Pop

1669 0a1e74d9 Iustin Pop
  """
1670 0a1e74d9 Iustin Pop
  if cl is None:
1671 0a1e74d9 Iustin Pop
    cl = GetClient()
1672 0a1e74d9 Iustin Pop
1673 293ba2d8 Iustin Pop
  SetGenericOpcodeOpts([op], opts)
1674 293ba2d8 Iustin Pop
1675 5d297d8a Michael Hanselmann
  job_id = SendJob([op], cl=cl)
1676 0a1e74d9 Iustin Pop
1677 583163a6 Michael Hanselmann
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn,
1678 583163a6 Michael Hanselmann
                       reporter=reporter)
1679 53c04d04 Iustin Pop
1680 53c04d04 Iustin Pop
  return op_results[0]
1681 0a1e74d9 Iustin Pop
1682 0a1e74d9 Iustin Pop
1683 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1684 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1685 94428652 Iustin Pop

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

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

1694 94428652 Iustin Pop
  """
1695 94428652 Iustin Pop
  if opts and opts.submit_only:
1696 293ba2d8 Iustin Pop
    job = [op]
1697 293ba2d8 Iustin Pop
    SetGenericOpcodeOpts(job, opts)
1698 293ba2d8 Iustin Pop
    job_id = SendJob(job, cl=cl)
1699 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
1700 94428652 Iustin Pop
  else:
1701 293ba2d8 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
1702 293ba2d8 Iustin Pop
1703 293ba2d8 Iustin Pop
1704 293ba2d8 Iustin Pop
def SetGenericOpcodeOpts(opcode_list, options):
1705 293ba2d8 Iustin Pop
  """Processor for generic options.
1706 293ba2d8 Iustin Pop

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

1710 293ba2d8 Iustin Pop
  @param opcode_list: list of opcodes
1711 293ba2d8 Iustin Pop
  @param options: command line options or None
1712 293ba2d8 Iustin Pop
  @return: None (in-place modification)
1713 293ba2d8 Iustin Pop

1714 293ba2d8 Iustin Pop
  """
1715 293ba2d8 Iustin Pop
  if not options:
1716 293ba2d8 Iustin Pop
    return
1717 293ba2d8 Iustin Pop
  for op in opcode_list:
1718 aa06f8c6 Michael Hanselmann
    op.debug_level = options.debug
1719 a0a6ff34 Iustin Pop
    if hasattr(options, "dry_run"):
1720 a0a6ff34 Iustin Pop
      op.dry_run = options.dry_run
1721 aa06f8c6 Michael Hanselmann
    if getattr(options, "priority", None) is not None:
1722 aa06f8c6 Michael Hanselmann
      op.priority = _PRIONAME_TO_VALUE[options.priority]
1723 94428652 Iustin Pop
1724 94428652 Iustin Pop
1725 af30b2fd Michael Hanselmann
def GetClient():
1726 af30b2fd Michael Hanselmann
  # TODO: Cache object?
1727 b33e986b Iustin Pop
  try:
1728 b33e986b Iustin Pop
    client = luxi.Client()
1729 b33e986b Iustin Pop
  except luxi.NoMasterError:
1730 d9a51679 Michael Hanselmann
    ss = ssconf.SimpleStore()
1731 d9a51679 Michael Hanselmann
1732 d9a51679 Michael Hanselmann
    # Try to read ssconf file
1733 d9a51679 Michael Hanselmann
    try:
1734 d9a51679 Michael Hanselmann
      ss.GetMasterNode()
1735 d9a51679 Michael Hanselmann
    except errors.ConfigurationError:
1736 d9a51679 Michael Hanselmann
      raise errors.OpPrereqError("Cluster not initialized or this machine is"
1737 d9a51679 Michael Hanselmann
                                 " not part of a cluster")
1738 d9a51679 Michael Hanselmann
1739 d9a51679 Michael Hanselmann
    master, myself = ssconf.GetMasterAndMyself(ss=ss)
1740 b33e986b Iustin Pop
    if master != myself:
1741 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
1742 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
1743 b33e986b Iustin Pop
                                 master)
1744 d9a51679 Michael Hanselmann
    raise
1745 b33e986b Iustin Pop
  return client
1746 af30b2fd Michael Hanselmann
1747 af30b2fd Michael Hanselmann
1748 73702ee7 Iustin Pop
def FormatError(err):
1749 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
1750 73702ee7 Iustin Pop

1751 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
1752 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
1753 73702ee7 Iustin Pop
  second, a string describing the error message (not
1754 73702ee7 Iustin Pop
  newline-terminated).
1755 73702ee7 Iustin Pop

1756 73702ee7 Iustin Pop
  """
1757 73702ee7 Iustin Pop
  retcode = 1
1758 73702ee7 Iustin Pop
  obuf = StringIO()
1759 e2e521d0 Iustin Pop
  msg = str(err)
1760 73702ee7 Iustin Pop
  if isinstance(err, errors.ConfigurationError):
1761 e2e521d0 Iustin Pop
    txt = "Corrupt configuration file: %s" % msg
1762 46fbdd04 Iustin Pop
    logging.error(txt)
1763 e2e521d0 Iustin Pop
    obuf.write(txt + "\n")
1764 73702ee7 Iustin Pop
    obuf.write("Aborting.")
1765 73702ee7 Iustin Pop
    retcode = 2
1766 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksAbort):
1767 73702ee7 Iustin Pop
    obuf.write("Failure: hooks execution failed:\n")
1768 73702ee7 Iustin Pop
    for node, script, out in err.args[0]:
1769 73702ee7 Iustin Pop
      if out:
1770 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s, output: %s\n" %
1771 73702ee7 Iustin Pop
                   (node, script, out))
1772 73702ee7 Iustin Pop
      else:
1773 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s (no output)\n" %
1774 73702ee7 Iustin Pop
                   (node, script))
1775 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksFailure):
1776 e2e521d0 Iustin Pop
    obuf.write("Failure: hooks general failure: %s" % msg)
1777 73702ee7 Iustin Pop
  elif isinstance(err, errors.ResolverError):
1778 b705c7a6 Manuel Franceschini
    this_host = netutils.Hostname.GetSysName()
1779 73702ee7 Iustin Pop
    if err.args[0] == this_host:
1780 73702ee7 Iustin Pop
      msg = "Failure: can't resolve my own hostname ('%s')"
1781 73702ee7 Iustin Pop
    else:
1782 73702ee7 Iustin Pop
      msg = "Failure: can't resolve hostname '%s'"
1783 73702ee7 Iustin Pop
    obuf.write(msg % err.args[0])
1784 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpPrereqError):
1785 5c983ee5 Iustin Pop
    if len(err.args) == 2:
1786 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
1787 5c983ee5 Iustin Pop
               " operation:\nerror type: %s, error details:\n%s" %
1788 5c983ee5 Iustin Pop
                 (err.args[1], err.args[0]))
1789 5c983ee5 Iustin Pop
    else:
1790 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
1791 5c983ee5 Iustin Pop
                 " operation:\n%s" % msg)
1792 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpExecError):
1793 e2e521d0 Iustin Pop
    obuf.write("Failure: command execution error:\n%s" % msg)
1794 73702ee7 Iustin Pop
  elif isinstance(err, errors.TagError):
1795 e2e521d0 Iustin Pop
    obuf.write("Failure: invalid tag(s) given:\n%s" % msg)
1796 686d7433 Iustin Pop
  elif isinstance(err, errors.JobQueueDrainError):
1797 686d7433 Iustin Pop
    obuf.write("Failure: the job queue is marked for drain and doesn't"
1798 686d7433 Iustin Pop
               " accept new requests\n")
1799 f87b405e Michael Hanselmann
  elif isinstance(err, errors.JobQueueFull):
1800 f87b405e Michael Hanselmann
    obuf.write("Failure: the job queue is full and doesn't accept new"
1801 f87b405e Michael Hanselmann
               " job submissions until old jobs are archived\n")
1802 a5728081 Guido Trotter
  elif isinstance(err, errors.TypeEnforcementError):
1803 a5728081 Guido Trotter
    obuf.write("Parameter Error: %s" % msg)
1804 c1ce76bb Iustin Pop
  elif isinstance(err, errors.ParameterError):
1805 c1ce76bb Iustin Pop
    obuf.write("Failure: unknown/wrong parameter name '%s'" % msg)
1806 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.NoMasterError):
1807 03a8dbdc Iustin Pop
    obuf.write("Cannot communicate with the master daemon.\nIs it running"
1808 082c5adb Michael Hanselmann
               " and listening for connections?")
1809 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.TimeoutError):
1810 03a8dbdc Iustin Pop
    obuf.write("Timeout while talking to the master daemon. Error:\n"
1811 03a8dbdc Iustin Pop
               "%s" % msg)
1812 5a1c22fe Iustin Pop
  elif isinstance(err, luxi.PermissionError):
1813 5a1c22fe Iustin Pop
    obuf.write("It seems you don't have permissions to connect to the"
1814 5a1c22fe Iustin Pop
               " master daemon.\nPlease retry as a different user.")
1815 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.ProtocolError):
1816 03a8dbdc Iustin Pop
    obuf.write("Unhandled protocol error while talking to the master daemon:\n"
1817 03a8dbdc Iustin Pop
               "%s" % msg)
1818 91c622a8 Iustin Pop
  elif isinstance(err, errors.JobLost):
1819 91c622a8 Iustin Pop
    obuf.write("Error checking job status: %s" % msg)
1820 797506fc Michael Hanselmann
  elif isinstance(err, errors.GenericError):
1821 797506fc Michael Hanselmann
    obuf.write("Unhandled Ganeti error: %s" % msg)
1822 e9d741b6 Iustin Pop
  elif isinstance(err, JobSubmittedException):
1823 e9d741b6 Iustin Pop
    obuf.write("JobID: %s\n" % err.args[0])
1824 e9d741b6 Iustin Pop
    retcode = 0
1825 73702ee7 Iustin Pop
  else:
1826 e2e521d0 Iustin Pop
    obuf.write("Unhandled exception: %s" % msg)
1827 73702ee7 Iustin Pop
  return retcode, obuf.getvalue().rstrip('\n')
1828 73702ee7 Iustin Pop
1829 73702ee7 Iustin Pop
1830 de47cf8f Guido Trotter
def GenericMain(commands, override=None, aliases=None):
1831 a8083063 Iustin Pop
  """Generic main function for all the gnt-* commands.
1832 a8083063 Iustin Pop

1833 334d1483 Iustin Pop
  Arguments:
1834 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
1835 334d1483 Iustin Pop
                for command line handling.
1836 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
1837 334d1483 Iustin Pop
                override command line options; this can be used to pass
1838 334d1483 Iustin Pop
                options from the scripts to generic functions
1839 de47cf8f Guido Trotter
    - aliases: dictionary with command aliases {'alias': 'target, ...}
1840 a8083063 Iustin Pop

1841 a8083063 Iustin Pop
  """
1842 a8083063 Iustin Pop
  # save the program name and the entire command line for later logging
1843 a8083063 Iustin Pop
  if sys.argv:
1844 a8083063 Iustin Pop
    binary = os.path.basename(sys.argv[0]) or sys.argv[0]
1845 a8083063 Iustin Pop
    if len(sys.argv) >= 2:
1846 a8083063 Iustin Pop
      binary += " " + sys.argv[1]
1847 a8083063 Iustin Pop
      old_cmdline = " ".join(sys.argv[2:])
1848 a8083063 Iustin Pop
    else:
1849 a8083063 Iustin Pop
      old_cmdline = ""
1850 a8083063 Iustin Pop
  else:
1851 a8083063 Iustin Pop
    binary = "<unknown program>"
1852 a8083063 Iustin Pop
    old_cmdline = ""
1853 a8083063 Iustin Pop
1854 de47cf8f Guido Trotter
  if aliases is None:
1855 de47cf8f Guido Trotter
    aliases = {}
1856 de47cf8f Guido Trotter
1857 3126878d Guido Trotter
  try:
1858 3126878d Guido Trotter
    func, options, args = _ParseArgs(sys.argv, commands, aliases)
1859 3126878d Guido Trotter
  except errors.ParameterError, err:
1860 3126878d Guido Trotter
    result, err_msg = FormatError(err)
1861 3126878d Guido Trotter
    ToStderr(err_msg)
1862 3126878d Guido Trotter
    return 1
1863 3126878d Guido Trotter
1864 a8083063 Iustin Pop
  if func is None: # parse error
1865 a8083063 Iustin Pop
    return 1
1866 a8083063 Iustin Pop
1867 334d1483 Iustin Pop
  if override is not None:
1868 334d1483 Iustin Pop
    for key, val in override.iteritems():
1869 334d1483 Iustin Pop
      setattr(options, key, val)
1870 334d1483 Iustin Pop
1871 82d9caef Iustin Pop
  utils.SetupLogging(constants.LOG_COMMANDS, debug=options.debug,
1872 82d9caef Iustin Pop
                     stderr_logging=True, program=binary)
1873 a8083063 Iustin Pop
1874 a8083063 Iustin Pop
  if old_cmdline:
1875 46fbdd04 Iustin Pop
    logging.info("run with arguments '%s'", old_cmdline)
1876 a8083063 Iustin Pop
  else:
1877 46fbdd04 Iustin Pop
    logging.info("run with no arguments")
1878 a8083063 Iustin Pop
1879 a8083063 Iustin Pop
  try:
1880 a4af651e Iustin Pop
    result = func(options, args)
1881 d8353c3a Iustin Pop
  except (errors.GenericError, luxi.ProtocolError,
1882 d8353c3a Iustin Pop
          JobSubmittedException), err:
1883 a4af651e Iustin Pop
    result, err_msg = FormatError(err)
1884 5bbd3f7f Michael Hanselmann
    logging.exception("Error during command processing")
1885 46fbdd04 Iustin Pop
    ToStderr(err_msg)
1886 a8083063 Iustin Pop
1887 a8083063 Iustin Pop
  return result
1888 137161c9 Michael Hanselmann
1889 137161c9 Michael Hanselmann
1890 845c79d8 Michael Hanselmann
def ParseNicOption(optvalue):
1891 845c79d8 Michael Hanselmann
  """Parses the value of the --net option(s).
1892 845c79d8 Michael Hanselmann

1893 845c79d8 Michael Hanselmann
  """
1894 845c79d8 Michael Hanselmann
  try:
1895 845c79d8 Michael Hanselmann
    nic_max = max(int(nidx[0]) + 1 for nidx in optvalue)
1896 845c79d8 Michael Hanselmann
  except (TypeError, ValueError), err:
1897 845c79d8 Michael Hanselmann
    raise errors.OpPrereqError("Invalid NIC index passed: %s" % str(err))
1898 845c79d8 Michael Hanselmann
1899 845c79d8 Michael Hanselmann
  nics = [{}] * nic_max
1900 845c79d8 Michael Hanselmann
  for nidx, ndict in optvalue:
1901 845c79d8 Michael Hanselmann
    nidx = int(nidx)
1902 845c79d8 Michael Hanselmann
1903 845c79d8 Michael Hanselmann
    if not isinstance(ndict, dict):
1904 845c79d8 Michael Hanselmann
      raise errors.OpPrereqError("Invalid nic/%d value: expected dict,"
1905 845c79d8 Michael Hanselmann
                                 " got %s" % (nidx, ndict))
1906 845c79d8 Michael Hanselmann
1907 845c79d8 Michael Hanselmann
    utils.ForceDictType(ndict, constants.INIC_PARAMS_TYPES)
1908 845c79d8 Michael Hanselmann
1909 845c79d8 Michael Hanselmann
    nics[nidx] = ndict
1910 845c79d8 Michael Hanselmann
1911 845c79d8 Michael Hanselmann
  return nics
1912 845c79d8 Michael Hanselmann
1913 845c79d8 Michael Hanselmann
1914 d77490c5 Iustin Pop
def GenericInstanceCreate(mode, opts, args):
1915 d77490c5 Iustin Pop
  """Add an instance to the cluster via either creation or import.
1916 d77490c5 Iustin Pop

1917 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
1918 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
1919 d77490c5 Iustin Pop
  @type args: list
1920 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
1921 d77490c5 Iustin Pop
  @rtype: int
1922 d77490c5 Iustin Pop
  @return: the desired exit code
1923 d77490c5 Iustin Pop

1924 d77490c5 Iustin Pop
  """
1925 d77490c5 Iustin Pop
  instance = args[0]
1926 d77490c5 Iustin Pop
1927 d77490c5 Iustin Pop
  (pnode, snode) = SplitNodeOption(opts.node)
1928 d77490c5 Iustin Pop
1929 d77490c5 Iustin Pop
  hypervisor = None
1930 d77490c5 Iustin Pop
  hvparams = {}
1931 d77490c5 Iustin Pop
  if opts.hypervisor:
1932 d77490c5 Iustin Pop
    hypervisor, hvparams = opts.hypervisor
1933 d77490c5 Iustin Pop
1934 d77490c5 Iustin Pop
  if opts.nics:
1935 845c79d8 Michael Hanselmann
    nics = ParseNicOption(opts.nics)
1936 d77490c5 Iustin Pop
  elif opts.no_nics:
1937 d77490c5 Iustin Pop
    # no nics
1938 d77490c5 Iustin Pop
    nics = []
1939 0af0f641 Iustin Pop
  elif mode == constants.INSTANCE_CREATE:
1940 d77490c5 Iustin Pop
    # default of one nic, all auto
1941 d77490c5 Iustin Pop
    nics = [{}]
1942 0af0f641 Iustin Pop
  else:
1943 0af0f641 Iustin Pop
    # mode == import
1944 0af0f641 Iustin Pop
    nics = []
1945 d77490c5 Iustin Pop
1946 d77490c5 Iustin Pop
  if opts.disk_template == constants.DT_DISKLESS:
1947 d77490c5 Iustin Pop
    if opts.disks or opts.sd_size is not None:
1948 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Diskless instance but disk"
1949 d77490c5 Iustin Pop
                                 " information passed")
1950 d77490c5 Iustin Pop
    disks = []
1951 d77490c5 Iustin Pop
  else:
1952 9b12ed0f Iustin Pop
    if (not opts.disks and not opts.sd_size
1953 9b12ed0f Iustin Pop
        and mode == constants.INSTANCE_CREATE):
1954 d77490c5 Iustin Pop
      raise errors.OpPrereqError("No disk information specified")
1955 d77490c5 Iustin Pop
    if opts.disks and opts.sd_size is not None:
1956 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Please use either the '--disk' or"
1957 d77490c5 Iustin Pop
                                 " '-s' option")
1958 d77490c5 Iustin Pop
    if opts.sd_size is not None:
1959 d77490c5 Iustin Pop
      opts.disks = [(0, {"size": opts.sd_size})]
1960 9b12ed0f Iustin Pop
1961 9b12ed0f Iustin Pop
    if opts.disks:
1962 9b12ed0f Iustin Pop
      try:
1963 9b12ed0f Iustin Pop
        disk_max = max(int(didx[0]) + 1 for didx in opts.disks)
1964 9b12ed0f Iustin Pop
      except ValueError, err:
1965 9b12ed0f Iustin Pop
        raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err))
1966 9b12ed0f Iustin Pop
      disks = [{}] * disk_max
1967 9b12ed0f Iustin Pop
    else:
1968 9b12ed0f Iustin Pop
      disks = []
1969 d77490c5 Iustin Pop
    for didx, ddict in opts.disks:
1970 d77490c5 Iustin Pop
      didx = int(didx)
1971 d77490c5 Iustin Pop
      if not isinstance(ddict, dict):
1972 d77490c5 Iustin Pop
        msg = "Invalid disk/%d value: expected dict, got %s" % (didx, ddict)
1973 d77490c5 Iustin Pop
        raise errors.OpPrereqError(msg)
1974 5029db65 Iustin Pop
      elif "size" in ddict:
1975 5029db65 Iustin Pop
        if "adopt" in ddict:
1976 5029db65 Iustin Pop
          raise errors.OpPrereqError("Only one of 'size' and 'adopt' allowed"
1977 5029db65 Iustin Pop
                                     " (disk %d)" % didx)
1978 5029db65 Iustin Pop
        try:
1979 5029db65 Iustin Pop
          ddict["size"] = utils.ParseUnit(ddict["size"])
1980 5029db65 Iustin Pop
        except ValueError, err:
1981 5029db65 Iustin Pop
          raise errors.OpPrereqError("Invalid disk size for disk %d: %s" %
1982 5029db65 Iustin Pop
                                     (didx, err))
1983 5029db65 Iustin Pop
      elif "adopt" in ddict:
1984 5029db65 Iustin Pop
        if mode == constants.INSTANCE_IMPORT:
1985 5029db65 Iustin Pop
          raise errors.OpPrereqError("Disk adoption not allowed for instance"
1986 5029db65 Iustin Pop
                                     " import")
1987 5029db65 Iustin Pop
        ddict["size"] = 0
1988 5029db65 Iustin Pop
      else:
1989 5029db65 Iustin Pop
        raise errors.OpPrereqError("Missing size or adoption source for"
1990 5029db65 Iustin Pop
                                   " disk %d" % didx)
1991 d77490c5 Iustin Pop
      disks[didx] = ddict
1992 d77490c5 Iustin Pop
1993 d77490c5 Iustin Pop
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_TYPES)
1994 d77490c5 Iustin Pop
  utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
1995 d77490c5 Iustin Pop
1996 d77490c5 Iustin Pop
  if mode == constants.INSTANCE_CREATE:
1997 d77490c5 Iustin Pop
    start = opts.start
1998 d77490c5 Iustin Pop
    os_type = opts.os
1999 1ee8e01a Guido Trotter
    force_variant = opts.force_variant
2000 d77490c5 Iustin Pop
    src_node = None
2001 d77490c5 Iustin Pop
    src_path = None
2002 25a8792c Iustin Pop
    no_install = opts.no_install
2003 e588764d Iustin Pop
    identify_defaults = False
2004 d77490c5 Iustin Pop
  elif mode == constants.INSTANCE_IMPORT:
2005 d77490c5 Iustin Pop
    start = False
2006 d77490c5 Iustin Pop
    os_type = None
2007 1ee8e01a Guido Trotter
    force_variant = False
2008 d77490c5 Iustin Pop
    src_node = opts.src_node
2009 d77490c5 Iustin Pop
    src_path = opts.src_dir
2010 25a8792c Iustin Pop
    no_install = None
2011 e588764d Iustin Pop
    identify_defaults = opts.identify_defaults
2012 d77490c5 Iustin Pop
  else:
2013 d77490c5 Iustin Pop
    raise errors.ProgrammerError("Invalid creation mode %s" % mode)
2014 d77490c5 Iustin Pop
2015 d77490c5 Iustin Pop
  op = opcodes.OpCreateInstance(instance_name=instance,
2016 d77490c5 Iustin Pop
                                disks=disks,
2017 d77490c5 Iustin Pop
                                disk_template=opts.disk_template,
2018 d77490c5 Iustin Pop
                                nics=nics,
2019 d77490c5 Iustin Pop
                                pnode=pnode, snode=snode,
2020 d77490c5 Iustin Pop
                                ip_check=opts.ip_check,
2021 460d22be Iustin Pop
                                name_check=opts.name_check,
2022 d77490c5 Iustin Pop
                                wait_for_sync=opts.wait_for_sync,
2023 d77490c5 Iustin Pop
                                file_storage_dir=opts.file_storage_dir,
2024 d77490c5 Iustin Pop
                                file_driver=opts.file_driver,
2025 d77490c5 Iustin Pop
                                iallocator=opts.iallocator,
2026 d77490c5 Iustin Pop
                                hypervisor=hypervisor,
2027 d77490c5 Iustin Pop
                                hvparams=hvparams,
2028 d77490c5 Iustin Pop
                                beparams=opts.beparams,
2029 062a7100 Iustin Pop
                                osparams=opts.osparams,
2030 d77490c5 Iustin Pop
                                mode=mode,
2031 d77490c5 Iustin Pop
                                start=start,
2032 d77490c5 Iustin Pop
                                os_type=os_type,
2033 1ee8e01a Guido Trotter
                                force_variant=force_variant,
2034 d77490c5 Iustin Pop
                                src_node=src_node,
2035 25a8792c Iustin Pop
                                src_path=src_path,
2036 e588764d Iustin Pop
                                no_install=no_install,
2037 e588764d Iustin Pop
                                identify_defaults=identify_defaults)
2038 d77490c5 Iustin Pop
2039 d77490c5 Iustin Pop
  SubmitOrSend(op, opts)
2040 d77490c5 Iustin Pop
  return 0
2041 d77490c5 Iustin Pop
2042 d77490c5 Iustin Pop
2043 7e49b6ce Michael Hanselmann
class _RunWhileClusterStoppedHelper:
2044 7e49b6ce Michael Hanselmann
  """Helper class for L{RunWhileClusterStopped} to simplify state management
2045 7e49b6ce Michael Hanselmann

2046 7e49b6ce Michael Hanselmann
  """
2047 7e49b6ce Michael Hanselmann
  def __init__(self, feedback_fn, cluster_name, master_node, online_nodes):
2048 7e49b6ce Michael Hanselmann
    """Initializes this class.
2049 7e49b6ce Michael Hanselmann

2050 7e49b6ce Michael Hanselmann
    @type feedback_fn: callable
2051 7e49b6ce Michael Hanselmann
    @param feedback_fn: Feedback function
2052 7e49b6ce Michael Hanselmann
    @type cluster_name: string
2053 7e49b6ce Michael Hanselmann
    @param cluster_name: Cluster name
2054 7e49b6ce Michael Hanselmann
    @type master_node: string
2055 7e49b6ce Michael Hanselmann
    @param master_node Master node name
2056 7e49b6ce Michael Hanselmann
    @type online_nodes: list
2057 7e49b6ce Michael Hanselmann
    @param online_nodes: List of names of online nodes
2058 7e49b6ce Michael Hanselmann

2059 7e49b6ce Michael Hanselmann
    """
2060 7e49b6ce Michael Hanselmann
    self.feedback_fn = feedback_fn
2061 7e49b6ce Michael Hanselmann
    self.cluster_name = cluster_name
2062 7e49b6ce Michael Hanselmann
    self.master_node = master_node
2063 7e49b6ce Michael Hanselmann
    self.online_nodes = online_nodes
2064 7e49b6ce Michael Hanselmann
2065 7e49b6ce Michael Hanselmann
    self.ssh = ssh.SshRunner(self.cluster_name)
2066 7e49b6ce Michael Hanselmann
2067 7e49b6ce Michael Hanselmann
    self.nonmaster_nodes = [name for name in online_nodes
2068 7e49b6ce Michael Hanselmann
                            if name != master_node]
2069 7e49b6ce Michael Hanselmann
2070 7e49b6ce Michael Hanselmann
    assert self.master_node not in self.nonmaster_nodes
2071 7e49b6ce Michael Hanselmann
2072 7e49b6ce Michael Hanselmann
  def _RunCmd(self, node_name, cmd):
2073 7e49b6ce Michael Hanselmann
    """Runs a command on the local or a remote machine.
2074 7e49b6ce Michael Hanselmann

2075 7e49b6ce Michael Hanselmann
    @type node_name: string
2076 7e49b6ce Michael Hanselmann
    @param node_name: Machine name
2077 7e49b6ce Michael Hanselmann
    @type cmd: list
2078 7e49b6ce Michael Hanselmann
    @param cmd: Command
2079 7e49b6ce Michael Hanselmann

2080 7e49b6ce Michael Hanselmann
    """
2081 7e49b6ce Michael Hanselmann
    if node_name is None or node_name == self.master_node:
2082 7e49b6ce Michael Hanselmann
      # No need to use SSH
2083 7e49b6ce Michael Hanselmann
      result = utils.RunCmd(cmd)
2084 7e49b6ce Michael Hanselmann
    else:
2085 7e49b6ce Michael Hanselmann
      result = self.ssh.Run(node_name, "root", utils.ShellQuoteArgs(cmd))
2086 7e49b6ce Michael Hanselmann
2087 7e49b6ce Michael Hanselmann
    if result.failed:
2088 7e49b6ce Michael Hanselmann
      errmsg = ["Failed to run command %s" % result.cmd]
2089 7e49b6ce Michael Hanselmann
      if node_name:
2090 7e49b6ce Michael Hanselmann
        errmsg.append("on node %s" % node_name)
2091 7e49b6ce Michael Hanselmann
      errmsg.append(": exitcode %s and error %s" %
2092 7e49b6ce Michael Hanselmann
                    (result.exit_code, result.output))
2093 7e49b6ce Michael Hanselmann
      raise errors.OpExecError(" ".join(errmsg))
2094 7e49b6ce Michael Hanselmann
2095 7e49b6ce Michael Hanselmann
  def Call(self, fn, *args):
2096 7e49b6ce Michael Hanselmann
    """Call function while all daemons are stopped.
2097 7e49b6ce Michael Hanselmann

2098 7e49b6ce Michael Hanselmann
    @type fn: callable
2099 7e49b6ce Michael Hanselmann
    @param fn: Function to be called
2100 7e49b6ce Michael Hanselmann

2101 7e49b6ce Michael Hanselmann
    """
2102 7e49b6ce Michael Hanselmann
    # Pause watcher by acquiring an exclusive lock on watcher state file
2103 7e49b6ce Michael Hanselmann
    self.feedback_fn("Blocking watcher")
2104 7e49b6ce Michael Hanselmann
    watcher_block = utils.FileLock.Open(constants.WATCHER_STATEFILE)
2105 7e49b6ce Michael Hanselmann
    try:
2106 7e49b6ce Michael Hanselmann
      # TODO: Currently, this just blocks. There's no timeout.
2107 7e49b6ce Michael Hanselmann
      # TODO: Should it be a shared lock?
2108 7e49b6ce Michael Hanselmann
      watcher_block.Exclusive(blocking=True)
2109 7e49b6ce Michael Hanselmann
2110 7e49b6ce Michael Hanselmann
      # Stop master daemons, so that no new jobs can come in and all running
2111 7e49b6ce Michael Hanselmann
      # ones are finished
2112 7e49b6ce Michael Hanselmann
      self.feedback_fn("Stopping master daemons")
2113 7e49b6ce Michael Hanselmann
      self._RunCmd(None, [constants.DAEMON_UTIL, "stop-master"])
2114 7e49b6ce Michael Hanselmann
      try:
2115 7e49b6ce Michael Hanselmann
        # Stop daemons on all nodes
2116 7e49b6ce Michael Hanselmann
        for node_name in self.online_nodes:
2117 7e49b6ce Michael Hanselmann
          self.feedback_fn("Stopping daemons on %s" % node_name)
2118 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "stop-all"])
2119 7e49b6ce Michael Hanselmann
2120 7e49b6ce Michael Hanselmann
        # All daemons are shut down now
2121 7e49b6ce Michael Hanselmann
        try:
2122 7e49b6ce Michael Hanselmann
          return fn(self, *args)
2123 d512e84b Michael Hanselmann
        except Exception, err:
2124 d512e84b Michael Hanselmann
          _, errmsg = FormatError(err)
2125 7e49b6ce Michael Hanselmann
          logging.exception("Caught exception")
2126 d512e84b Michael Hanselmann
          self.feedback_fn(errmsg)
2127 7e49b6ce Michael Hanselmann
          raise
2128 7e49b6ce Michael Hanselmann
      finally:
2129 7e49b6ce Michael Hanselmann
        # Start cluster again, master node last
2130 7e49b6ce Michael Hanselmann
        for node_name in self.nonmaster_nodes + [self.master_node]:
2131 7e49b6ce Michael Hanselmann
          self.feedback_fn("Starting daemons on %s" % node_name)
2132 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "start-all"])
2133 7e49b6ce Michael Hanselmann
    finally:
2134 7e49b6ce Michael Hanselmann
      # Resume watcher
2135 7e49b6ce Michael Hanselmann
      watcher_block.Close()
2136 7e49b6ce Michael Hanselmann
2137 7e49b6ce Michael Hanselmann
2138 7e49b6ce Michael Hanselmann
def RunWhileClusterStopped(feedback_fn, fn, *args):
2139 7e49b6ce Michael Hanselmann
  """Calls a function while all cluster daemons are stopped.
2140 7e49b6ce Michael Hanselmann

2141 7e49b6ce Michael Hanselmann
  @type feedback_fn: callable
2142 7e49b6ce Michael Hanselmann
  @param feedback_fn: Feedback function
2143 7e49b6ce Michael Hanselmann
  @type fn: callable
2144 7e49b6ce Michael Hanselmann
  @param fn: Function to be called when daemons are stopped
2145 7e49b6ce Michael Hanselmann

2146 7e49b6ce Michael Hanselmann
  """
2147 7e49b6ce Michael Hanselmann
  feedback_fn("Gathering cluster information")
2148 7e49b6ce Michael Hanselmann
2149 7e49b6ce Michael Hanselmann
  # This ensures we're running on the master daemon
2150 7e49b6ce Michael Hanselmann
  cl = GetClient()
2151 7e49b6ce Michael Hanselmann
2152 7e49b6ce Michael Hanselmann
  (cluster_name, master_node) = \
2153 7e49b6ce Michael Hanselmann
    cl.QueryConfigValues(["cluster_name", "master_node"])
2154 7e49b6ce Michael Hanselmann
2155 7e49b6ce Michael Hanselmann
  online_nodes = GetOnlineNodes([], cl=cl)
2156 7e49b6ce Michael Hanselmann
2157 7e49b6ce Michael Hanselmann
  # Don't keep a reference to the client. The master daemon will go away.
2158 7e49b6ce Michael Hanselmann
  del cl
2159 7e49b6ce Michael Hanselmann
2160 7e49b6ce Michael Hanselmann
  assert master_node in online_nodes
2161 7e49b6ce Michael Hanselmann
2162 7e49b6ce Michael Hanselmann
  return _RunWhileClusterStoppedHelper(feedback_fn, cluster_name, master_node,
2163 7e49b6ce Michael Hanselmann
                                       online_nodes).Call(fn, *args)
2164 7e49b6ce Michael Hanselmann
2165 7e49b6ce Michael Hanselmann
2166 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
2167 9fbfbb7b Iustin Pop
                  numfields=None, unitfields=None,
2168 9fbfbb7b Iustin Pop
                  units=None):
2169 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
2170 137161c9 Michael Hanselmann

2171 9fbfbb7b Iustin Pop
  @type headers: dict
2172 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
2173 9fbfbb7b Iustin Pop
      the table
2174 9fbfbb7b Iustin Pop
  @type fields: list
2175 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
2176 9fbfbb7b Iustin Pop
      the data field
2177 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
2178 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
2179 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
2180 9fbfbb7b Iustin Pop
      each field
2181 9fbfbb7b Iustin Pop
  @type data: list
2182 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
2183 9fbfbb7b Iustin Pop
  @type numfields: list
2184 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
2185 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
2186 9fbfbb7b Iustin Pop
  @type unitfields: list
2187 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
2188 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
2189 9fbfbb7b Iustin Pop
  @type units: string or None
2190 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
2191 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
2192 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
2193 137161c9 Michael Hanselmann

2194 137161c9 Michael Hanselmann
  """
2195 9fbfbb7b Iustin Pop
  if units is None:
2196 9fbfbb7b Iustin Pop
    if separator:
2197 9fbfbb7b Iustin Pop
      units = "m"
2198 9fbfbb7b Iustin Pop
    else:
2199 9fbfbb7b Iustin Pop
      units = "h"
2200 9fbfbb7b Iustin Pop
2201 137161c9 Michael Hanselmann
  if numfields is None:
2202 137161c9 Michael Hanselmann
    numfields = []
2203 137161c9 Michael Hanselmann
  if unitfields is None:
2204 137161c9 Michael Hanselmann
    unitfields = []
2205 137161c9 Michael Hanselmann
2206 fe267188 Iustin Pop
  numfields = utils.FieldSet(*numfields)   # pylint: disable-msg=W0142
2207 fe267188 Iustin Pop
  unitfields = utils.FieldSet(*unitfields) # pylint: disable-msg=W0142
2208 00430f8e Iustin Pop
2209 137161c9 Michael Hanselmann
  format_fields = []
2210 137161c9 Michael Hanselmann
  for field in fields:
2211 01ca31ae Iustin Pop
    if headers and field not in headers:
2212 ea5a5b74 Guido Trotter
      # TODO: handle better unknown fields (either revert to old
2213 71c1af58 Iustin Pop
      # style of raising exception, or deal more intelligently with
2214 71c1af58 Iustin Pop
      # variable fields)
2215 71c1af58 Iustin Pop
      headers[field] = field
2216 137161c9 Michael Hanselmann
    if separator is not None:
2217 137161c9 Michael Hanselmann
      format_fields.append("%s")
2218 00430f8e Iustin Pop
    elif numfields.Matches(field):
2219 137161c9 Michael Hanselmann
      format_fields.append("%*s")
2220 137161c9 Michael Hanselmann
    else:
2221 137161c9 Michael Hanselmann
      format_fields.append("%-*s")
2222 137161c9 Michael Hanselmann
2223 137161c9 Michael Hanselmann
  if separator is None:
2224 137161c9 Michael Hanselmann
    mlens = [0 for name in fields]
2225 c04bc777 Iustin Pop
    format_str = ' '.join(format_fields)
2226 137161c9 Michael Hanselmann
  else:
2227 c04bc777 Iustin Pop
    format_str = separator.replace("%", "%%").join(format_fields)
2228 137161c9 Michael Hanselmann
2229 137161c9 Michael Hanselmann
  for row in data:
2230 dcbd6288 Guido Trotter
    if row is None:
2231 dcbd6288 Guido Trotter
      continue
2232 137161c9 Michael Hanselmann
    for idx, val in enumerate(row):
2233 00430f8e Iustin Pop
      if unitfields.Matches(fields[idx]):
2234 137161c9 Michael Hanselmann
        try:
2235 137161c9 Michael Hanselmann
          val = int(val)
2236 691744c4 Iustin Pop
        except (TypeError, ValueError):
2237 137161c9 Michael Hanselmann
          pass
2238 137161c9 Michael Hanselmann
        else:
2239 9fbfbb7b Iustin Pop
          val = row[idx] = utils.FormatUnit(val, units)
2240 01ca31ae Iustin Pop
      val = row[idx] = str(val)
2241 137161c9 Michael Hanselmann
      if separator is None:
2242 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(val))
2243 137161c9 Michael Hanselmann
2244 16be8703 Iustin Pop
  result = []
2245 137161c9 Michael Hanselmann
  if headers:
2246 137161c9 Michael Hanselmann
    args = []
2247 137161c9 Michael Hanselmann
    for idx, name in enumerate(fields):
2248 137161c9 Michael Hanselmann
      hdr = headers[name]
2249 137161c9 Michael Hanselmann
      if separator is None:
2250 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(hdr))
2251 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2252 137161c9 Michael Hanselmann
      args.append(hdr)
2253 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2254 137161c9 Michael Hanselmann
2255 ec39d63c Michael Hanselmann
  if separator is None:
2256 ec39d63c Michael Hanselmann
    assert len(mlens) == len(fields)
2257 ec39d63c Michael Hanselmann
2258 ec39d63c Michael Hanselmann
    if fields and not numfields.Matches(fields[-1]):
2259 ec39d63c Michael Hanselmann
      mlens[-1] = 0
2260 ec39d63c Michael Hanselmann
2261 137161c9 Michael Hanselmann
  for line in data:
2262 137161c9 Michael Hanselmann
    args = []
2263 dcbd6288 Guido Trotter
    if line is None:
2264 dcbd6288 Guido Trotter
      line = ['-' for _ in fields]
2265 f1501b3f Michael Hanselmann
    for idx in range(len(fields)):
2266 137161c9 Michael Hanselmann
      if separator is None:
2267 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2268 137161c9 Michael Hanselmann
      args.append(line[idx])
2269 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2270 16be8703 Iustin Pop
2271 16be8703 Iustin Pop
  return result
2272 3386e7a9 Iustin Pop
2273 3386e7a9 Iustin Pop
2274 3386e7a9 Iustin Pop
def FormatTimestamp(ts):
2275 3386e7a9 Iustin Pop
  """Formats a given timestamp.
2276 3386e7a9 Iustin Pop

2277 3386e7a9 Iustin Pop
  @type ts: timestamp
2278 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
2279 3386e7a9 Iustin Pop

2280 3386e7a9 Iustin Pop
  @rtype: string
2281 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
2282 3386e7a9 Iustin Pop

2283 3386e7a9 Iustin Pop
  """
2284 e0ec0ff6 Iustin Pop
  if not isinstance (ts, (tuple, list)) or len(ts) != 2:
2285 e0ec0ff6 Iustin Pop
    return '?'
2286 3386e7a9 Iustin Pop
  sec, usec = ts
2287 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
2288 2241e2b9 Iustin Pop
2289 2241e2b9 Iustin Pop
2290 2241e2b9 Iustin Pop
def ParseTimespec(value):
2291 2241e2b9 Iustin Pop
  """Parse a time specification.
2292 2241e2b9 Iustin Pop

2293 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
2294 2241e2b9 Iustin Pop

2295 2241e2b9 Iustin Pop
    - s: seconds
2296 2241e2b9 Iustin Pop
    - m: minutes
2297 2241e2b9 Iustin Pop
    - h: hours
2298 2241e2b9 Iustin Pop
    - d: day
2299 2241e2b9 Iustin Pop
    - w: weeks
2300 2241e2b9 Iustin Pop

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

2303 2241e2b9 Iustin Pop
  """
2304 2241e2b9 Iustin Pop
  value = str(value)
2305 2241e2b9 Iustin Pop
  if not value:
2306 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
2307 2241e2b9 Iustin Pop
  suffix_map = {
2308 2241e2b9 Iustin Pop
    's': 1,
2309 2241e2b9 Iustin Pop
    'm': 60,
2310 2241e2b9 Iustin Pop
    'h': 3600,
2311 2241e2b9 Iustin Pop
    'd': 86400,
2312 2241e2b9 Iustin Pop
    'w': 604800,
2313 2241e2b9 Iustin Pop
    }
2314 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
2315 2241e2b9 Iustin Pop
    try:
2316 2241e2b9 Iustin Pop
      value = int(value)
2317 691744c4 Iustin Pop
    except (TypeError, ValueError):
2318 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2319 2241e2b9 Iustin Pop
  else:
2320 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
2321 2241e2b9 Iustin Pop
    value = value[:-1]
2322 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
2323 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
2324 2241e2b9 Iustin Pop
                                 " suffix passed)")
2325 2241e2b9 Iustin Pop
    try:
2326 2241e2b9 Iustin Pop
      value = int(value) * multiplier
2327 691744c4 Iustin Pop
    except (TypeError, ValueError):
2328 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2329 2241e2b9 Iustin Pop
  return value
2330 46fbdd04 Iustin Pop
2331 46fbdd04 Iustin Pop
2332 e9e26bb3 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False, secondary_ips=False,
2333 e9e26bb3 Iustin Pop
                   filter_master=False):
2334 4040a784 Iustin Pop
  """Returns the names of online nodes.
2335 4040a784 Iustin Pop

2336 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
2337 4040a784 Iustin Pop
  the online nodes.
2338 4040a784 Iustin Pop

2339 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
2340 4040a784 Iustin Pop
      offline ones)
2341 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
2342 4040a784 Iustin Pop
  @type nowarn: boolean
2343 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
2344 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
2345 4040a784 Iustin Pop
      note is not displayed
2346 e9e26bb3 Iustin Pop
  @type secondary_ips: boolean
2347 e9e26bb3 Iustin Pop
  @param secondary_ips: if True, return the secondary IPs instead of the
2348 e9e26bb3 Iustin Pop
      names, useful for doing network traffic over the replication interface
2349 e9e26bb3 Iustin Pop
      (if any)
2350 e9e26bb3 Iustin Pop
  @type filter_master: boolean
2351 e9e26bb3 Iustin Pop
  @param filter_master: if True, do not return the master node in the list
2352 e9e26bb3 Iustin Pop
      (useful in coordination with secondary_ips where we cannot check our
2353 e9e26bb3 Iustin Pop
      node name against the list)
2354 4040a784 Iustin Pop

2355 4040a784 Iustin Pop
  """
2356 4040a784 Iustin Pop
  if cl is None:
2357 4040a784 Iustin Pop
    cl = GetClient()
2358 4040a784 Iustin Pop
2359 e9e26bb3 Iustin Pop
  if secondary_ips:
2360 e9e26bb3 Iustin Pop
    name_idx = 2
2361 e9e26bb3 Iustin Pop
  else:
2362 e9e26bb3 Iustin Pop
    name_idx = 0
2363 e9e26bb3 Iustin Pop
2364 e9e26bb3 Iustin Pop
  if filter_master:
2365 e9e26bb3 Iustin Pop
    master_node = cl.QueryConfigValues(["master_node"])[0]
2366 e9e26bb3 Iustin Pop
    filter_fn = lambda x: x != master_node
2367 e9e26bb3 Iustin Pop
  else:
2368 e9e26bb3 Iustin Pop
    filter_fn = lambda _: True
2369 e9e26bb3 Iustin Pop
2370 e9e26bb3 Iustin Pop
  result = cl.QueryNodes(names=nodes, fields=["name", "offline", "sip"],
2371 2e7b8369 Iustin Pop
                         use_locking=False)
2372 4040a784 Iustin Pop
  offline = [row[0] for row in result if row[1]]
2373 4040a784 Iustin Pop
  if offline and not nowarn:
2374 1f864b60 Iustin Pop
    ToStderr("Note: skipping offline node(s): %s" % utils.CommaJoin(offline))
2375 e9e26bb3 Iustin Pop
  return [row[name_idx] for row in result if not row[1] and filter_fn(row[0])]
2376 4040a784 Iustin Pop
2377 4040a784 Iustin Pop
2378 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
2379 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
2380 46fbdd04 Iustin Pop

2381 46fbdd04 Iustin Pop
  @type stream: file object
2382 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
2383 46fbdd04 Iustin Pop
  @type txt: str
2384 46fbdd04 Iustin Pop
  @param txt: the message
2385 46fbdd04 Iustin Pop

2386 46fbdd04 Iustin Pop
  """
2387 46fbdd04 Iustin Pop
  if args:
2388 46fbdd04 Iustin Pop
    args = tuple(args)
2389 46fbdd04 Iustin Pop
    stream.write(txt % args)
2390 46fbdd04 Iustin Pop
  else:
2391 46fbdd04 Iustin Pop
    stream.write(txt)
2392 46fbdd04 Iustin Pop
  stream.write('\n')
2393 46fbdd04 Iustin Pop
  stream.flush()
2394 46fbdd04 Iustin Pop
2395 46fbdd04 Iustin Pop
2396 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
2397 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
2398 46fbdd04 Iustin Pop

2399 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2400 46fbdd04 Iustin Pop

2401 46fbdd04 Iustin Pop
  @type txt: str
2402 46fbdd04 Iustin Pop
  @param txt: the message
2403 46fbdd04 Iustin Pop

2404 46fbdd04 Iustin Pop
  """
2405 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
2406 46fbdd04 Iustin Pop
2407 46fbdd04 Iustin Pop
2408 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
2409 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
2410 46fbdd04 Iustin Pop

2411 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2412 46fbdd04 Iustin Pop

2413 46fbdd04 Iustin Pop
  @type txt: str
2414 46fbdd04 Iustin Pop
  @param txt: the message
2415 46fbdd04 Iustin Pop

2416 46fbdd04 Iustin Pop
  """
2417 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
2418 479636a3 Iustin Pop
2419 479636a3 Iustin Pop
2420 479636a3 Iustin Pop
class JobExecutor(object):
2421 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
2422 479636a3 Iustin Pop

2423 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
2424 479636a3 Iustin Pop
  GetResults() calls.
2425 479636a3 Iustin Pop

2426 479636a3 Iustin Pop
  """
2427 919ca415 Iustin Pop
  def __init__(self, cl=None, verbose=True, opts=None, feedback_fn=None):
2428 479636a3 Iustin Pop
    self.queue = []
2429 479636a3 Iustin Pop
    if cl is None:
2430 479636a3 Iustin Pop
      cl = GetClient()
2431 479636a3 Iustin Pop
    self.cl = cl
2432 479636a3 Iustin Pop
    self.verbose = verbose
2433 23b4b983 Iustin Pop
    self.jobs = []
2434 cff5fa7f Iustin Pop
    self.opts = opts
2435 919ca415 Iustin Pop
    self.feedback_fn = feedback_fn
2436 479636a3 Iustin Pop
2437 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
2438 23b4b983 Iustin Pop
    """Record a job for later submit.
2439 479636a3 Iustin Pop

2440 479636a3 Iustin Pop
    @type name: string
2441 479636a3 Iustin Pop
    @param name: a description of the job, will be used in WaitJobSet
2442 479636a3 Iustin Pop
    """
2443 cff5fa7f Iustin Pop
    SetGenericOpcodeOpts(ops, self.opts)
2444 23b4b983 Iustin Pop
    self.queue.append((name, ops))
2445 23b4b983 Iustin Pop
2446 66ecc479 Guido Trotter
  def SubmitPending(self, each=False):
2447 23b4b983 Iustin Pop
    """Submit all pending jobs.
2448 23b4b983 Iustin Pop

2449 23b4b983 Iustin Pop
    """
2450 66ecc479 Guido Trotter
    if each:
2451 66ecc479 Guido Trotter
      results = []
2452 66ecc479 Guido Trotter
      for row in self.queue:
2453 66ecc479 Guido Trotter
        # SubmitJob will remove the success status, but raise an exception if
2454 66ecc479 Guido Trotter
        # the submission fails, so we'll notice that anyway.
2455 66ecc479 Guido Trotter
        results.append([True, self.cl.SubmitJob(row[1])])
2456 66ecc479 Guido Trotter
    else:
2457 66ecc479 Guido Trotter
      results = self.cl.SubmitManyJobs([row[1] for row in self.queue])
2458 5299e61f Iustin Pop
    for (idx, ((status, data), (name, _))) in enumerate(zip(results,
2459 5299e61f Iustin Pop
                                                            self.queue)):
2460 5299e61f Iustin Pop
      self.jobs.append((idx, status, data, name))
2461 5299e61f Iustin Pop
2462 5299e61f Iustin Pop
  def _ChooseJob(self):
2463 5299e61f Iustin Pop
    """Choose a non-waiting/queued job to poll next.
2464 5299e61f Iustin Pop

2465 5299e61f Iustin Pop
    """
2466 5299e61f Iustin Pop
    assert self.jobs, "_ChooseJob called with empty job list"
2467 5299e61f Iustin Pop
2468 5299e61f Iustin Pop
    result = self.cl.QueryJobs([i[2] for i in self.jobs], ["status"])
2469 5299e61f Iustin Pop
    assert result
2470 5299e61f Iustin Pop
2471 5299e61f Iustin Pop
    for job_data, status in zip(self.jobs, result):
2472 91c622a8 Iustin Pop
      if (isinstance(status, list) and status and
2473 91c622a8 Iustin Pop
          status[0] in (constants.JOB_STATUS_QUEUED,
2474 91c622a8 Iustin Pop
                        constants.JOB_STATUS_WAITLOCK,
2475 91c622a8 Iustin Pop
                        constants.JOB_STATUS_CANCELING)):
2476 91c622a8 Iustin Pop
        # job is still present and waiting
2477 5299e61f Iustin Pop
        continue
2478 91c622a8 Iustin Pop
      # good candidate found (either running job or lost job)
2479 5299e61f Iustin Pop
      self.jobs.remove(job_data)
2480 5299e61f Iustin Pop
      return job_data
2481 5299e61f Iustin Pop
2482 5299e61f Iustin Pop
    # no job found
2483 5299e61f Iustin Pop
    return self.jobs.pop(0)
2484 479636a3 Iustin Pop
2485 479636a3 Iustin Pop
  def GetResults(self):
2486 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
2487 479636a3 Iustin Pop

2488 479636a3 Iustin Pop
    @rtype: list
2489 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
2490 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
2491 479636a3 Iustin Pop
        there will be the error message
2492 479636a3 Iustin Pop

2493 479636a3 Iustin Pop
    """
2494 23b4b983 Iustin Pop
    if not self.jobs:
2495 23b4b983 Iustin Pop
      self.SubmitPending()
2496 479636a3 Iustin Pop
    results = []
2497 479636a3 Iustin Pop
    if self.verbose:
2498 5299e61f Iustin Pop
      ok_jobs = [row[2] for row in self.jobs if row[1]]
2499 23b4b983 Iustin Pop
      if ok_jobs:
2500 1f864b60 Iustin Pop
        ToStdout("Submitted jobs %s", utils.CommaJoin(ok_jobs))
2501 5299e61f Iustin Pop
2502 5299e61f Iustin Pop
    # first, remove any non-submitted jobs
2503 cea881e5 Michael Hanselmann
    self.jobs, failures = compat.partition(self.jobs, lambda x: x[1])
2504 5299e61f Iustin Pop
    for idx, _, jid, name in failures:
2505 c63355f2 Iustin Pop
      ToStderr("Failed to submit job for %s: %s", name, jid)
2506 c63355f2 Iustin Pop
      results.append((idx, False, jid))
2507 5299e61f Iustin Pop
2508 5299e61f Iustin Pop
    while self.jobs:
2509 5299e61f Iustin Pop
      (idx, _, jid, name) = self._ChooseJob()
2510 5299e61f Iustin Pop
      ToStdout("Waiting for job %s for %s...", jid, name)
2511 479636a3 Iustin Pop
      try:
2512 919ca415 Iustin Pop
        job_result = PollJob(jid, cl=self.cl, feedback_fn=self.feedback_fn)
2513 479636a3 Iustin Pop
        success = True
2514 91c622a8 Iustin Pop
      except errors.JobLost, err:
2515 91c622a8 Iustin Pop
        _, job_result = FormatError(err)
2516 91c622a8 Iustin Pop
        ToStderr("Job %s for %s has been archived, cannot check its result",
2517 91c622a8 Iustin Pop
                 jid, name)
2518 91c622a8 Iustin Pop
        success = False
2519 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
2520 479636a3 Iustin Pop
        _, job_result = FormatError(err)
2521 479636a3 Iustin Pop
        success = False
2522 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
2523 479636a3 Iustin Pop
        ToStderr("Job %s for %s has failed: %s", jid, name, job_result)
2524 479636a3 Iustin Pop
2525 5299e61f Iustin Pop
      results.append((idx, success, job_result))
2526 5299e61f Iustin Pop
2527 5299e61f Iustin Pop
    # sort based on the index, then drop it
2528 5299e61f Iustin Pop
    results.sort()
2529 5299e61f Iustin Pop
    results = [i[1:] for i in results]
2530 5299e61f Iustin Pop
2531 479636a3 Iustin Pop
    return results
2532 479636a3 Iustin Pop
2533 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
2534 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
2535 479636a3 Iustin Pop

2536 479636a3 Iustin Pop
    @type wait: boolean
2537 479636a3 Iustin Pop
    @param wait: whether to wait or not
2538 479636a3 Iustin Pop

2539 479636a3 Iustin Pop
    """
2540 479636a3 Iustin Pop
    if wait:
2541 479636a3 Iustin Pop
      return self.GetResults()
2542 479636a3 Iustin Pop
    else:
2543 23b4b983 Iustin Pop
      if not self.jobs:
2544 23b4b983 Iustin Pop
        self.SubmitPending()
2545 71834b2a Guido Trotter
      for _, status, result, name in self.jobs:
2546 23b4b983 Iustin Pop
        if status:
2547 23b4b983 Iustin Pop
          ToStdout("%s: %s", result, name)
2548 23b4b983 Iustin Pop
        else:
2549 23b4b983 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)
2550 53a8a54d Iustin Pop
      return [row[1:3] for row in self.jobs]