Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ 377972f4

History | View | Annotate | Download (95 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 18009c1e Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 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 ee3aedff Michael Hanselmann
from ganeti import qlang
43 a8083063 Iustin Pop
44 c38c44ad Michael Hanselmann
from optparse import (OptionParser, TitledHelpFormatter,
45 38206f3c Iustin Pop
                      Option, OptionValueError)
46 a8083063 Iustin Pop
47 03298ebe Michael Hanselmann
48 4abc4f1e Iustin Pop
__all__ = [
49 4abc4f1e Iustin Pop
  # Command line options
50 fdad8c4d Balazs Lecz
  "ADD_UIDS_OPT",
51 e7e09483 Iustin Pop
  "ALLOCATABLE_OPT",
52 90e99856 Adeodato Simo
  "ALLOC_POLICY_OPT",
53 2d5e7ae1 Iustin Pop
  "ALL_OPT",
54 4c61d894 Iustin Pop
  "AUTO_PROMOTE_OPT",
55 e00f7a05 Iustin Pop
  "AUTO_REPLACE_OPT",
56 087ed2ed Iustin Pop
  "BACKEND_OPT",
57 61a14bb3 Iustin Pop
  "BLK_OS_OPT",
58 f91e255a Iustin Pop
  "CAPAB_MASTER_OPT",
59 53919782 Iustin Pop
  "CAPAB_VM_OPT",
60 baef337d Iustin Pop
  "CLEANUP_OPT",
61 3db3eb2a Michael Hanselmann
  "CLUSTER_DOMAIN_SECRET_OPT",
62 4abc4f1e Iustin Pop
  "CONFIRM_OPT",
63 e32df528 Iustin Pop
  "CP_SIZE_OPT",
64 4abc4f1e Iustin Pop
  "DEBUG_OPT",
65 a0c9776a Iustin Pop
  "DEBUG_SIMERR_OPT",
66 4b038a1e Iustin Pop
  "DISKIDX_OPT",
67 e3876ccb Iustin Pop
  "DISK_OPT",
68 4b038a1e Iustin Pop
  "DISK_TEMPLATE_OPT",
69 771734c9 Iustin Pop
  "DRAINED_OPT",
70 a0a6ff34 Iustin Pop
  "DRY_RUN_OPT",
71 26591bfd Luca Bigliardi
  "DRBD_HELPER_OPT",
72 7ea7bcf6 Iustin Pop
  "EARLY_RELEASE_OPT",
73 383a3591 Iustin Pop
  "ENABLED_HV_OPT",
74 14e9e7f3 Iustin Pop
  "ERROR_CODES_OPT",
75 4abc4f1e Iustin Pop
  "FIELDS_OPT",
76 4a25828c Iustin Pop
  "FILESTORE_DIR_OPT",
77 0f87c43e Iustin Pop
  "FILESTORE_DRIVER_OPT",
78 06073e85 Guido Trotter
  "FORCE_OPT",
79 06073e85 Guido Trotter
  "FORCE_VARIANT_OPT",
80 29392516 Iustin Pop
  "GLOBAL_FILEDIR_OPT",
81 61a14bb3 Iustin Pop
  "HID_OS_OPT",
82 073271f6 Iustin Pop
  "HVLIST_OPT",
83 48f212d7 Iustin Pop
  "HVOPTS_OPT",
84 236fd9c4 Iustin Pop
  "HYPERVISOR_OPT",
85 4eb62659 Iustin Pop
  "IALLOCATOR_OPT",
86 bf4af505 Apollon Oikonomopoulos
  "DEFAULT_IALLOCATOR_OPT",
87 e588764d Iustin Pop
  "IDENTIFY_DEFAULTS_OPT",
88 82a786d5 Iustin Pop
  "IGNORE_CONSIST_OPT",
89 b6e841a8 Iustin Pop
  "IGNORE_FAILURES_OPT",
90 b44bd844 Michael Hanselmann
  "IGNORE_OFFLINE_OPT",
91 8d8d650c Michael Hanselmann
  "IGNORE_REMOVE_FAILURES_OPT",
92 ee3f9578 Iustin Pop
  "IGNORE_SECONDARIES_OPT",
93 05586c90 Iustin Pop
  "IGNORE_SIZE_OPT",
94 19b9ba9a Michael Hanselmann
  "INTERVAL_OPT",
95 e3646f22 Iustin Pop
  "MAC_PREFIX_OPT",
96 3953242f Iustin Pop
  "MAINTAIN_NODE_HEALTH_OPT",
97 29392516 Iustin Pop
  "MASTER_NETDEV_OPT",
98 771734c9 Iustin Pop
  "MC_OPT",
99 783a6c0b Iustin Pop
  "MIGRATION_MODE_OPT",
100 7d3a9fab Iustin Pop
  "NET_OPT",
101 6d4a1656 Michael Hanselmann
  "NEW_CLUSTER_CERT_OPT",
102 3db3eb2a Michael Hanselmann
  "NEW_CLUSTER_DOMAIN_SECRET_OPT",
103 6b7d5878 Michael Hanselmann
  "NEW_CONFD_HMAC_KEY_OPT",
104 6d4a1656 Michael Hanselmann
  "NEW_RAPI_CERT_OPT",
105 a14db5ff Iustin Pop
  "NEW_SECONDARY_OPT",
106 4fbc93dd Iustin Pop
  "NIC_PARAMS_OPT",
107 61413377 Stephen Shirley
  "NODE_FORCE_JOIN_OPT",
108 7edc4637 Iustin Pop
  "NODE_LIST_OPT",
109 990b7886 Iustin Pop
  "NODE_PLACEMENT_OPT",
110 5fbbd028 Guido Trotter
  "NODEGROUP_OPT",
111 a535cef7 René Nussbaumer
  "NODE_PARAMS_OPT",
112 dd94e9f6 René Nussbaumer
  "NODE_POWERED_OPT",
113 26591bfd Luca Bigliardi
  "NODRBD_STORAGE_OPT",
114 4abc4f1e Iustin Pop
  "NOHDR_OPT",
115 91e0748c Iustin Pop
  "NOIPCHECK_OPT",
116 25a8792c Iustin Pop
  "NO_INSTALL_OPT",
117 460d22be Iustin Pop
  "NONAMECHECK_OPT",
118 831040bf Iustin Pop
  "NOLVM_STORAGE_OPT",
119 29392516 Iustin Pop
  "NOMODIFY_ETCHOSTS_OPT",
120 b989b9d9 Ken Wehr
  "NOMODIFY_SSH_SETUP_OPT",
121 26023ecd Iustin Pop
  "NONICS_OPT",
122 f2a0828c Iustin Pop
  "NONLIVE_OPT",
123 14e9e7f3 Iustin Pop
  "NONPLUS1_OPT",
124 44c44832 Iustin Pop
  "NOSHUTDOWN_OPT",
125 edeb878a Iustin Pop
  "NOSTART_OPT",
126 fcdde7f2 Iustin Pop
  "NOSSH_KEYCHECK_OPT",
127 58371861 Iustin Pop
  "NOVOTING_OPT",
128 3f75b4f3 Iustin Pop
  "NWSYNC_OPT",
129 a72d0a79 Iustin Pop
  "ON_PRIMARY_OPT",
130 feb09e6a Iustin Pop
  "ON_SECONDARY_OPT",
131 771734c9 Iustin Pop
  "OFFLINE_OPT",
132 062a7100 Iustin Pop
  "OSPARAMS_OPT",
133 d3ed23ff Iustin Pop
  "OS_OPT",
134 ff00c1a7 Iustin Pop
  "OS_SIZE_OPT",
135 b883637f René Nussbaumer
  "PREALLOC_WIPE_DISKS_OPT",
136 e7323b5e Manuel Franceschini
  "PRIMARY_IP_VERSION_OPT",
137 84a5b33c Michael Hanselmann
  "PRIORITY_OPT",
138 6d4a1656 Michael Hanselmann
  "RAPI_CERT_OPT",
139 b8d0f938 Iustin Pop
  "READD_OPT",
140 12054861 Iustin Pop
  "REBOOT_TYPE_OPT",
141 8d8d650c Michael Hanselmann
  "REMOVE_INSTANCE_OPT",
142 fdad8c4d Balazs Lecz
  "REMOVE_UIDS_OPT",
143 f38ea602 Iustin Pop
  "RESERVED_LVS_OPT",
144 31d97b2a Guido Trotter
  "ROMAN_OPT",
145 8d823629 Iustin Pop
  "SECONDARY_IP_OPT",
146 67840b40 Iustin Pop
  "SELECT_OS_OPT",
147 4abc4f1e Iustin Pop
  "SEP_OPT",
148 fdcf4d84 Iustin Pop
  "SHOWCMD_OPT",
149 7e5eaaa8 Guido Trotter
  "SHUTDOWN_TIMEOUT_OPT",
150 f36d7d81 Iustin Pop
  "SINGLE_NODE_OPT",
151 df62e5db Iustin Pop
  "SRC_DIR_OPT",
152 df62e5db Iustin Pop
  "SRC_NODE_OPT",
153 4abc4f1e Iustin Pop
  "SUBMIT_OPT",
154 99a8c799 Iustin Pop
  "STATIC_OPT",
155 4abc4f1e Iustin Pop
  "SYNC_OPT",
156 4abc4f1e Iustin Pop
  "TAG_SRC_OPT",
157 b5762e2a Guido Trotter
  "TIMEOUT_OPT",
158 1338f2b4 Balazs Lecz
  "UIDPOOL_OPT",
159 4abc4f1e Iustin Pop
  "USEUNITS_OPT",
160 74adc100 Iustin Pop
  "USE_REPL_NET_OPT",
161 9cdb9578 Iustin Pop
  "VERBOSE_OPT",
162 b58726e8 Iustin Pop
  "VG_NAME_OPT",
163 1f587d3d Iustin Pop
  "YES_DOIT_OPT",
164 4abc4f1e Iustin Pop
  # Generic functions for CLI programs
165 4abc4f1e Iustin Pop
  "GenericMain",
166 d77490c5 Iustin Pop
  "GenericInstanceCreate",
167 ee3aedff Michael Hanselmann
  "GenericList",
168 ee3aedff Michael Hanselmann
  "GenericListFields",
169 4abc4f1e Iustin Pop
  "GetClient",
170 4abc4f1e Iustin Pop
  "GetOnlineNodes",
171 4abc4f1e Iustin Pop
  "JobExecutor",
172 4abc4f1e Iustin Pop
  "JobSubmittedException",
173 4abc4f1e Iustin Pop
  "ParseTimespec",
174 7e49b6ce Michael Hanselmann
  "RunWhileClusterStopped",
175 4abc4f1e Iustin Pop
  "SubmitOpCode",
176 4abc4f1e Iustin Pop
  "SubmitOrSend",
177 4abc4f1e Iustin Pop
  "UsesRPC",
178 4abc4f1e Iustin Pop
  # Formatting functions
179 4abc4f1e Iustin Pop
  "ToStderr", "ToStdout",
180 4abc4f1e Iustin Pop
  "FormatError",
181 ee3aedff Michael Hanselmann
  "FormatQueryResult",
182 acd19189 René Nussbaumer
  "FormatParameterDict",
183 4abc4f1e Iustin Pop
  "GenerateTable",
184 4abc4f1e Iustin Pop
  "AskUser",
185 4abc4f1e Iustin Pop
  "FormatTimestamp",
186 8a7f1c61 Michael Hanselmann
  "FormatLogMessage",
187 4abc4f1e Iustin Pop
  # Tags functions
188 4abc4f1e Iustin Pop
  "ListTags",
189 4abc4f1e Iustin Pop
  "AddTags",
190 4abc4f1e Iustin Pop
  "RemoveTags",
191 4abc4f1e Iustin Pop
  # command line options support infrastructure
192 4abc4f1e Iustin Pop
  "ARGS_MANY_INSTANCES",
193 4abc4f1e Iustin Pop
  "ARGS_MANY_NODES",
194 667dbd6b Adeodato Simo
  "ARGS_MANY_GROUPS",
195 4abc4f1e Iustin Pop
  "ARGS_NONE",
196 4abc4f1e Iustin Pop
  "ARGS_ONE_INSTANCE",
197 4abc4f1e Iustin Pop
  "ARGS_ONE_NODE",
198 667dbd6b Adeodato Simo
  "ARGS_ONE_GROUP",
199 f9faf9c3 René Nussbaumer
  "ARGS_ONE_OS",
200 4abc4f1e Iustin Pop
  "ArgChoice",
201 4abc4f1e Iustin Pop
  "ArgCommand",
202 4abc4f1e Iustin Pop
  "ArgFile",
203 667dbd6b Adeodato Simo
  "ArgGroup",
204 4abc4f1e Iustin Pop
  "ArgHost",
205 4abc4f1e Iustin Pop
  "ArgInstance",
206 4abc4f1e Iustin Pop
  "ArgJobId",
207 4abc4f1e Iustin Pop
  "ArgNode",
208 f9faf9c3 René Nussbaumer
  "ArgOs",
209 4abc4f1e Iustin Pop
  "ArgSuggest",
210 4abc4f1e Iustin Pop
  "ArgUnknown",
211 4abc4f1e Iustin Pop
  "OPT_COMPL_INST_ADD_NODES",
212 4abc4f1e Iustin Pop
  "OPT_COMPL_MANY_NODES",
213 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_IALLOCATOR",
214 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_INSTANCE",
215 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_NODE",
216 36e247e1 Guido Trotter
  "OPT_COMPL_ONE_NODEGROUP",
217 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_OS",
218 4abc4f1e Iustin Pop
  "cli_option",
219 4abc4f1e Iustin Pop
  "SplitNodeOption",
220 07150497 Guido Trotter
  "CalculateOSNames",
221 a4ebd726 Michael Hanselmann
  "ParseFields",
222 eb28ecf6 Guido Trotter
  "COMMON_CREATE_OPTS",
223 4abc4f1e Iustin Pop
  ]
224 846baef9 Iustin Pop
225 8b46606c Guido Trotter
NO_PREFIX = "no_"
226 8b46606c Guido Trotter
UN_PREFIX = "-"
227 846baef9 Iustin Pop
228 84a5b33c Michael Hanselmann
#: Priorities (sorted)
229 84a5b33c Michael Hanselmann
_PRIORITY_NAMES = [
230 84a5b33c Michael Hanselmann
  ("low", constants.OP_PRIO_LOW),
231 84a5b33c Michael Hanselmann
  ("normal", constants.OP_PRIO_NORMAL),
232 84a5b33c Michael Hanselmann
  ("high", constants.OP_PRIO_HIGH),
233 84a5b33c Michael Hanselmann
  ]
234 84a5b33c Michael Hanselmann
235 84a5b33c Michael Hanselmann
#: Priority dictionary for easier lookup
236 84a5b33c Michael Hanselmann
# TODO: Replace this and _PRIORITY_NAMES with a single sorted dictionary once
237 84a5b33c Michael Hanselmann
# we migrate to Python 2.6
238 84a5b33c Michael Hanselmann
_PRIONAME_TO_VALUE = dict(_PRIORITY_NAMES)
239 84a5b33c Michael Hanselmann
240 ee3aedff Michael Hanselmann
# Query result status for clients
241 ee3aedff Michael Hanselmann
(QR_NORMAL,
242 ee3aedff Michael Hanselmann
 QR_UNKNOWN,
243 ee3aedff Michael Hanselmann
 QR_INCOMPLETE) = range(3)
244 ee3aedff Michael Hanselmann
245 03298ebe Michael Hanselmann
246 863d7f46 Michael Hanselmann
class _Argument:
247 7260cfbe Iustin Pop
  def __init__(self, min=0, max=None): # pylint: disable-msg=W0622
248 863d7f46 Michael Hanselmann
    self.min = min
249 863d7f46 Michael Hanselmann
    self.max = max
250 863d7f46 Michael Hanselmann
251 863d7f46 Michael Hanselmann
  def __repr__(self):
252 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s>" %
253 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max))
254 863d7f46 Michael Hanselmann
255 863d7f46 Michael Hanselmann
256 863d7f46 Michael Hanselmann
class ArgSuggest(_Argument):
257 863d7f46 Michael Hanselmann
  """Suggesting argument.
258 863d7f46 Michael Hanselmann

259 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor.
260 863d7f46 Michael Hanselmann

261 863d7f46 Michael Hanselmann
  """
262 7260cfbe Iustin Pop
  # pylint: disable-msg=W0622
263 863d7f46 Michael Hanselmann
  def __init__(self, min=0, max=None, choices=None):
264 863d7f46 Michael Hanselmann
    _Argument.__init__(self, min=min, max=max)
265 863d7f46 Michael Hanselmann
    self.choices = choices
266 863d7f46 Michael Hanselmann
267 863d7f46 Michael Hanselmann
  def __repr__(self):
268 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s choices=%r>" %
269 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max, self.choices))
270 863d7f46 Michael Hanselmann
271 863d7f46 Michael Hanselmann
272 863d7f46 Michael Hanselmann
class ArgChoice(ArgSuggest):
273 863d7f46 Michael Hanselmann
  """Choice argument.
274 863d7f46 Michael Hanselmann

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

278 863d7f46 Michael Hanselmann
  """
279 863d7f46 Michael Hanselmann
280 863d7f46 Michael Hanselmann
281 863d7f46 Michael Hanselmann
class ArgUnknown(_Argument):
282 863d7f46 Michael Hanselmann
  """Unknown argument to program (e.g. determined at runtime).
283 863d7f46 Michael Hanselmann

284 863d7f46 Michael Hanselmann
  """
285 863d7f46 Michael Hanselmann
286 863d7f46 Michael Hanselmann
287 863d7f46 Michael Hanselmann
class ArgInstance(_Argument):
288 863d7f46 Michael Hanselmann
  """Instances argument.
289 863d7f46 Michael Hanselmann

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

296 863d7f46 Michael Hanselmann
  """
297 863d7f46 Michael Hanselmann
298 667dbd6b Adeodato Simo
299 667dbd6b Adeodato Simo
class ArgGroup(_Argument):
300 667dbd6b Adeodato Simo
  """Node group argument.
301 667dbd6b Adeodato Simo

302 667dbd6b Adeodato Simo
  """
303 667dbd6b Adeodato Simo
304 667dbd6b Adeodato Simo
305 863d7f46 Michael Hanselmann
class ArgJobId(_Argument):
306 863d7f46 Michael Hanselmann
  """Job ID argument.
307 863d7f46 Michael Hanselmann

308 863d7f46 Michael Hanselmann
  """
309 863d7f46 Michael Hanselmann
310 863d7f46 Michael Hanselmann
311 863d7f46 Michael Hanselmann
class ArgFile(_Argument):
312 863d7f46 Michael Hanselmann
  """File path argument.
313 863d7f46 Michael Hanselmann

314 863d7f46 Michael Hanselmann
  """
315 863d7f46 Michael Hanselmann
316 863d7f46 Michael Hanselmann
317 863d7f46 Michael Hanselmann
class ArgCommand(_Argument):
318 863d7f46 Michael Hanselmann
  """Command argument.
319 863d7f46 Michael Hanselmann

320 863d7f46 Michael Hanselmann
  """
321 863d7f46 Michael Hanselmann
322 863d7f46 Michael Hanselmann
323 83ec7961 Michael Hanselmann
class ArgHost(_Argument):
324 83ec7961 Michael Hanselmann
  """Host argument.
325 83ec7961 Michael Hanselmann

326 83ec7961 Michael Hanselmann
  """
327 83ec7961 Michael Hanselmann
328 83ec7961 Michael Hanselmann
329 f9faf9c3 René Nussbaumer
class ArgOs(_Argument):
330 f9faf9c3 René Nussbaumer
  """OS argument.
331 f9faf9c3 René Nussbaumer

332 f9faf9c3 René Nussbaumer
  """
333 f9faf9c3 René Nussbaumer
334 f9faf9c3 René Nussbaumer
335 4a265c08 Michael Hanselmann
ARGS_NONE = []
336 4a265c08 Michael Hanselmann
ARGS_MANY_INSTANCES = [ArgInstance()]
337 4a265c08 Michael Hanselmann
ARGS_MANY_NODES = [ArgNode()]
338 667dbd6b Adeodato Simo
ARGS_MANY_GROUPS = [ArgGroup()]
339 4a265c08 Michael Hanselmann
ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
340 4a265c08 Michael Hanselmann
ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
341 667dbd6b Adeodato Simo
ARGS_ONE_GROUP = [ArgInstance(min=1, max=1)]
342 f9faf9c3 René Nussbaumer
ARGS_ONE_OS = [ArgOs(min=1, max=1)]
343 4a265c08 Michael Hanselmann
344 4a265c08 Michael Hanselmann
345 846baef9 Iustin Pop
def _ExtractTagsObject(opts, args):
346 846baef9 Iustin Pop
  """Extract the tag type object.
347 846baef9 Iustin Pop

348 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
349 846baef9 Iustin Pop

350 846baef9 Iustin Pop
  """
351 846baef9 Iustin Pop
  if not hasattr(opts, "tag_type"):
352 846baef9 Iustin Pop
    raise errors.ProgrammerError("tag_type not passed to _ExtractTagsObject")
353 846baef9 Iustin Pop
  kind = opts.tag_type
354 846baef9 Iustin Pop
  if kind == constants.TAG_CLUSTER:
355 846baef9 Iustin Pop
    retval = kind, kind
356 846baef9 Iustin Pop
  elif kind == constants.TAG_NODE or kind == constants.TAG_INSTANCE:
357 846baef9 Iustin Pop
    if not args:
358 0c434948 Iustin Pop
      raise errors.OpPrereqError("no arguments passed to the command")
359 846baef9 Iustin Pop
    name = args.pop(0)
360 846baef9 Iustin Pop
    retval = kind, name
361 846baef9 Iustin Pop
  else:
362 846baef9 Iustin Pop
    raise errors.ProgrammerError("Unhandled tag type '%s'" % kind)
363 846baef9 Iustin Pop
  return retval
364 846baef9 Iustin Pop
365 846baef9 Iustin Pop
366 810c50b7 Iustin Pop
def _ExtendTags(opts, args):
367 810c50b7 Iustin Pop
  """Extend the args if a source file has been given.
368 810c50b7 Iustin Pop

369 810c50b7 Iustin Pop
  This function will extend the tags with the contents of the file
370 810c50b7 Iustin Pop
  passed in the 'tags_source' attribute of the opts parameter. A file
371 810c50b7 Iustin Pop
  named '-' will be replaced by stdin.
372 810c50b7 Iustin Pop

373 810c50b7 Iustin Pop
  """
374 810c50b7 Iustin Pop
  fname = opts.tags_source
375 810c50b7 Iustin Pop
  if fname is None:
376 810c50b7 Iustin Pop
    return
377 810c50b7 Iustin Pop
  if fname == "-":
378 810c50b7 Iustin Pop
    new_fh = sys.stdin
379 810c50b7 Iustin Pop
  else:
380 810c50b7 Iustin Pop
    new_fh = open(fname, "r")
381 810c50b7 Iustin Pop
  new_data = []
382 810c50b7 Iustin Pop
  try:
383 810c50b7 Iustin Pop
    # we don't use the nice 'new_data = [line.strip() for line in fh]'
384 810c50b7 Iustin Pop
    # because of python bug 1633941
385 810c50b7 Iustin Pop
    while True:
386 810c50b7 Iustin Pop
      line = new_fh.readline()
387 810c50b7 Iustin Pop
      if not line:
388 810c50b7 Iustin Pop
        break
389 810c50b7 Iustin Pop
      new_data.append(line.strip())
390 810c50b7 Iustin Pop
  finally:
391 810c50b7 Iustin Pop
    new_fh.close()
392 810c50b7 Iustin Pop
  args.extend(new_data)
393 810c50b7 Iustin Pop
394 810c50b7 Iustin Pop
395 846baef9 Iustin Pop
def ListTags(opts, args):
396 846baef9 Iustin Pop
  """List the tags on a given object.
397 846baef9 Iustin Pop

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

403 846baef9 Iustin Pop
  """
404 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
405 7699c3af Iustin Pop
  cl = GetClient()
406 7699c3af Iustin Pop
  result = cl.QueryTags(kind, name)
407 846baef9 Iustin Pop
  result = list(result)
408 846baef9 Iustin Pop
  result.sort()
409 846baef9 Iustin Pop
  for tag in result:
410 03298ebe Michael Hanselmann
    ToStdout(tag)
411 846baef9 Iustin Pop
412 846baef9 Iustin Pop
413 846baef9 Iustin Pop
def AddTags(opts, args):
414 846baef9 Iustin Pop
  """Add tags on a given object.
415 846baef9 Iustin Pop

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

421 846baef9 Iustin Pop
  """
422 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
423 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
424 846baef9 Iustin Pop
  if not args:
425 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be added")
426 d1602edc Iustin Pop
  op = opcodes.OpTagsSet(kind=kind, name=name, tags=args)
427 af1a81d1 Michael Hanselmann
  SubmitOpCode(op, opts=opts)
428 846baef9 Iustin Pop
429 846baef9 Iustin Pop
430 846baef9 Iustin Pop
def RemoveTags(opts, args):
431 846baef9 Iustin Pop
  """Remove tags from a given object.
432 846baef9 Iustin Pop

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

438 846baef9 Iustin Pop
  """
439 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
440 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
441 846baef9 Iustin Pop
  if not args:
442 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be removed")
443 3f0ab95f Iustin Pop
  op = opcodes.OpTagsDel(kind=kind, name=name, tags=args)
444 af1a81d1 Michael Hanselmann
  SubmitOpCode(op, opts=opts)
445 846baef9 Iustin Pop
446 a8083063 Iustin Pop
447 8929d28c Iustin Pop
def check_unit(option, opt, value): # pylint: disable-msg=W0613
448 65fe4693 Iustin Pop
  """OptParsers custom converter for units.
449 65fe4693 Iustin Pop

450 65fe4693 Iustin Pop
  """
451 a8083063 Iustin Pop
  try:
452 a8083063 Iustin Pop
    return utils.ParseUnit(value)
453 a8083063 Iustin Pop
  except errors.UnitParseError, err:
454 3ecf6786 Iustin Pop
    raise OptionValueError("option %s: %s" % (opt, err))
455 a8083063 Iustin Pop
456 a8083063 Iustin Pop
457 a8469393 Iustin Pop
def _SplitKeyVal(opt, data):
458 a8469393 Iustin Pop
  """Convert a KeyVal string into a dict.
459 a8469393 Iustin Pop

460 a8469393 Iustin Pop
  This function will convert a key=val[,...] string into a dict. Empty
461 a8469393 Iustin Pop
  values will be converted specially: keys which have the prefix 'no_'
462 a8469393 Iustin Pop
  will have the value=False and the prefix stripped, the others will
463 a8469393 Iustin Pop
  have value=True.
464 a8469393 Iustin Pop

465 a8469393 Iustin Pop
  @type opt: string
466 a8469393 Iustin Pop
  @param opt: a string holding the option name for which we process the
467 a8469393 Iustin Pop
      data, used in building error messages
468 a8469393 Iustin Pop
  @type data: string
469 a8469393 Iustin Pop
  @param data: a string of the format key=val,key=val,...
470 a8469393 Iustin Pop
  @rtype: dict
471 a8469393 Iustin Pop
  @return: {key=val, key=val}
472 a8469393 Iustin Pop
  @raises errors.ParameterError: if there are duplicate keys
473 a8469393 Iustin Pop

474 a8469393 Iustin Pop
  """
475 a8469393 Iustin Pop
  kv_dict = {}
476 4f31882e Guido Trotter
  if data:
477 1b3a7656 Iustin Pop
    for elem in utils.UnescapeAndSplit(data, sep=","):
478 4f31882e Guido Trotter
      if "=" in elem:
479 4f31882e Guido Trotter
        key, val = elem.split("=", 1)
480 a8469393 Iustin Pop
      else:
481 4f31882e Guido Trotter
        if elem.startswith(NO_PREFIX):
482 4f31882e Guido Trotter
          key, val = elem[len(NO_PREFIX):], False
483 4f31882e Guido Trotter
        elif elem.startswith(UN_PREFIX):
484 4f31882e Guido Trotter
          key, val = elem[len(UN_PREFIX):], None
485 4f31882e Guido Trotter
        else:
486 4f31882e Guido Trotter
          key, val = elem, True
487 4f31882e Guido Trotter
      if key in kv_dict:
488 4f31882e Guido Trotter
        raise errors.ParameterError("Duplicate key '%s' in option %s" %
489 4f31882e Guido Trotter
                                    (key, opt))
490 4f31882e Guido Trotter
      kv_dict[key] = val
491 a8469393 Iustin Pop
  return kv_dict
492 a8469393 Iustin Pop
493 a8469393 Iustin Pop
494 8929d28c Iustin Pop
def check_ident_key_val(option, opt, value):  # pylint: disable-msg=W0613
495 552c8dff Michael Hanselmann
  """Custom parser for ident:key=val,key=val options.
496 552c8dff Michael Hanselmann

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

500 a8469393 Iustin Pop
  """
501 a8469393 Iustin Pop
  if ":" not in value:
502 8b46606c Guido Trotter
    ident, rest = value, ''
503 a8469393 Iustin Pop
  else:
504 a8469393 Iustin Pop
    ident, rest = value.split(":", 1)
505 8b46606c Guido Trotter
506 8b46606c Guido Trotter
  if ident.startswith(NO_PREFIX):
507 8b46606c Guido Trotter
    if rest:
508 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
509 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
510 8b46606c Guido Trotter
    retval = (ident[len(NO_PREFIX):], False)
511 8b46606c Guido Trotter
  elif ident.startswith(UN_PREFIX):
512 8b46606c Guido Trotter
    if rest:
513 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
514 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
515 8b46606c Guido Trotter
    retval = (ident[len(UN_PREFIX):], None)
516 8b46606c Guido Trotter
  else:
517 a8469393 Iustin Pop
    kv_dict = _SplitKeyVal(opt, rest)
518 a8469393 Iustin Pop
    retval = (ident, kv_dict)
519 a8469393 Iustin Pop
  return retval
520 a8469393 Iustin Pop
521 a8469393 Iustin Pop
522 8929d28c Iustin Pop
def check_key_val(option, opt, value):  # pylint: disable-msg=W0613
523 552c8dff Michael Hanselmann
  """Custom parser class for key=val,key=val options.
524 552c8dff Michael Hanselmann

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

527 a8469393 Iustin Pop
  """
528 a8469393 Iustin Pop
  return _SplitKeyVal(opt, value)
529 a8469393 Iustin Pop
530 a8469393 Iustin Pop
531 e7b61bb0 Iustin Pop
def check_bool(option, opt, value): # pylint: disable-msg=W0613
532 e7b61bb0 Iustin Pop
  """Custom parser for yes/no options.
533 e7b61bb0 Iustin Pop

534 e7b61bb0 Iustin Pop
  This will store the parsed value as either True or False.
535 e7b61bb0 Iustin Pop

536 e7b61bb0 Iustin Pop
  """
537 e7b61bb0 Iustin Pop
  value = value.lower()
538 e7b61bb0 Iustin Pop
  if value == constants.VALUE_FALSE or value == "no":
539 e7b61bb0 Iustin Pop
    return False
540 e7b61bb0 Iustin Pop
  elif value == constants.VALUE_TRUE or value == "yes":
541 e7b61bb0 Iustin Pop
    return True
542 e7b61bb0 Iustin Pop
  else:
543 e7b61bb0 Iustin Pop
    raise errors.ParameterError("Invalid boolean value '%s'" % value)
544 e7b61bb0 Iustin Pop
545 e7b61bb0 Iustin Pop
546 63d44c55 Michael Hanselmann
# completion_suggestion is normally a list. Using numeric values not evaluating
547 63d44c55 Michael Hanselmann
# to False for dynamic completion.
548 63d44c55 Michael Hanselmann
(OPT_COMPL_MANY_NODES,
549 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_NODE,
550 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_INSTANCE,
551 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_OS,
552 2d3ed64b Michael Hanselmann
 OPT_COMPL_ONE_IALLOCATOR,
553 36e247e1 Guido Trotter
 OPT_COMPL_INST_ADD_NODES,
554 36e247e1 Guido Trotter
 OPT_COMPL_ONE_NODEGROUP) = range(100, 107)
555 63d44c55 Michael Hanselmann
556 63d44c55 Michael Hanselmann
OPT_COMPL_ALL = frozenset([
557 63d44c55 Michael Hanselmann
  OPT_COMPL_MANY_NODES,
558 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_NODE,
559 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_INSTANCE,
560 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_OS,
561 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_IALLOCATOR,
562 2d3ed64b Michael Hanselmann
  OPT_COMPL_INST_ADD_NODES,
563 36e247e1 Guido Trotter
  OPT_COMPL_ONE_NODEGROUP,
564 63d44c55 Michael Hanselmann
  ])
565 63d44c55 Michael Hanselmann
566 63d44c55 Michael Hanselmann
567 552c8dff Michael Hanselmann
class CliOption(Option):
568 552c8dff Michael Hanselmann
  """Custom option class for optparse.
569 a8469393 Iustin Pop

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

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

1185 c41eea6e Iustin Pop
  @param argv: the command line
1186 c41eea6e Iustin Pop
  @param commands: dictionary with special contents, see the design
1187 c41eea6e Iustin Pop
      doc for cmdline handling
1188 c41eea6e Iustin Pop
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
1189 098c0958 Michael Hanselmann

1190 a8083063 Iustin Pop
  """
1191 a8083063 Iustin Pop
  if len(argv) == 0:
1192 a8083063 Iustin Pop
    binary = "<command>"
1193 a8083063 Iustin Pop
  else:
1194 a8083063 Iustin Pop
    binary = argv[0].split("/")[-1]
1195 a8083063 Iustin Pop
1196 a8083063 Iustin Pop
  if len(argv) > 1 and argv[1] == "--version":
1197 84a12e40 Iustin Pop
    ToStdout("%s (ganeti %s) %s", binary, constants.VCS_VERSION,
1198 84a12e40 Iustin Pop
             constants.RELEASE_VERSION)
1199 a8083063 Iustin Pop
    # Quit right away. That way we don't have to care about this special
1200 a8083063 Iustin Pop
    # argument. optparse.py does it the same.
1201 a8083063 Iustin Pop
    sys.exit(0)
1202 a8083063 Iustin Pop
1203 de47cf8f Guido Trotter
  if len(argv) < 2 or not (argv[1] in commands or
1204 70a35b6f Guido Trotter
                           argv[1] in aliases):
1205 a8083063 Iustin Pop
    # let's do a nice thing
1206 a8083063 Iustin Pop
    sortedcmds = commands.keys()
1207 a8083063 Iustin Pop
    sortedcmds.sort()
1208 03298ebe Michael Hanselmann
1209 03298ebe Michael Hanselmann
    ToStdout("Usage: %s {command} [options...] [argument...]", binary)
1210 03298ebe Michael Hanselmann
    ToStdout("%s <command> --help to see details, or man %s", binary, binary)
1211 03298ebe Michael Hanselmann
    ToStdout("")
1212 03298ebe Michael Hanselmann
1213 a8083063 Iustin Pop
    # compute the max line length for cmd + usage
1214 4e713df6 Iustin Pop
    mlen = max([len(" %s" % cmd) for cmd in commands])
1215 a8083063 Iustin Pop
    mlen = min(60, mlen) # should not get here...
1216 03298ebe Michael Hanselmann
1217 a8083063 Iustin Pop
    # and format a nice command list
1218 03298ebe Michael Hanselmann
    ToStdout("Commands:")
1219 a8083063 Iustin Pop
    for cmd in sortedcmds:
1220 4e713df6 Iustin Pop
      cmdstr = " %s" % (cmd,)
1221 9a033156 Iustin Pop
      help_text = commands[cmd][4]
1222 03298ebe Michael Hanselmann
      help_lines = textwrap.wrap(help_text, 79 - 3 - mlen)
1223 03298ebe Michael Hanselmann
      ToStdout("%-*s - %s", mlen, cmdstr, help_lines.pop(0))
1224 a8083063 Iustin Pop
      for line in help_lines:
1225 03298ebe Michael Hanselmann
        ToStdout("%-*s   %s", mlen, "", line)
1226 03298ebe Michael Hanselmann
1227 03298ebe Michael Hanselmann
    ToStdout("")
1228 03298ebe Michael Hanselmann
1229 a8083063 Iustin Pop
    return None, None, None
1230 de47cf8f Guido Trotter
1231 de47cf8f Guido Trotter
  # get command, unalias it, and look it up in commands
1232 a8083063 Iustin Pop
  cmd = argv.pop(1)
1233 de47cf8f Guido Trotter
  if cmd in aliases:
1234 de47cf8f Guido Trotter
    if cmd in commands:
1235 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' overrides an existing"
1236 de47cf8f Guido Trotter
                                   " command" % cmd)
1237 de47cf8f Guido Trotter
1238 de47cf8f Guido Trotter
    if aliases[cmd] not in commands:
1239 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' maps to non-existing"
1240 de47cf8f Guido Trotter
                                   " command '%s'" % (cmd, aliases[cmd]))
1241 de47cf8f Guido Trotter
1242 de47cf8f Guido Trotter
    cmd = aliases[cmd]
1243 de47cf8f Guido Trotter
1244 a8005e17 Michael Hanselmann
  func, args_def, parser_opts, usage, description = commands[cmd]
1245 5786c087 Michael Hanselmann
  parser = OptionParser(option_list=parser_opts + COMMON_OPTS,
1246 a8083063 Iustin Pop
                        description=description,
1247 a8083063 Iustin Pop
                        formatter=TitledHelpFormatter(),
1248 a8083063 Iustin Pop
                        usage="%%prog %s %s" % (cmd, usage))
1249 a8083063 Iustin Pop
  parser.disable_interspersed_args()
1250 a8083063 Iustin Pop
  options, args = parser.parse_args()
1251 a8005e17 Michael Hanselmann
1252 a8005e17 Michael Hanselmann
  if not _CheckArguments(cmd, args_def, args):
1253 a8083063 Iustin Pop
    return None, None, None
1254 a8083063 Iustin Pop
1255 a8083063 Iustin Pop
  return func, options, args
1256 a8083063 Iustin Pop
1257 a8083063 Iustin Pop
1258 a8005e17 Michael Hanselmann
def _CheckArguments(cmd, args_def, args):
1259 a8005e17 Michael Hanselmann
  """Verifies the arguments using the argument definition.
1260 a8005e17 Michael Hanselmann

1261 a8005e17 Michael Hanselmann
  Algorithm:
1262 a8005e17 Michael Hanselmann

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

1265 a8005e17 Michael Hanselmann
    1. For each argument in definition
1266 a8005e17 Michael Hanselmann

1267 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
1268 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
1269 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
1270 a8005e17 Michael Hanselmann

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

1273 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
1274 a8005e17 Michael Hanselmann

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

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

1279 a8005e17 Michael Hanselmann
  """
1280 a8005e17 Michael Hanselmann
  if args and not args_def:
1281 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects no arguments", cmd)
1282 a8005e17 Michael Hanselmann
    return False
1283 a8005e17 Michael Hanselmann
1284 a8005e17 Michael Hanselmann
  min_count = None
1285 a8005e17 Michael Hanselmann
  max_count = None
1286 a8005e17 Michael Hanselmann
  check_max = None
1287 a8005e17 Michael Hanselmann
1288 a8005e17 Michael Hanselmann
  last_idx = len(args_def) - 1
1289 a8005e17 Michael Hanselmann
1290 a8005e17 Michael Hanselmann
  for idx, arg in enumerate(args_def):
1291 a8005e17 Michael Hanselmann
    if min_count is None:
1292 a8005e17 Michael Hanselmann
      min_count = arg.min
1293 a8005e17 Michael Hanselmann
    elif arg.min is not None:
1294 a8005e17 Michael Hanselmann
      min_count += arg.min
1295 a8005e17 Michael Hanselmann
1296 a8005e17 Michael Hanselmann
    if max_count is None:
1297 a8005e17 Michael Hanselmann
      max_count = arg.max
1298 a8005e17 Michael Hanselmann
    elif arg.max is not None:
1299 a8005e17 Michael Hanselmann
      max_count += arg.max
1300 a8005e17 Michael Hanselmann
1301 a8005e17 Michael Hanselmann
    if idx == last_idx:
1302 a8005e17 Michael Hanselmann
      check_max = (arg.max is not None)
1303 a8005e17 Michael Hanselmann
1304 a8005e17 Michael Hanselmann
    elif arg.max is None:
1305 a8005e17 Michael Hanselmann
      raise errors.ProgrammerError("Only the last argument can have max=None")
1306 a8005e17 Michael Hanselmann
1307 a8005e17 Michael Hanselmann
  if check_max:
1308 a8005e17 Michael Hanselmann
    # Command with exact number of arguments
1309 a8005e17 Michael Hanselmann
    if (min_count is not None and max_count is not None and
1310 a8005e17 Michael Hanselmann
        min_count == max_count and len(args) != min_count):
1311 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects %d argument(s)", cmd, min_count)
1312 a8005e17 Michael Hanselmann
      return False
1313 a8005e17 Michael Hanselmann
1314 a8005e17 Michael Hanselmann
    # Command with limited number of arguments
1315 a8005e17 Michael Hanselmann
    if max_count is not None and len(args) > max_count:
1316 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects only %d argument(s)",
1317 a8005e17 Michael Hanselmann
               cmd, max_count)
1318 a8005e17 Michael Hanselmann
      return False
1319 a8005e17 Michael Hanselmann
1320 a8005e17 Michael Hanselmann
  # Command with some required arguments
1321 a8005e17 Michael Hanselmann
  if min_count is not None and len(args) < min_count:
1322 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects at least %d argument(s)",
1323 a8005e17 Michael Hanselmann
             cmd, min_count)
1324 a8005e17 Michael Hanselmann
    return False
1325 a8005e17 Michael Hanselmann
1326 a8005e17 Michael Hanselmann
  return True
1327 a8005e17 Michael Hanselmann
1328 a8005e17 Michael Hanselmann
1329 60d49723 Michael Hanselmann
def SplitNodeOption(value):
1330 60d49723 Michael Hanselmann
  """Splits the value of a --node option.
1331 60d49723 Michael Hanselmann

1332 60d49723 Michael Hanselmann
  """
1333 60d49723 Michael Hanselmann
  if value and ':' in value:
1334 60d49723 Michael Hanselmann
    return value.split(':', 1)
1335 60d49723 Michael Hanselmann
  else:
1336 60d49723 Michael Hanselmann
    return (value, None)
1337 60d49723 Michael Hanselmann
1338 60d49723 Michael Hanselmann
1339 07150497 Guido Trotter
def CalculateOSNames(os_name, os_variants):
1340 07150497 Guido Trotter
  """Calculates all the names an OS can be called, according to its variants.
1341 07150497 Guido Trotter

1342 07150497 Guido Trotter
  @type os_name: string
1343 07150497 Guido Trotter
  @param os_name: base name of the os
1344 07150497 Guido Trotter
  @type os_variants: list or None
1345 07150497 Guido Trotter
  @param os_variants: list of supported variants
1346 07150497 Guido Trotter
  @rtype: list
1347 07150497 Guido Trotter
  @return: list of valid names
1348 07150497 Guido Trotter

1349 07150497 Guido Trotter
  """
1350 07150497 Guido Trotter
  if os_variants:
1351 07150497 Guido Trotter
    return ['%s+%s' % (os_name, v) for v in os_variants]
1352 07150497 Guido Trotter
  else:
1353 07150497 Guido Trotter
    return [os_name]
1354 07150497 Guido Trotter
1355 07150497 Guido Trotter
1356 a4ebd726 Michael Hanselmann
def ParseFields(selected, default):
1357 a4ebd726 Michael Hanselmann
  """Parses the values of "--field"-like options.
1358 a4ebd726 Michael Hanselmann

1359 a4ebd726 Michael Hanselmann
  @type selected: string or None
1360 a4ebd726 Michael Hanselmann
  @param selected: User-selected options
1361 a4ebd726 Michael Hanselmann
  @type default: list
1362 a4ebd726 Michael Hanselmann
  @param default: Default fields
1363 a4ebd726 Michael Hanselmann

1364 a4ebd726 Michael Hanselmann
  """
1365 a4ebd726 Michael Hanselmann
  if selected is None:
1366 a4ebd726 Michael Hanselmann
    return default
1367 a4ebd726 Michael Hanselmann
1368 a4ebd726 Michael Hanselmann
  if selected.startswith("+"):
1369 a4ebd726 Michael Hanselmann
    return default + selected[1:].split(",")
1370 a4ebd726 Michael Hanselmann
1371 a4ebd726 Michael Hanselmann
  return selected.split(",")
1372 a4ebd726 Michael Hanselmann
1373 a4ebd726 Michael Hanselmann
1374 e0e916fe Iustin Pop
UsesRPC = rpc.RunWithRPC
1375 4331f6cd Michael Hanselmann
1376 4331f6cd Michael Hanselmann
1377 47988778 Iustin Pop
def AskUser(text, choices=None):
1378 47988778 Iustin Pop
  """Ask the user a question.
1379 a8083063 Iustin Pop

1380 c41eea6e Iustin Pop
  @param text: the question to ask
1381 a8083063 Iustin Pop

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

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

1391 a8083063 Iustin Pop
  """
1392 47988778 Iustin Pop
  if choices is None:
1393 47988778 Iustin Pop
    choices = [('y', True, 'Perform the operation'),
1394 47988778 Iustin Pop
               ('n', False, 'Do not perform the operation')]
1395 47988778 Iustin Pop
  if not choices or not isinstance(choices, list):
1396 5bbd3f7f Michael Hanselmann
    raise errors.ProgrammerError("Invalid choices argument to AskUser")
1397 47988778 Iustin Pop
  for entry in choices:
1398 47988778 Iustin Pop
    if not isinstance(entry, tuple) or len(entry) < 3 or entry[0] == '?':
1399 5bbd3f7f Michael Hanselmann
      raise errors.ProgrammerError("Invalid choices element to AskUser")
1400 47988778 Iustin Pop
1401 47988778 Iustin Pop
  answer = choices[-1][1]
1402 47988778 Iustin Pop
  new_text = []
1403 47988778 Iustin Pop
  for line in text.splitlines():
1404 47988778 Iustin Pop
    new_text.append(textwrap.fill(line, 70, replace_whitespace=False))
1405 47988778 Iustin Pop
  text = "\n".join(new_text)
1406 a8083063 Iustin Pop
  try:
1407 3023170f Iustin Pop
    f = file("/dev/tty", "a+")
1408 a8083063 Iustin Pop
  except IOError:
1409 47988778 Iustin Pop
    return answer
1410 a8083063 Iustin Pop
  try:
1411 47988778 Iustin Pop
    chars = [entry[0] for entry in choices]
1412 47988778 Iustin Pop
    chars[-1] = "[%s]" % chars[-1]
1413 47988778 Iustin Pop
    chars.append('?')
1414 47988778 Iustin Pop
    maps = dict([(entry[0], entry[1]) for entry in choices])
1415 47988778 Iustin Pop
    while True:
1416 47988778 Iustin Pop
      f.write(text)
1417 47988778 Iustin Pop
      f.write('\n')
1418 47988778 Iustin Pop
      f.write("/".join(chars))
1419 47988778 Iustin Pop
      f.write(": ")
1420 47988778 Iustin Pop
      line = f.readline(2).strip().lower()
1421 47988778 Iustin Pop
      if line in maps:
1422 47988778 Iustin Pop
        answer = maps[line]
1423 47988778 Iustin Pop
        break
1424 47988778 Iustin Pop
      elif line == '?':
1425 47988778 Iustin Pop
        for entry in choices:
1426 47988778 Iustin Pop
          f.write(" %s - %s\n" % (entry[0], entry[2]))
1427 47988778 Iustin Pop
        f.write("\n")
1428 47988778 Iustin Pop
        continue
1429 a8083063 Iustin Pop
  finally:
1430 a8083063 Iustin Pop
    f.close()
1431 a8083063 Iustin Pop
  return answer
1432 a8083063 Iustin Pop
1433 a8083063 Iustin Pop
1434 e9d741b6 Iustin Pop
class JobSubmittedException(Exception):
1435 e9d741b6 Iustin Pop
  """Job was submitted, client should exit.
1436 e9d741b6 Iustin Pop

1437 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1438 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1439 e9d741b6 Iustin Pop

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

1442 e9d741b6 Iustin Pop
  """
1443 e9d741b6 Iustin Pop
1444 e9d741b6 Iustin Pop
1445 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1446 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1447 a8083063 Iustin Pop

1448 0a1e74d9 Iustin Pop
  @type ops: list
1449 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1450 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1451 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1452 0a1e74d9 Iustin Pop
             if None, a new client will be created
1453 a8083063 Iustin Pop

1454 a8083063 Iustin Pop
  """
1455 e2212007 Iustin Pop
  if cl is None:
1456 b33e986b Iustin Pop
    cl = GetClient()
1457 685ee993 Iustin Pop
1458 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1459 0a1e74d9 Iustin Pop
1460 0a1e74d9 Iustin Pop
  return job_id
1461 0a1e74d9 Iustin Pop
1462 0a1e74d9 Iustin Pop
1463 4e338533 Michael Hanselmann
def GenericPollJob(job_id, cbs, report_cbs):
1464 4e338533 Michael Hanselmann
  """Generic job-polling function.
1465 0a1e74d9 Iustin Pop

1466 4e338533 Michael Hanselmann
  @type job_id: number
1467 4e338533 Michael Hanselmann
  @param job_id: Job ID
1468 4e338533 Michael Hanselmann
  @type cbs: Instance of L{JobPollCbBase}
1469 4e338533 Michael Hanselmann
  @param cbs: Data callbacks
1470 4e338533 Michael Hanselmann
  @type report_cbs: Instance of L{JobPollReportCbBase}
1471 4e338533 Michael Hanselmann
  @param report_cbs: Reporting callbacks
1472 0a1e74d9 Iustin Pop

1473 0a1e74d9 Iustin Pop
  """
1474 6c5a7090 Michael Hanselmann
  prev_job_info = None
1475 6c5a7090 Michael Hanselmann
  prev_logmsg_serial = None
1476 6c5a7090 Michael Hanselmann
1477 f4484122 Michael Hanselmann
  status = None
1478 f4484122 Michael Hanselmann
1479 685ee993 Iustin Pop
  while True:
1480 4e338533 Michael Hanselmann
    result = cbs.WaitForJobChangeOnce(job_id, ["status"], prev_job_info,
1481 4e338533 Michael Hanselmann
                                      prev_logmsg_serial)
1482 6c5a7090 Michael Hanselmann
    if not result:
1483 685ee993 Iustin Pop
      # job not found, go away!
1484 0bbe448c Michael Hanselmann
      raise errors.JobLost("Job with id %s lost" % job_id)
1485 4e338533 Michael Hanselmann
1486 4e338533 Michael Hanselmann
    if result == constants.JOB_NOTCHANGED:
1487 4e338533 Michael Hanselmann
      report_cbs.ReportNotChanged(job_id, status)
1488 f4484122 Michael Hanselmann
1489 f4484122 Michael Hanselmann
      # Wait again
1490 f4484122 Michael Hanselmann
      continue
1491 685ee993 Iustin Pop
1492 6c5a7090 Michael Hanselmann
    # Split result, a tuple of (field values, log entries)
1493 6c5a7090 Michael Hanselmann
    (job_info, log_entries) = result
1494 6c5a7090 Michael Hanselmann
    (status, ) = job_info
1495 6c5a7090 Michael Hanselmann
1496 6c5a7090 Michael Hanselmann
    if log_entries:
1497 6c5a7090 Michael Hanselmann
      for log_entry in log_entries:
1498 4e338533 Michael Hanselmann
        (serial, timestamp, log_type, message) = log_entry
1499 4e338533 Michael Hanselmann
        report_cbs.ReportLogMessage(job_id, serial, timestamp,
1500 4e338533 Michael Hanselmann
                                    log_type, message)
1501 6c5a7090 Michael Hanselmann
        prev_logmsg_serial = max(prev_logmsg_serial, serial)
1502 6c5a7090 Michael Hanselmann
1503 0bbe448c Michael Hanselmann
    # TODO: Handle canceled and archived jobs
1504 fbf0262f Michael Hanselmann
    elif status in (constants.JOB_STATUS_SUCCESS,
1505 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_ERROR,
1506 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELING,
1507 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELED):
1508 685ee993 Iustin Pop
      break
1509 6c5a7090 Michael Hanselmann
1510 6c5a7090 Michael Hanselmann
    prev_job_info = job_info
1511 685ee993 Iustin Pop
1512 4e338533 Michael Hanselmann
  jobs = cbs.QueryJobs([job_id], ["status", "opstatus", "opresult"])
1513 0bbe448c Michael Hanselmann
  if not jobs:
1514 0bbe448c Michael Hanselmann
    raise errors.JobLost("Job with id %s lost" % job_id)
1515 685ee993 Iustin Pop
1516 0e050889 Iustin Pop
  status, opstatus, result = jobs[0]
1517 4e338533 Michael Hanselmann
1518 0bbe448c Michael Hanselmann
  if status == constants.JOB_STATUS_SUCCESS:
1519 53c04d04 Iustin Pop
    return result
1520 4e338533 Michael Hanselmann
1521 4e338533 Michael Hanselmann
  if status in (constants.JOB_STATUS_CANCELING, constants.JOB_STATUS_CANCELED):
1522 fbf0262f Michael Hanselmann
    raise errors.OpExecError("Job was canceled")
1523 4e338533 Michael Hanselmann
1524 4e338533 Michael Hanselmann
  has_ok = False
1525 4e338533 Michael Hanselmann
  for idx, (status, msg) in enumerate(zip(opstatus, result)):
1526 4e338533 Michael Hanselmann
    if status == constants.OP_STATUS_SUCCESS:
1527 4e338533 Michael Hanselmann
      has_ok = True
1528 4e338533 Michael Hanselmann
    elif status == constants.OP_STATUS_ERROR:
1529 4e338533 Michael Hanselmann
      errors.MaybeRaise(msg)
1530 4e338533 Michael Hanselmann
1531 4e338533 Michael Hanselmann
      if has_ok:
1532 4e338533 Michael Hanselmann
        raise errors.OpExecError("partial failure (opcode %d): %s" %
1533 4e338533 Michael Hanselmann
                                 (idx, msg))
1534 4e338533 Michael Hanselmann
1535 4e338533 Michael Hanselmann
      raise errors.OpExecError(str(msg))
1536 4e338533 Michael Hanselmann
1537 4e338533 Michael Hanselmann
  # default failure mode
1538 4e338533 Michael Hanselmann
  raise errors.OpExecError(result)
1539 4e338533 Michael Hanselmann
1540 4e338533 Michael Hanselmann
1541 4e338533 Michael Hanselmann
class JobPollCbBase:
1542 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} callbacks.
1543 4e338533 Michael Hanselmann

1544 4e338533 Michael Hanselmann
  """
1545 4e338533 Michael Hanselmann
  def __init__(self):
1546 4e338533 Michael Hanselmann
    """Initializes this class.
1547 4e338533 Michael Hanselmann

1548 4e338533 Michael Hanselmann
    """
1549 4e338533 Michael Hanselmann
1550 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1551 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1552 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1553 4e338533 Michael Hanselmann

1554 4e338533 Michael Hanselmann
    """
1555 4e338533 Michael Hanselmann
    raise NotImplementedError()
1556 4e338533 Michael Hanselmann
1557 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1558 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1559 4e338533 Michael Hanselmann

1560 4e338533 Michael Hanselmann
    @type job_ids: list of numbers
1561 4e338533 Michael Hanselmann
    @param job_ids: Job IDs
1562 4e338533 Michael Hanselmann
    @type fields: list of strings
1563 4e338533 Michael Hanselmann
    @param fields: Fields
1564 4e338533 Michael Hanselmann

1565 4e338533 Michael Hanselmann
    """
1566 4e338533 Michael Hanselmann
    raise NotImplementedError()
1567 4e338533 Michael Hanselmann
1568 4e338533 Michael Hanselmann
1569 4e338533 Michael Hanselmann
class JobPollReportCbBase:
1570 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} reporting callbacks.
1571 4e338533 Michael Hanselmann

1572 4e338533 Michael Hanselmann
  """
1573 4e338533 Michael Hanselmann
  def __init__(self):
1574 4e338533 Michael Hanselmann
    """Initializes this class.
1575 4e338533 Michael Hanselmann

1576 4e338533 Michael Hanselmann
    """
1577 4e338533 Michael Hanselmann
1578 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1579 4e338533 Michael Hanselmann
    """Handles a log message.
1580 4e338533 Michael Hanselmann

1581 4e338533 Michael Hanselmann
    """
1582 4e338533 Michael Hanselmann
    raise NotImplementedError()
1583 4e338533 Michael Hanselmann
1584 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1585 4e338533 Michael Hanselmann
    """Called for if a job hasn't changed in a while.
1586 4e338533 Michael Hanselmann

1587 4e338533 Michael Hanselmann
    @type job_id: number
1588 4e338533 Michael Hanselmann
    @param job_id: Job ID
1589 4e338533 Michael Hanselmann
    @type status: string or None
1590 4e338533 Michael Hanselmann
    @param status: Job status if available
1591 4e338533 Michael Hanselmann

1592 4e338533 Michael Hanselmann
    """
1593 4e338533 Michael Hanselmann
    raise NotImplementedError()
1594 4e338533 Michael Hanselmann
1595 4e338533 Michael Hanselmann
1596 4e338533 Michael Hanselmann
class _LuxiJobPollCb(JobPollCbBase):
1597 4e338533 Michael Hanselmann
  def __init__(self, cl):
1598 4e338533 Michael Hanselmann
    """Initializes this class.
1599 4e338533 Michael Hanselmann

1600 4e338533 Michael Hanselmann
    """
1601 4e338533 Michael Hanselmann
    JobPollCbBase.__init__(self)
1602 4e338533 Michael Hanselmann
    self.cl = cl
1603 4e338533 Michael Hanselmann
1604 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1605 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1606 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1607 4e338533 Michael Hanselmann

1608 4e338533 Michael Hanselmann
    """
1609 4e338533 Michael Hanselmann
    return self.cl.WaitForJobChangeOnce(job_id, fields,
1610 4e338533 Michael Hanselmann
                                        prev_job_info, prev_log_serial)
1611 4e338533 Michael Hanselmann
1612 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1613 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1614 4e338533 Michael Hanselmann

1615 4e338533 Michael Hanselmann
    """
1616 4e338533 Michael Hanselmann
    return self.cl.QueryJobs(job_ids, fields)
1617 4e338533 Michael Hanselmann
1618 4e338533 Michael Hanselmann
1619 4e338533 Michael Hanselmann
class FeedbackFnJobPollReportCb(JobPollReportCbBase):
1620 4e338533 Michael Hanselmann
  def __init__(self, feedback_fn):
1621 4e338533 Michael Hanselmann
    """Initializes this class.
1622 4e338533 Michael Hanselmann

1623 4e338533 Michael Hanselmann
    """
1624 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1625 4e338533 Michael Hanselmann
1626 4e338533 Michael Hanselmann
    self.feedback_fn = feedback_fn
1627 4e338533 Michael Hanselmann
1628 4e338533 Michael Hanselmann
    assert callable(feedback_fn)
1629 4e338533 Michael Hanselmann
1630 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1631 4e338533 Michael Hanselmann
    """Handles a log message.
1632 4e338533 Michael Hanselmann

1633 4e338533 Michael Hanselmann
    """
1634 4e338533 Michael Hanselmann
    self.feedback_fn((timestamp, log_type, log_msg))
1635 4e338533 Michael Hanselmann
1636 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1637 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1638 4e338533 Michael Hanselmann

1639 4e338533 Michael Hanselmann
    """
1640 4e338533 Michael Hanselmann
    # Ignore
1641 4e338533 Michael Hanselmann
1642 4e338533 Michael Hanselmann
1643 4e338533 Michael Hanselmann
class StdioJobPollReportCb(JobPollReportCbBase):
1644 4e338533 Michael Hanselmann
  def __init__(self):
1645 4e338533 Michael Hanselmann
    """Initializes this class.
1646 4e338533 Michael Hanselmann

1647 4e338533 Michael Hanselmann
    """
1648 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1649 4e338533 Michael Hanselmann
1650 4e338533 Michael Hanselmann
    self.notified_queued = False
1651 4e338533 Michael Hanselmann
    self.notified_waitlock = False
1652 4e338533 Michael Hanselmann
1653 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1654 4e338533 Michael Hanselmann
    """Handles a log message.
1655 4e338533 Michael Hanselmann

1656 4e338533 Michael Hanselmann
    """
1657 4e338533 Michael Hanselmann
    ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)),
1658 8a7f1c61 Michael Hanselmann
             FormatLogMessage(log_type, log_msg))
1659 4e338533 Michael Hanselmann
1660 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1661 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1662 4e338533 Michael Hanselmann

1663 4e338533 Michael Hanselmann
    """
1664 4e338533 Michael Hanselmann
    if status is None:
1665 4e338533 Michael Hanselmann
      return
1666 4e338533 Michael Hanselmann
1667 4e338533 Michael Hanselmann
    if status == constants.JOB_STATUS_QUEUED and not self.notified_queued:
1668 4e338533 Michael Hanselmann
      ToStderr("Job %s is waiting in queue", job_id)
1669 4e338533 Michael Hanselmann
      self.notified_queued = True
1670 4e338533 Michael Hanselmann
1671 4e338533 Michael Hanselmann
    elif status == constants.JOB_STATUS_WAITLOCK and not self.notified_waitlock:
1672 4e338533 Michael Hanselmann
      ToStderr("Job %s is trying to acquire all necessary locks", job_id)
1673 4e338533 Michael Hanselmann
      self.notified_waitlock = True
1674 4e338533 Michael Hanselmann
1675 4e338533 Michael Hanselmann
1676 8a7f1c61 Michael Hanselmann
def FormatLogMessage(log_type, log_msg):
1677 8a7f1c61 Michael Hanselmann
  """Formats a job message according to its type.
1678 8a7f1c61 Michael Hanselmann

1679 8a7f1c61 Michael Hanselmann
  """
1680 8a7f1c61 Michael Hanselmann
  if log_type != constants.ELOG_MESSAGE:
1681 8a7f1c61 Michael Hanselmann
    log_msg = str(log_msg)
1682 8a7f1c61 Michael Hanselmann
1683 8a7f1c61 Michael Hanselmann
  return utils.SafeEncode(log_msg)
1684 8a7f1c61 Michael Hanselmann
1685 8a7f1c61 Michael Hanselmann
1686 583163a6 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None, reporter=None):
1687 4e338533 Michael Hanselmann
  """Function to poll for the result of a job.
1688 4e338533 Michael Hanselmann

1689 4e338533 Michael Hanselmann
  @type job_id: job identified
1690 4e338533 Michael Hanselmann
  @param job_id: the job to poll for results
1691 4e338533 Michael Hanselmann
  @type cl: luxi.Client
1692 4e338533 Michael Hanselmann
  @param cl: the luxi client to use for communicating with the master;
1693 4e338533 Michael Hanselmann
             if None, a new client will be created
1694 4e338533 Michael Hanselmann

1695 4e338533 Michael Hanselmann
  """
1696 4e338533 Michael Hanselmann
  if cl is None:
1697 4e338533 Michael Hanselmann
    cl = GetClient()
1698 4e338533 Michael Hanselmann
1699 583163a6 Michael Hanselmann
  if reporter is None:
1700 583163a6 Michael Hanselmann
    if feedback_fn:
1701 583163a6 Michael Hanselmann
      reporter = FeedbackFnJobPollReportCb(feedback_fn)
1702 583163a6 Michael Hanselmann
    else:
1703 583163a6 Michael Hanselmann
      reporter = StdioJobPollReportCb()
1704 583163a6 Michael Hanselmann
  elif feedback_fn:
1705 583163a6 Michael Hanselmann
    raise errors.ProgrammerError("Can't specify reporter and feedback function")
1706 4e338533 Michael Hanselmann
1707 4e338533 Michael Hanselmann
  return GenericPollJob(job_id, _LuxiJobPollCb(cl), reporter)
1708 ceab32dd Iustin Pop
1709 ceab32dd Iustin Pop
1710 583163a6 Michael Hanselmann
def SubmitOpCode(op, cl=None, feedback_fn=None, opts=None, reporter=None):
1711 0a1e74d9 Iustin Pop
  """Legacy function to submit an opcode.
1712 0a1e74d9 Iustin Pop

1713 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1714 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1715 0a1e74d9 Iustin Pop
  interaction functions.
1716 0a1e74d9 Iustin Pop

1717 0a1e74d9 Iustin Pop
  """
1718 0a1e74d9 Iustin Pop
  if cl is None:
1719 0a1e74d9 Iustin Pop
    cl = GetClient()
1720 0a1e74d9 Iustin Pop
1721 293ba2d8 Iustin Pop
  SetGenericOpcodeOpts([op], opts)
1722 293ba2d8 Iustin Pop
1723 5d297d8a Michael Hanselmann
  job_id = SendJob([op], cl=cl)
1724 0a1e74d9 Iustin Pop
1725 583163a6 Michael Hanselmann
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn,
1726 583163a6 Michael Hanselmann
                       reporter=reporter)
1727 53c04d04 Iustin Pop
1728 53c04d04 Iustin Pop
  return op_results[0]
1729 0a1e74d9 Iustin Pop
1730 0a1e74d9 Iustin Pop
1731 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1732 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1733 94428652 Iustin Pop

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

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

1742 94428652 Iustin Pop
  """
1743 94428652 Iustin Pop
  if opts and opts.submit_only:
1744 293ba2d8 Iustin Pop
    job = [op]
1745 293ba2d8 Iustin Pop
    SetGenericOpcodeOpts(job, opts)
1746 293ba2d8 Iustin Pop
    job_id = SendJob(job, cl=cl)
1747 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
1748 94428652 Iustin Pop
  else:
1749 293ba2d8 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
1750 293ba2d8 Iustin Pop
1751 293ba2d8 Iustin Pop
1752 293ba2d8 Iustin Pop
def SetGenericOpcodeOpts(opcode_list, options):
1753 293ba2d8 Iustin Pop
  """Processor for generic options.
1754 293ba2d8 Iustin Pop

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

1758 293ba2d8 Iustin Pop
  @param opcode_list: list of opcodes
1759 293ba2d8 Iustin Pop
  @param options: command line options or None
1760 293ba2d8 Iustin Pop
  @return: None (in-place modification)
1761 293ba2d8 Iustin Pop

1762 293ba2d8 Iustin Pop
  """
1763 293ba2d8 Iustin Pop
  if not options:
1764 293ba2d8 Iustin Pop
    return
1765 293ba2d8 Iustin Pop
  for op in opcode_list:
1766 aa06f8c6 Michael Hanselmann
    op.debug_level = options.debug
1767 a0a6ff34 Iustin Pop
    if hasattr(options, "dry_run"):
1768 a0a6ff34 Iustin Pop
      op.dry_run = options.dry_run
1769 aa06f8c6 Michael Hanselmann
    if getattr(options, "priority", None) is not None:
1770 aa06f8c6 Michael Hanselmann
      op.priority = _PRIONAME_TO_VALUE[options.priority]
1771 94428652 Iustin Pop
1772 94428652 Iustin Pop
1773 af30b2fd Michael Hanselmann
def GetClient():
1774 af30b2fd Michael Hanselmann
  # TODO: Cache object?
1775 b33e986b Iustin Pop
  try:
1776 b33e986b Iustin Pop
    client = luxi.Client()
1777 b33e986b Iustin Pop
  except luxi.NoMasterError:
1778 d9a51679 Michael Hanselmann
    ss = ssconf.SimpleStore()
1779 d9a51679 Michael Hanselmann
1780 d9a51679 Michael Hanselmann
    # Try to read ssconf file
1781 d9a51679 Michael Hanselmann
    try:
1782 d9a51679 Michael Hanselmann
      ss.GetMasterNode()
1783 d9a51679 Michael Hanselmann
    except errors.ConfigurationError:
1784 d9a51679 Michael Hanselmann
      raise errors.OpPrereqError("Cluster not initialized or this machine is"
1785 d9a51679 Michael Hanselmann
                                 " not part of a cluster")
1786 d9a51679 Michael Hanselmann
1787 d9a51679 Michael Hanselmann
    master, myself = ssconf.GetMasterAndMyself(ss=ss)
1788 b33e986b Iustin Pop
    if master != myself:
1789 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
1790 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
1791 b33e986b Iustin Pop
                                 master)
1792 d9a51679 Michael Hanselmann
    raise
1793 b33e986b Iustin Pop
  return client
1794 af30b2fd Michael Hanselmann
1795 af30b2fd Michael Hanselmann
1796 73702ee7 Iustin Pop
def FormatError(err):
1797 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
1798 73702ee7 Iustin Pop

1799 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
1800 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
1801 73702ee7 Iustin Pop
  second, a string describing the error message (not
1802 73702ee7 Iustin Pop
  newline-terminated).
1803 73702ee7 Iustin Pop

1804 73702ee7 Iustin Pop
  """
1805 73702ee7 Iustin Pop
  retcode = 1
1806 73702ee7 Iustin Pop
  obuf = StringIO()
1807 e2e521d0 Iustin Pop
  msg = str(err)
1808 73702ee7 Iustin Pop
  if isinstance(err, errors.ConfigurationError):
1809 e2e521d0 Iustin Pop
    txt = "Corrupt configuration file: %s" % msg
1810 46fbdd04 Iustin Pop
    logging.error(txt)
1811 e2e521d0 Iustin Pop
    obuf.write(txt + "\n")
1812 73702ee7 Iustin Pop
    obuf.write("Aborting.")
1813 73702ee7 Iustin Pop
    retcode = 2
1814 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksAbort):
1815 73702ee7 Iustin Pop
    obuf.write("Failure: hooks execution failed:\n")
1816 73702ee7 Iustin Pop
    for node, script, out in err.args[0]:
1817 73702ee7 Iustin Pop
      if out:
1818 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s, output: %s\n" %
1819 73702ee7 Iustin Pop
                   (node, script, out))
1820 73702ee7 Iustin Pop
      else:
1821 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s (no output)\n" %
1822 73702ee7 Iustin Pop
                   (node, script))
1823 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksFailure):
1824 e2e521d0 Iustin Pop
    obuf.write("Failure: hooks general failure: %s" % msg)
1825 73702ee7 Iustin Pop
  elif isinstance(err, errors.ResolverError):
1826 b705c7a6 Manuel Franceschini
    this_host = netutils.Hostname.GetSysName()
1827 73702ee7 Iustin Pop
    if err.args[0] == this_host:
1828 73702ee7 Iustin Pop
      msg = "Failure: can't resolve my own hostname ('%s')"
1829 73702ee7 Iustin Pop
    else:
1830 73702ee7 Iustin Pop
      msg = "Failure: can't resolve hostname '%s'"
1831 73702ee7 Iustin Pop
    obuf.write(msg % err.args[0])
1832 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpPrereqError):
1833 5c983ee5 Iustin Pop
    if len(err.args) == 2:
1834 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
1835 5c983ee5 Iustin Pop
               " operation:\nerror type: %s, error details:\n%s" %
1836 5c983ee5 Iustin Pop
                 (err.args[1], err.args[0]))
1837 5c983ee5 Iustin Pop
    else:
1838 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
1839 5c983ee5 Iustin Pop
                 " operation:\n%s" % msg)
1840 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpExecError):
1841 e2e521d0 Iustin Pop
    obuf.write("Failure: command execution error:\n%s" % msg)
1842 73702ee7 Iustin Pop
  elif isinstance(err, errors.TagError):
1843 e2e521d0 Iustin Pop
    obuf.write("Failure: invalid tag(s) given:\n%s" % msg)
1844 686d7433 Iustin Pop
  elif isinstance(err, errors.JobQueueDrainError):
1845 686d7433 Iustin Pop
    obuf.write("Failure: the job queue is marked for drain and doesn't"
1846 686d7433 Iustin Pop
               " accept new requests\n")
1847 f87b405e Michael Hanselmann
  elif isinstance(err, errors.JobQueueFull):
1848 f87b405e Michael Hanselmann
    obuf.write("Failure: the job queue is full and doesn't accept new"
1849 f87b405e Michael Hanselmann
               " job submissions until old jobs are archived\n")
1850 a5728081 Guido Trotter
  elif isinstance(err, errors.TypeEnforcementError):
1851 a5728081 Guido Trotter
    obuf.write("Parameter Error: %s" % msg)
1852 c1ce76bb Iustin Pop
  elif isinstance(err, errors.ParameterError):
1853 c1ce76bb Iustin Pop
    obuf.write("Failure: unknown/wrong parameter name '%s'" % msg)
1854 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.NoMasterError):
1855 03a8dbdc Iustin Pop
    obuf.write("Cannot communicate with the master daemon.\nIs it running"
1856 082c5adb Michael Hanselmann
               " and listening for connections?")
1857 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.TimeoutError):
1858 cd4c86a8 Michael Hanselmann
    obuf.write("Timeout while talking to the master daemon. Jobs might have"
1859 cd4c86a8 Michael Hanselmann
               " been submitted and will continue to run even if the call"
1860 cd4c86a8 Michael Hanselmann
               " timed out. Useful commands in this situation are \"gnt-job"
1861 cd4c86a8 Michael Hanselmann
               " list\", \"gnt-job cancel\" and \"gnt-job watch\". Error:\n")
1862 cd4c86a8 Michael Hanselmann
    obuf.write(msg)
1863 5a1c22fe Iustin Pop
  elif isinstance(err, luxi.PermissionError):
1864 5a1c22fe Iustin Pop
    obuf.write("It seems you don't have permissions to connect to the"
1865 5a1c22fe Iustin Pop
               " master daemon.\nPlease retry as a different user.")
1866 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.ProtocolError):
1867 03a8dbdc Iustin Pop
    obuf.write("Unhandled protocol error while talking to the master daemon:\n"
1868 03a8dbdc Iustin Pop
               "%s" % msg)
1869 91c622a8 Iustin Pop
  elif isinstance(err, errors.JobLost):
1870 91c622a8 Iustin Pop
    obuf.write("Error checking job status: %s" % msg)
1871 797506fc Michael Hanselmann
  elif isinstance(err, errors.GenericError):
1872 797506fc Michael Hanselmann
    obuf.write("Unhandled Ganeti error: %s" % msg)
1873 e9d741b6 Iustin Pop
  elif isinstance(err, JobSubmittedException):
1874 e9d741b6 Iustin Pop
    obuf.write("JobID: %s\n" % err.args[0])
1875 e9d741b6 Iustin Pop
    retcode = 0
1876 73702ee7 Iustin Pop
  else:
1877 e2e521d0 Iustin Pop
    obuf.write("Unhandled exception: %s" % msg)
1878 73702ee7 Iustin Pop
  return retcode, obuf.getvalue().rstrip('\n')
1879 73702ee7 Iustin Pop
1880 73702ee7 Iustin Pop
1881 de47cf8f Guido Trotter
def GenericMain(commands, override=None, aliases=None):
1882 a8083063 Iustin Pop
  """Generic main function for all the gnt-* commands.
1883 a8083063 Iustin Pop

1884 334d1483 Iustin Pop
  Arguments:
1885 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
1886 334d1483 Iustin Pop
                for command line handling.
1887 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
1888 334d1483 Iustin Pop
                override command line options; this can be used to pass
1889 334d1483 Iustin Pop
                options from the scripts to generic functions
1890 de47cf8f Guido Trotter
    - aliases: dictionary with command aliases {'alias': 'target, ...}
1891 a8083063 Iustin Pop

1892 a8083063 Iustin Pop
  """
1893 a8083063 Iustin Pop
  # save the program name and the entire command line for later logging
1894 a8083063 Iustin Pop
  if sys.argv:
1895 a8083063 Iustin Pop
    binary = os.path.basename(sys.argv[0]) or sys.argv[0]
1896 a8083063 Iustin Pop
    if len(sys.argv) >= 2:
1897 a8083063 Iustin Pop
      binary += " " + sys.argv[1]
1898 a8083063 Iustin Pop
      old_cmdline = " ".join(sys.argv[2:])
1899 a8083063 Iustin Pop
    else:
1900 a8083063 Iustin Pop
      old_cmdline = ""
1901 a8083063 Iustin Pop
  else:
1902 a8083063 Iustin Pop
    binary = "<unknown program>"
1903 a8083063 Iustin Pop
    old_cmdline = ""
1904 a8083063 Iustin Pop
1905 de47cf8f Guido Trotter
  if aliases is None:
1906 de47cf8f Guido Trotter
    aliases = {}
1907 de47cf8f Guido Trotter
1908 3126878d Guido Trotter
  try:
1909 3126878d Guido Trotter
    func, options, args = _ParseArgs(sys.argv, commands, aliases)
1910 3126878d Guido Trotter
  except errors.ParameterError, err:
1911 3126878d Guido Trotter
    result, err_msg = FormatError(err)
1912 3126878d Guido Trotter
    ToStderr(err_msg)
1913 3126878d Guido Trotter
    return 1
1914 3126878d Guido Trotter
1915 a8083063 Iustin Pop
  if func is None: # parse error
1916 a8083063 Iustin Pop
    return 1
1917 a8083063 Iustin Pop
1918 334d1483 Iustin Pop
  if override is not None:
1919 334d1483 Iustin Pop
    for key, val in override.iteritems():
1920 334d1483 Iustin Pop
      setattr(options, key, val)
1921 334d1483 Iustin Pop
1922 cfcc79c6 Michael Hanselmann
  utils.SetupLogging(constants.LOG_COMMANDS, binary, debug=options.debug,
1923 cfcc79c6 Michael Hanselmann
                     stderr_logging=True)
1924 a8083063 Iustin Pop
1925 a8083063 Iustin Pop
  if old_cmdline:
1926 46fbdd04 Iustin Pop
    logging.info("run with arguments '%s'", old_cmdline)
1927 a8083063 Iustin Pop
  else:
1928 46fbdd04 Iustin Pop
    logging.info("run with no arguments")
1929 a8083063 Iustin Pop
1930 a8083063 Iustin Pop
  try:
1931 a4af651e Iustin Pop
    result = func(options, args)
1932 d8353c3a Iustin Pop
  except (errors.GenericError, luxi.ProtocolError,
1933 d8353c3a Iustin Pop
          JobSubmittedException), err:
1934 a4af651e Iustin Pop
    result, err_msg = FormatError(err)
1935 5bbd3f7f Michael Hanselmann
    logging.exception("Error during command processing")
1936 46fbdd04 Iustin Pop
    ToStderr(err_msg)
1937 8a53b55f Iustin Pop
  except KeyboardInterrupt:
1938 8a53b55f Iustin Pop
    result = constants.EXIT_FAILURE
1939 8a53b55f Iustin Pop
    ToStderr("Aborted. Note that if the operation created any jobs, they"
1940 8a53b55f Iustin Pop
             " might have been submitted and"
1941 8a53b55f Iustin Pop
             " will continue to run in the background.")
1942 a8083063 Iustin Pop
1943 a8083063 Iustin Pop
  return result
1944 137161c9 Michael Hanselmann
1945 137161c9 Michael Hanselmann
1946 845c79d8 Michael Hanselmann
def ParseNicOption(optvalue):
1947 845c79d8 Michael Hanselmann
  """Parses the value of the --net option(s).
1948 845c79d8 Michael Hanselmann

1949 845c79d8 Michael Hanselmann
  """
1950 845c79d8 Michael Hanselmann
  try:
1951 845c79d8 Michael Hanselmann
    nic_max = max(int(nidx[0]) + 1 for nidx in optvalue)
1952 845c79d8 Michael Hanselmann
  except (TypeError, ValueError), err:
1953 845c79d8 Michael Hanselmann
    raise errors.OpPrereqError("Invalid NIC index passed: %s" % str(err))
1954 845c79d8 Michael Hanselmann
1955 845c79d8 Michael Hanselmann
  nics = [{}] * nic_max
1956 845c79d8 Michael Hanselmann
  for nidx, ndict in optvalue:
1957 845c79d8 Michael Hanselmann
    nidx = int(nidx)
1958 845c79d8 Michael Hanselmann
1959 845c79d8 Michael Hanselmann
    if not isinstance(ndict, dict):
1960 845c79d8 Michael Hanselmann
      raise errors.OpPrereqError("Invalid nic/%d value: expected dict,"
1961 845c79d8 Michael Hanselmann
                                 " got %s" % (nidx, ndict))
1962 845c79d8 Michael Hanselmann
1963 845c79d8 Michael Hanselmann
    utils.ForceDictType(ndict, constants.INIC_PARAMS_TYPES)
1964 845c79d8 Michael Hanselmann
1965 845c79d8 Michael Hanselmann
    nics[nidx] = ndict
1966 845c79d8 Michael Hanselmann
1967 845c79d8 Michael Hanselmann
  return nics
1968 845c79d8 Michael Hanselmann
1969 845c79d8 Michael Hanselmann
1970 d77490c5 Iustin Pop
def GenericInstanceCreate(mode, opts, args):
1971 d77490c5 Iustin Pop
  """Add an instance to the cluster via either creation or import.
1972 d77490c5 Iustin Pop

1973 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
1974 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
1975 d77490c5 Iustin Pop
  @type args: list
1976 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
1977 d77490c5 Iustin Pop
  @rtype: int
1978 d77490c5 Iustin Pop
  @return: the desired exit code
1979 d77490c5 Iustin Pop

1980 d77490c5 Iustin Pop
  """
1981 d77490c5 Iustin Pop
  instance = args[0]
1982 d77490c5 Iustin Pop
1983 d77490c5 Iustin Pop
  (pnode, snode) = SplitNodeOption(opts.node)
1984 d77490c5 Iustin Pop
1985 d77490c5 Iustin Pop
  hypervisor = None
1986 d77490c5 Iustin Pop
  hvparams = {}
1987 d77490c5 Iustin Pop
  if opts.hypervisor:
1988 d77490c5 Iustin Pop
    hypervisor, hvparams = opts.hypervisor
1989 d77490c5 Iustin Pop
1990 d77490c5 Iustin Pop
  if opts.nics:
1991 845c79d8 Michael Hanselmann
    nics = ParseNicOption(opts.nics)
1992 d77490c5 Iustin Pop
  elif opts.no_nics:
1993 d77490c5 Iustin Pop
    # no nics
1994 d77490c5 Iustin Pop
    nics = []
1995 0af0f641 Iustin Pop
  elif mode == constants.INSTANCE_CREATE:
1996 d77490c5 Iustin Pop
    # default of one nic, all auto
1997 d77490c5 Iustin Pop
    nics = [{}]
1998 0af0f641 Iustin Pop
  else:
1999 0af0f641 Iustin Pop
    # mode == import
2000 0af0f641 Iustin Pop
    nics = []
2001 d77490c5 Iustin Pop
2002 d77490c5 Iustin Pop
  if opts.disk_template == constants.DT_DISKLESS:
2003 d77490c5 Iustin Pop
    if opts.disks or opts.sd_size is not None:
2004 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Diskless instance but disk"
2005 d77490c5 Iustin Pop
                                 " information passed")
2006 d77490c5 Iustin Pop
    disks = []
2007 d77490c5 Iustin Pop
  else:
2008 9b12ed0f Iustin Pop
    if (not opts.disks and not opts.sd_size
2009 9b12ed0f Iustin Pop
        and mode == constants.INSTANCE_CREATE):
2010 d77490c5 Iustin Pop
      raise errors.OpPrereqError("No disk information specified")
2011 d77490c5 Iustin Pop
    if opts.disks and opts.sd_size is not None:
2012 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Please use either the '--disk' or"
2013 d77490c5 Iustin Pop
                                 " '-s' option")
2014 d77490c5 Iustin Pop
    if opts.sd_size is not None:
2015 d77490c5 Iustin Pop
      opts.disks = [(0, {"size": opts.sd_size})]
2016 9b12ed0f Iustin Pop
2017 9b12ed0f Iustin Pop
    if opts.disks:
2018 9b12ed0f Iustin Pop
      try:
2019 9b12ed0f Iustin Pop
        disk_max = max(int(didx[0]) + 1 for didx in opts.disks)
2020 9b12ed0f Iustin Pop
      except ValueError, err:
2021 9b12ed0f Iustin Pop
        raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err))
2022 9b12ed0f Iustin Pop
      disks = [{}] * disk_max
2023 9b12ed0f Iustin Pop
    else:
2024 9b12ed0f Iustin Pop
      disks = []
2025 d77490c5 Iustin Pop
    for didx, ddict in opts.disks:
2026 d77490c5 Iustin Pop
      didx = int(didx)
2027 d77490c5 Iustin Pop
      if not isinstance(ddict, dict):
2028 d77490c5 Iustin Pop
        msg = "Invalid disk/%d value: expected dict, got %s" % (didx, ddict)
2029 d77490c5 Iustin Pop
        raise errors.OpPrereqError(msg)
2030 5029db65 Iustin Pop
      elif "size" in ddict:
2031 5029db65 Iustin Pop
        if "adopt" in ddict:
2032 5029db65 Iustin Pop
          raise errors.OpPrereqError("Only one of 'size' and 'adopt' allowed"
2033 5029db65 Iustin Pop
                                     " (disk %d)" % didx)
2034 5029db65 Iustin Pop
        try:
2035 5029db65 Iustin Pop
          ddict["size"] = utils.ParseUnit(ddict["size"])
2036 5029db65 Iustin Pop
        except ValueError, err:
2037 5029db65 Iustin Pop
          raise errors.OpPrereqError("Invalid disk size for disk %d: %s" %
2038 5029db65 Iustin Pop
                                     (didx, err))
2039 5029db65 Iustin Pop
      elif "adopt" in ddict:
2040 5029db65 Iustin Pop
        if mode == constants.INSTANCE_IMPORT:
2041 5029db65 Iustin Pop
          raise errors.OpPrereqError("Disk adoption not allowed for instance"
2042 5029db65 Iustin Pop
                                     " import")
2043 5029db65 Iustin Pop
        ddict["size"] = 0
2044 5029db65 Iustin Pop
      else:
2045 5029db65 Iustin Pop
        raise errors.OpPrereqError("Missing size or adoption source for"
2046 5029db65 Iustin Pop
                                   " disk %d" % didx)
2047 d77490c5 Iustin Pop
      disks[didx] = ddict
2048 d77490c5 Iustin Pop
2049 d77490c5 Iustin Pop
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_TYPES)
2050 d77490c5 Iustin Pop
  utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
2051 d77490c5 Iustin Pop
2052 d77490c5 Iustin Pop
  if mode == constants.INSTANCE_CREATE:
2053 d77490c5 Iustin Pop
    start = opts.start
2054 d77490c5 Iustin Pop
    os_type = opts.os
2055 1ee8e01a Guido Trotter
    force_variant = opts.force_variant
2056 d77490c5 Iustin Pop
    src_node = None
2057 d77490c5 Iustin Pop
    src_path = None
2058 25a8792c Iustin Pop
    no_install = opts.no_install
2059 e588764d Iustin Pop
    identify_defaults = False
2060 d77490c5 Iustin Pop
  elif mode == constants.INSTANCE_IMPORT:
2061 d77490c5 Iustin Pop
    start = False
2062 d77490c5 Iustin Pop
    os_type = None
2063 1ee8e01a Guido Trotter
    force_variant = False
2064 d77490c5 Iustin Pop
    src_node = opts.src_node
2065 d77490c5 Iustin Pop
    src_path = opts.src_dir
2066 25a8792c Iustin Pop
    no_install = None
2067 e588764d Iustin Pop
    identify_defaults = opts.identify_defaults
2068 d77490c5 Iustin Pop
  else:
2069 d77490c5 Iustin Pop
    raise errors.ProgrammerError("Invalid creation mode %s" % mode)
2070 d77490c5 Iustin Pop
2071 e1530b10 Iustin Pop
  op = opcodes.OpInstanceCreate(instance_name=instance,
2072 d77490c5 Iustin Pop
                                disks=disks,
2073 d77490c5 Iustin Pop
                                disk_template=opts.disk_template,
2074 d77490c5 Iustin Pop
                                nics=nics,
2075 d77490c5 Iustin Pop
                                pnode=pnode, snode=snode,
2076 d77490c5 Iustin Pop
                                ip_check=opts.ip_check,
2077 460d22be Iustin Pop
                                name_check=opts.name_check,
2078 d77490c5 Iustin Pop
                                wait_for_sync=opts.wait_for_sync,
2079 d77490c5 Iustin Pop
                                file_storage_dir=opts.file_storage_dir,
2080 d77490c5 Iustin Pop
                                file_driver=opts.file_driver,
2081 d77490c5 Iustin Pop
                                iallocator=opts.iallocator,
2082 d77490c5 Iustin Pop
                                hypervisor=hypervisor,
2083 d77490c5 Iustin Pop
                                hvparams=hvparams,
2084 d77490c5 Iustin Pop
                                beparams=opts.beparams,
2085 062a7100 Iustin Pop
                                osparams=opts.osparams,
2086 d77490c5 Iustin Pop
                                mode=mode,
2087 d77490c5 Iustin Pop
                                start=start,
2088 d77490c5 Iustin Pop
                                os_type=os_type,
2089 1ee8e01a Guido Trotter
                                force_variant=force_variant,
2090 d77490c5 Iustin Pop
                                src_node=src_node,
2091 25a8792c Iustin Pop
                                src_path=src_path,
2092 e588764d Iustin Pop
                                no_install=no_install,
2093 e588764d Iustin Pop
                                identify_defaults=identify_defaults)
2094 d77490c5 Iustin Pop
2095 d77490c5 Iustin Pop
  SubmitOrSend(op, opts)
2096 d77490c5 Iustin Pop
  return 0
2097 d77490c5 Iustin Pop
2098 d77490c5 Iustin Pop
2099 7e49b6ce Michael Hanselmann
class _RunWhileClusterStoppedHelper:
2100 7e49b6ce Michael Hanselmann
  """Helper class for L{RunWhileClusterStopped} to simplify state management
2101 7e49b6ce Michael Hanselmann

2102 7e49b6ce Michael Hanselmann
  """
2103 7e49b6ce Michael Hanselmann
  def __init__(self, feedback_fn, cluster_name, master_node, online_nodes):
2104 7e49b6ce Michael Hanselmann
    """Initializes this class.
2105 7e49b6ce Michael Hanselmann

2106 7e49b6ce Michael Hanselmann
    @type feedback_fn: callable
2107 7e49b6ce Michael Hanselmann
    @param feedback_fn: Feedback function
2108 7e49b6ce Michael Hanselmann
    @type cluster_name: string
2109 7e49b6ce Michael Hanselmann
    @param cluster_name: Cluster name
2110 7e49b6ce Michael Hanselmann
    @type master_node: string
2111 7e49b6ce Michael Hanselmann
    @param master_node Master node name
2112 7e49b6ce Michael Hanselmann
    @type online_nodes: list
2113 7e49b6ce Michael Hanselmann
    @param online_nodes: List of names of online nodes
2114 7e49b6ce Michael Hanselmann

2115 7e49b6ce Michael Hanselmann
    """
2116 7e49b6ce Michael Hanselmann
    self.feedback_fn = feedback_fn
2117 7e49b6ce Michael Hanselmann
    self.cluster_name = cluster_name
2118 7e49b6ce Michael Hanselmann
    self.master_node = master_node
2119 7e49b6ce Michael Hanselmann
    self.online_nodes = online_nodes
2120 7e49b6ce Michael Hanselmann
2121 7e49b6ce Michael Hanselmann
    self.ssh = ssh.SshRunner(self.cluster_name)
2122 7e49b6ce Michael Hanselmann
2123 7e49b6ce Michael Hanselmann
    self.nonmaster_nodes = [name for name in online_nodes
2124 7e49b6ce Michael Hanselmann
                            if name != master_node]
2125 7e49b6ce Michael Hanselmann
2126 7e49b6ce Michael Hanselmann
    assert self.master_node not in self.nonmaster_nodes
2127 7e49b6ce Michael Hanselmann
2128 7e49b6ce Michael Hanselmann
  def _RunCmd(self, node_name, cmd):
2129 7e49b6ce Michael Hanselmann
    """Runs a command on the local or a remote machine.
2130 7e49b6ce Michael Hanselmann

2131 7e49b6ce Michael Hanselmann
    @type node_name: string
2132 7e49b6ce Michael Hanselmann
    @param node_name: Machine name
2133 7e49b6ce Michael Hanselmann
    @type cmd: list
2134 7e49b6ce Michael Hanselmann
    @param cmd: Command
2135 7e49b6ce Michael Hanselmann

2136 7e49b6ce Michael Hanselmann
    """
2137 7e49b6ce Michael Hanselmann
    if node_name is None or node_name == self.master_node:
2138 7e49b6ce Michael Hanselmann
      # No need to use SSH
2139 7e49b6ce Michael Hanselmann
      result = utils.RunCmd(cmd)
2140 7e49b6ce Michael Hanselmann
    else:
2141 7e49b6ce Michael Hanselmann
      result = self.ssh.Run(node_name, "root", utils.ShellQuoteArgs(cmd))
2142 7e49b6ce Michael Hanselmann
2143 7e49b6ce Michael Hanselmann
    if result.failed:
2144 7e49b6ce Michael Hanselmann
      errmsg = ["Failed to run command %s" % result.cmd]
2145 7e49b6ce Michael Hanselmann
      if node_name:
2146 7e49b6ce Michael Hanselmann
        errmsg.append("on node %s" % node_name)
2147 7e49b6ce Michael Hanselmann
      errmsg.append(": exitcode %s and error %s" %
2148 7e49b6ce Michael Hanselmann
                    (result.exit_code, result.output))
2149 7e49b6ce Michael Hanselmann
      raise errors.OpExecError(" ".join(errmsg))
2150 7e49b6ce Michael Hanselmann
2151 7e49b6ce Michael Hanselmann
  def Call(self, fn, *args):
2152 7e49b6ce Michael Hanselmann
    """Call function while all daemons are stopped.
2153 7e49b6ce Michael Hanselmann

2154 7e49b6ce Michael Hanselmann
    @type fn: callable
2155 7e49b6ce Michael Hanselmann
    @param fn: Function to be called
2156 7e49b6ce Michael Hanselmann

2157 7e49b6ce Michael Hanselmann
    """
2158 7e49b6ce Michael Hanselmann
    # Pause watcher by acquiring an exclusive lock on watcher state file
2159 7e49b6ce Michael Hanselmann
    self.feedback_fn("Blocking watcher")
2160 7e49b6ce Michael Hanselmann
    watcher_block = utils.FileLock.Open(constants.WATCHER_STATEFILE)
2161 7e49b6ce Michael Hanselmann
    try:
2162 7e49b6ce Michael Hanselmann
      # TODO: Currently, this just blocks. There's no timeout.
2163 7e49b6ce Michael Hanselmann
      # TODO: Should it be a shared lock?
2164 7e49b6ce Michael Hanselmann
      watcher_block.Exclusive(blocking=True)
2165 7e49b6ce Michael Hanselmann
2166 7e49b6ce Michael Hanselmann
      # Stop master daemons, so that no new jobs can come in and all running
2167 7e49b6ce Michael Hanselmann
      # ones are finished
2168 7e49b6ce Michael Hanselmann
      self.feedback_fn("Stopping master daemons")
2169 7e49b6ce Michael Hanselmann
      self._RunCmd(None, [constants.DAEMON_UTIL, "stop-master"])
2170 7e49b6ce Michael Hanselmann
      try:
2171 7e49b6ce Michael Hanselmann
        # Stop daemons on all nodes
2172 7e49b6ce Michael Hanselmann
        for node_name in self.online_nodes:
2173 7e49b6ce Michael Hanselmann
          self.feedback_fn("Stopping daemons on %s" % node_name)
2174 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "stop-all"])
2175 7e49b6ce Michael Hanselmann
2176 7e49b6ce Michael Hanselmann
        # All daemons are shut down now
2177 7e49b6ce Michael Hanselmann
        try:
2178 7e49b6ce Michael Hanselmann
          return fn(self, *args)
2179 d512e84b Michael Hanselmann
        except Exception, err:
2180 d512e84b Michael Hanselmann
          _, errmsg = FormatError(err)
2181 7e49b6ce Michael Hanselmann
          logging.exception("Caught exception")
2182 d512e84b Michael Hanselmann
          self.feedback_fn(errmsg)
2183 7e49b6ce Michael Hanselmann
          raise
2184 7e49b6ce Michael Hanselmann
      finally:
2185 7e49b6ce Michael Hanselmann
        # Start cluster again, master node last
2186 7e49b6ce Michael Hanselmann
        for node_name in self.nonmaster_nodes + [self.master_node]:
2187 7e49b6ce Michael Hanselmann
          self.feedback_fn("Starting daemons on %s" % node_name)
2188 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "start-all"])
2189 7e49b6ce Michael Hanselmann
    finally:
2190 7e49b6ce Michael Hanselmann
      # Resume watcher
2191 7e49b6ce Michael Hanselmann
      watcher_block.Close()
2192 7e49b6ce Michael Hanselmann
2193 7e49b6ce Michael Hanselmann
2194 7e49b6ce Michael Hanselmann
def RunWhileClusterStopped(feedback_fn, fn, *args):
2195 7e49b6ce Michael Hanselmann
  """Calls a function while all cluster daemons are stopped.
2196 7e49b6ce Michael Hanselmann

2197 7e49b6ce Michael Hanselmann
  @type feedback_fn: callable
2198 7e49b6ce Michael Hanselmann
  @param feedback_fn: Feedback function
2199 7e49b6ce Michael Hanselmann
  @type fn: callable
2200 7e49b6ce Michael Hanselmann
  @param fn: Function to be called when daemons are stopped
2201 7e49b6ce Michael Hanselmann

2202 7e49b6ce Michael Hanselmann
  """
2203 7e49b6ce Michael Hanselmann
  feedback_fn("Gathering cluster information")
2204 7e49b6ce Michael Hanselmann
2205 7e49b6ce Michael Hanselmann
  # This ensures we're running on the master daemon
2206 7e49b6ce Michael Hanselmann
  cl = GetClient()
2207 7e49b6ce Michael Hanselmann
2208 7e49b6ce Michael Hanselmann
  (cluster_name, master_node) = \
2209 7e49b6ce Michael Hanselmann
    cl.QueryConfigValues(["cluster_name", "master_node"])
2210 7e49b6ce Michael Hanselmann
2211 7e49b6ce Michael Hanselmann
  online_nodes = GetOnlineNodes([], cl=cl)
2212 7e49b6ce Michael Hanselmann
2213 7e49b6ce Michael Hanselmann
  # Don't keep a reference to the client. The master daemon will go away.
2214 7e49b6ce Michael Hanselmann
  del cl
2215 7e49b6ce Michael Hanselmann
2216 7e49b6ce Michael Hanselmann
  assert master_node in online_nodes
2217 7e49b6ce Michael Hanselmann
2218 7e49b6ce Michael Hanselmann
  return _RunWhileClusterStoppedHelper(feedback_fn, cluster_name, master_node,
2219 7e49b6ce Michael Hanselmann
                                       online_nodes).Call(fn, *args)
2220 7e49b6ce Michael Hanselmann
2221 7e49b6ce Michael Hanselmann
2222 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
2223 9fbfbb7b Iustin Pop
                  numfields=None, unitfields=None,
2224 9fbfbb7b Iustin Pop
                  units=None):
2225 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
2226 137161c9 Michael Hanselmann

2227 9fbfbb7b Iustin Pop
  @type headers: dict
2228 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
2229 9fbfbb7b Iustin Pop
      the table
2230 9fbfbb7b Iustin Pop
  @type fields: list
2231 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
2232 9fbfbb7b Iustin Pop
      the data field
2233 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
2234 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
2235 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
2236 9fbfbb7b Iustin Pop
      each field
2237 9fbfbb7b Iustin Pop
  @type data: list
2238 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
2239 9fbfbb7b Iustin Pop
  @type numfields: list
2240 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
2241 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
2242 9fbfbb7b Iustin Pop
  @type unitfields: list
2243 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
2244 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
2245 9fbfbb7b Iustin Pop
  @type units: string or None
2246 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
2247 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
2248 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
2249 137161c9 Michael Hanselmann

2250 137161c9 Michael Hanselmann
  """
2251 9fbfbb7b Iustin Pop
  if units is None:
2252 9fbfbb7b Iustin Pop
    if separator:
2253 9fbfbb7b Iustin Pop
      units = "m"
2254 9fbfbb7b Iustin Pop
    else:
2255 9fbfbb7b Iustin Pop
      units = "h"
2256 9fbfbb7b Iustin Pop
2257 137161c9 Michael Hanselmann
  if numfields is None:
2258 137161c9 Michael Hanselmann
    numfields = []
2259 137161c9 Michael Hanselmann
  if unitfields is None:
2260 137161c9 Michael Hanselmann
    unitfields = []
2261 137161c9 Michael Hanselmann
2262 fe267188 Iustin Pop
  numfields = utils.FieldSet(*numfields)   # pylint: disable-msg=W0142
2263 fe267188 Iustin Pop
  unitfields = utils.FieldSet(*unitfields) # pylint: disable-msg=W0142
2264 00430f8e Iustin Pop
2265 137161c9 Michael Hanselmann
  format_fields = []
2266 137161c9 Michael Hanselmann
  for field in fields:
2267 01ca31ae Iustin Pop
    if headers and field not in headers:
2268 ea5a5b74 Guido Trotter
      # TODO: handle better unknown fields (either revert to old
2269 71c1af58 Iustin Pop
      # style of raising exception, or deal more intelligently with
2270 71c1af58 Iustin Pop
      # variable fields)
2271 71c1af58 Iustin Pop
      headers[field] = field
2272 137161c9 Michael Hanselmann
    if separator is not None:
2273 137161c9 Michael Hanselmann
      format_fields.append("%s")
2274 00430f8e Iustin Pop
    elif numfields.Matches(field):
2275 137161c9 Michael Hanselmann
      format_fields.append("%*s")
2276 137161c9 Michael Hanselmann
    else:
2277 137161c9 Michael Hanselmann
      format_fields.append("%-*s")
2278 137161c9 Michael Hanselmann
2279 137161c9 Michael Hanselmann
  if separator is None:
2280 137161c9 Michael Hanselmann
    mlens = [0 for name in fields]
2281 c04bc777 Iustin Pop
    format_str = ' '.join(format_fields)
2282 137161c9 Michael Hanselmann
  else:
2283 c04bc777 Iustin Pop
    format_str = separator.replace("%", "%%").join(format_fields)
2284 137161c9 Michael Hanselmann
2285 137161c9 Michael Hanselmann
  for row in data:
2286 dcbd6288 Guido Trotter
    if row is None:
2287 dcbd6288 Guido Trotter
      continue
2288 137161c9 Michael Hanselmann
    for idx, val in enumerate(row):
2289 00430f8e Iustin Pop
      if unitfields.Matches(fields[idx]):
2290 137161c9 Michael Hanselmann
        try:
2291 137161c9 Michael Hanselmann
          val = int(val)
2292 691744c4 Iustin Pop
        except (TypeError, ValueError):
2293 137161c9 Michael Hanselmann
          pass
2294 137161c9 Michael Hanselmann
        else:
2295 9fbfbb7b Iustin Pop
          val = row[idx] = utils.FormatUnit(val, units)
2296 01ca31ae Iustin Pop
      val = row[idx] = str(val)
2297 137161c9 Michael Hanselmann
      if separator is None:
2298 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(val))
2299 137161c9 Michael Hanselmann
2300 16be8703 Iustin Pop
  result = []
2301 137161c9 Michael Hanselmann
  if headers:
2302 137161c9 Michael Hanselmann
    args = []
2303 137161c9 Michael Hanselmann
    for idx, name in enumerate(fields):
2304 137161c9 Michael Hanselmann
      hdr = headers[name]
2305 137161c9 Michael Hanselmann
      if separator is None:
2306 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(hdr))
2307 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2308 137161c9 Michael Hanselmann
      args.append(hdr)
2309 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2310 137161c9 Michael Hanselmann
2311 ec39d63c Michael Hanselmann
  if separator is None:
2312 ec39d63c Michael Hanselmann
    assert len(mlens) == len(fields)
2313 ec39d63c Michael Hanselmann
2314 ec39d63c Michael Hanselmann
    if fields and not numfields.Matches(fields[-1]):
2315 ec39d63c Michael Hanselmann
      mlens[-1] = 0
2316 ec39d63c Michael Hanselmann
2317 137161c9 Michael Hanselmann
  for line in data:
2318 137161c9 Michael Hanselmann
    args = []
2319 dcbd6288 Guido Trotter
    if line is None:
2320 dcbd6288 Guido Trotter
      line = ['-' for _ in fields]
2321 f1501b3f Michael Hanselmann
    for idx in range(len(fields)):
2322 137161c9 Michael Hanselmann
      if separator is None:
2323 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2324 137161c9 Michael Hanselmann
      args.append(line[idx])
2325 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2326 16be8703 Iustin Pop
2327 16be8703 Iustin Pop
  return result
2328 3386e7a9 Iustin Pop
2329 3386e7a9 Iustin Pop
2330 ee3aedff Michael Hanselmann
def _FormatBool(value):
2331 ee3aedff Michael Hanselmann
  """Formats a boolean value as a string.
2332 ee3aedff Michael Hanselmann

2333 ee3aedff Michael Hanselmann
  """
2334 ee3aedff Michael Hanselmann
  if value:
2335 ee3aedff Michael Hanselmann
    return "Y"
2336 ee3aedff Michael Hanselmann
  return "N"
2337 ee3aedff Michael Hanselmann
2338 ee3aedff Michael Hanselmann
2339 ee3aedff Michael Hanselmann
#: Default formatting for query results; (callback, align right)
2340 ee3aedff Michael Hanselmann
_DEFAULT_FORMAT_QUERY = {
2341 ee3aedff Michael Hanselmann
  constants.QFT_TEXT: (str, False),
2342 ee3aedff Michael Hanselmann
  constants.QFT_BOOL: (_FormatBool, False),
2343 ee3aedff Michael Hanselmann
  constants.QFT_NUMBER: (str, True),
2344 ee3aedff Michael Hanselmann
  constants.QFT_TIMESTAMP: (utils.FormatTime, False),
2345 ee3aedff Michael Hanselmann
  constants.QFT_OTHER: (str, False),
2346 ee3aedff Michael Hanselmann
  constants.QFT_UNKNOWN: (str, False),
2347 ee3aedff Michael Hanselmann
  }
2348 ee3aedff Michael Hanselmann
2349 ee3aedff Michael Hanselmann
2350 ee3aedff Michael Hanselmann
def _GetColumnFormatter(fdef, override, unit):
2351 ee3aedff Michael Hanselmann
  """Returns formatting function for a field.
2352 ee3aedff Michael Hanselmann

2353 ee3aedff Michael Hanselmann
  @type fdef: L{objects.QueryFieldDefinition}
2354 ee3aedff Michael Hanselmann
  @type override: dict
2355 ee3aedff Michael Hanselmann
  @param override: Dictionary for overriding field formatting functions,
2356 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2357 ee3aedff Michael Hanselmann
  @type unit: string
2358 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT}
2359 ee3aedff Michael Hanselmann
  @rtype: tuple; (callable, bool)
2360 ee3aedff Michael Hanselmann
  @return: Returns the function to format a value (takes one parameter) and a
2361 ee3aedff Michael Hanselmann
    boolean for aligning the value on the right-hand side
2362 ee3aedff Michael Hanselmann

2363 ee3aedff Michael Hanselmann
  """
2364 ee3aedff Michael Hanselmann
  fmt = override.get(fdef.name, None)
2365 ee3aedff Michael Hanselmann
  if fmt is not None:
2366 ee3aedff Michael Hanselmann
    return fmt
2367 ee3aedff Michael Hanselmann
2368 ee3aedff Michael Hanselmann
  assert constants.QFT_UNIT not in _DEFAULT_FORMAT_QUERY
2369 ee3aedff Michael Hanselmann
2370 ee3aedff Michael Hanselmann
  if fdef.kind == constants.QFT_UNIT:
2371 ee3aedff Michael Hanselmann
    # Can't keep this information in the static dictionary
2372 ee3aedff Michael Hanselmann
    return (lambda value: utils.FormatUnit(value, unit), True)
2373 ee3aedff Michael Hanselmann
2374 ee3aedff Michael Hanselmann
  fmt = _DEFAULT_FORMAT_QUERY.get(fdef.kind, None)
2375 ee3aedff Michael Hanselmann
  if fmt is not None:
2376 ee3aedff Michael Hanselmann
    return fmt
2377 ee3aedff Michael Hanselmann
2378 ee3aedff Michael Hanselmann
  raise NotImplementedError("Can't format column type '%s'" % fdef.kind)
2379 ee3aedff Michael Hanselmann
2380 ee3aedff Michael Hanselmann
2381 ee3aedff Michael Hanselmann
class _QueryColumnFormatter:
2382 ee3aedff Michael Hanselmann
  """Callable class for formatting fields of a query.
2383 ee3aedff Michael Hanselmann

2384 ee3aedff Michael Hanselmann
  """
2385 f0b1bafe Iustin Pop
  def __init__(self, fn, status_fn, verbose):
2386 ee3aedff Michael Hanselmann
    """Initializes this class.
2387 ee3aedff Michael Hanselmann

2388 ee3aedff Michael Hanselmann
    @type fn: callable
2389 ee3aedff Michael Hanselmann
    @param fn: Formatting function
2390 ee3aedff Michael Hanselmann
    @type status_fn: callable
2391 ee3aedff Michael Hanselmann
    @param status_fn: Function to report fields' status
2392 f0b1bafe Iustin Pop
    @type verbose: boolean
2393 f0b1bafe Iustin Pop
    @param verbose: whether to use verbose field descriptions or not
2394 ee3aedff Michael Hanselmann

2395 ee3aedff Michael Hanselmann
    """
2396 ee3aedff Michael Hanselmann
    self._fn = fn
2397 ee3aedff Michael Hanselmann
    self._status_fn = status_fn
2398 f0b1bafe Iustin Pop
    if verbose:
2399 f0b1bafe Iustin Pop
      self._desc_index = 0
2400 f0b1bafe Iustin Pop
    else:
2401 f0b1bafe Iustin Pop
      self._desc_index = 1
2402 ee3aedff Michael Hanselmann
2403 ee3aedff Michael Hanselmann
  def __call__(self, data):
2404 ee3aedff Michael Hanselmann
    """Returns a field's string representation.
2405 ee3aedff Michael Hanselmann

2406 ee3aedff Michael Hanselmann
    """
2407 ee3aedff Michael Hanselmann
    (status, value) = data
2408 ee3aedff Michael Hanselmann
2409 ee3aedff Michael Hanselmann
    # Report status
2410 ee3aedff Michael Hanselmann
    self._status_fn(status)
2411 ee3aedff Michael Hanselmann
2412 cfb084ae René Nussbaumer
    if status == constants.RS_NORMAL:
2413 ee3aedff Michael Hanselmann
      return self._fn(value)
2414 ee3aedff Michael Hanselmann
2415 ee3aedff Michael Hanselmann
    assert value is None, \
2416 ee3aedff Michael Hanselmann
           "Found value %r for abnormal status %s" % (value, status)
2417 ee3aedff Michael Hanselmann
2418 f0b1bafe Iustin Pop
    if status in constants.RSS_DESCRIPTION:
2419 f0b1bafe Iustin Pop
      return constants.RSS_DESCRIPTION[status][self._desc_index]
2420 a6070ef7 Michael Hanselmann
2421 ee3aedff Michael Hanselmann
    raise NotImplementedError("Unknown status %s" % status)
2422 ee3aedff Michael Hanselmann
2423 ee3aedff Michael Hanselmann
2424 ee3aedff Michael Hanselmann
def FormatQueryResult(result, unit=None, format_override=None, separator=None,
2425 f0b1bafe Iustin Pop
                      header=False, verbose=False):
2426 ee3aedff Michael Hanselmann
  """Formats data in L{objects.QueryResponse}.
2427 ee3aedff Michael Hanselmann

2428 ee3aedff Michael Hanselmann
  @type result: L{objects.QueryResponse}
2429 ee3aedff Michael Hanselmann
  @param result: result of query operation
2430 ee3aedff Michael Hanselmann
  @type unit: string
2431 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT},
2432 18009c1e Iustin Pop
    see L{utils.text.FormatUnit}
2433 ee3aedff Michael Hanselmann
  @type format_override: dict
2434 ee3aedff Michael Hanselmann
  @param format_override: Dictionary for overriding field formatting functions,
2435 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2436 ee3aedff Michael Hanselmann
  @type separator: string or None
2437 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2438 ee3aedff Michael Hanselmann
  @type header: bool
2439 ee3aedff Michael Hanselmann
  @param header: Whether to output header row
2440 f0b1bafe Iustin Pop
  @type verbose: boolean
2441 f0b1bafe Iustin Pop
  @param verbose: whether to use verbose field descriptions or not
2442 ee3aedff Michael Hanselmann

2443 ee3aedff Michael Hanselmann
  """
2444 ee3aedff Michael Hanselmann
  if unit is None:
2445 ee3aedff Michael Hanselmann
    if separator:
2446 ee3aedff Michael Hanselmann
      unit = "m"
2447 ee3aedff Michael Hanselmann
    else:
2448 ee3aedff Michael Hanselmann
      unit = "h"
2449 ee3aedff Michael Hanselmann
2450 ee3aedff Michael Hanselmann
  if format_override is None:
2451 ee3aedff Michael Hanselmann
    format_override = {}
2452 ee3aedff Michael Hanselmann
2453 cfb084ae René Nussbaumer
  stats = dict.fromkeys(constants.RS_ALL, 0)
2454 ee3aedff Michael Hanselmann
2455 ee3aedff Michael Hanselmann
  def _RecordStatus(status):
2456 ee3aedff Michael Hanselmann
    if status in stats:
2457 ee3aedff Michael Hanselmann
      stats[status] += 1
2458 ee3aedff Michael Hanselmann
2459 ee3aedff Michael Hanselmann
  columns = []
2460 ee3aedff Michael Hanselmann
  for fdef in result.fields:
2461 ee3aedff Michael Hanselmann
    assert fdef.title and fdef.name
2462 ee3aedff Michael Hanselmann
    (fn, align_right) = _GetColumnFormatter(fdef, format_override, unit)
2463 ee3aedff Michael Hanselmann
    columns.append(TableColumn(fdef.title,
2464 f0b1bafe Iustin Pop
                               _QueryColumnFormatter(fn, _RecordStatus,
2465 f0b1bafe Iustin Pop
                                                     verbose),
2466 ee3aedff Michael Hanselmann
                               align_right))
2467 ee3aedff Michael Hanselmann
2468 ee3aedff Michael Hanselmann
  table = FormatTable(result.data, columns, header, separator)
2469 ee3aedff Michael Hanselmann
2470 ee3aedff Michael Hanselmann
  # Collect statistics
2471 cfb084ae René Nussbaumer
  assert len(stats) == len(constants.RS_ALL)
2472 ee3aedff Michael Hanselmann
  assert compat.all(count >= 0 for count in stats.values())
2473 ee3aedff Michael Hanselmann
2474 ee3aedff Michael Hanselmann
  # Determine overall status. If there was no data, unknown fields must be
2475 ee3aedff Michael Hanselmann
  # detected via the field definitions.
2476 cfb084ae René Nussbaumer
  if (stats[constants.RS_UNKNOWN] or
2477 ee3aedff Michael Hanselmann
      (not result.data and _GetUnknownFields(result.fields))):
2478 ee3aedff Michael Hanselmann
    status = QR_UNKNOWN
2479 ee3aedff Michael Hanselmann
  elif compat.any(count > 0 for key, count in stats.items()
2480 cfb084ae René Nussbaumer
                  if key != constants.RS_NORMAL):
2481 ee3aedff Michael Hanselmann
    status = QR_INCOMPLETE
2482 ee3aedff Michael Hanselmann
  else:
2483 ee3aedff Michael Hanselmann
    status = QR_NORMAL
2484 ee3aedff Michael Hanselmann
2485 ee3aedff Michael Hanselmann
  return (status, table)
2486 ee3aedff Michael Hanselmann
2487 ee3aedff Michael Hanselmann
2488 ee3aedff Michael Hanselmann
def _GetUnknownFields(fdefs):
2489 ee3aedff Michael Hanselmann
  """Returns list of unknown fields included in C{fdefs}.
2490 ee3aedff Michael Hanselmann

2491 ee3aedff Michael Hanselmann
  @type fdefs: list of L{objects.QueryFieldDefinition}
2492 ee3aedff Michael Hanselmann

2493 ee3aedff Michael Hanselmann
  """
2494 ee3aedff Michael Hanselmann
  return [fdef for fdef in fdefs
2495 ee3aedff Michael Hanselmann
          if fdef.kind == constants.QFT_UNKNOWN]
2496 ee3aedff Michael Hanselmann
2497 ee3aedff Michael Hanselmann
2498 ee3aedff Michael Hanselmann
def _WarnUnknownFields(fdefs):
2499 ee3aedff Michael Hanselmann
  """Prints a warning to stderr if a query included unknown fields.
2500 ee3aedff Michael Hanselmann

2501 ee3aedff Michael Hanselmann
  @type fdefs: list of L{objects.QueryFieldDefinition}
2502 ee3aedff Michael Hanselmann

2503 ee3aedff Michael Hanselmann
  """
2504 ee3aedff Michael Hanselmann
  unknown = _GetUnknownFields(fdefs)
2505 ee3aedff Michael Hanselmann
  if unknown:
2506 ee3aedff Michael Hanselmann
    ToStderr("Warning: Queried for unknown fields %s",
2507 ee3aedff Michael Hanselmann
             utils.CommaJoin(fdef.name for fdef in unknown))
2508 ee3aedff Michael Hanselmann
    return True
2509 ee3aedff Michael Hanselmann
2510 ee3aedff Michael Hanselmann
  return False
2511 ee3aedff Michael Hanselmann
2512 ee3aedff Michael Hanselmann
2513 ee3aedff Michael Hanselmann
def GenericList(resource, fields, names, unit, separator, header, cl=None,
2514 f0b1bafe Iustin Pop
                format_override=None, verbose=False):
2515 ee3aedff Michael Hanselmann
  """Generic implementation for listing all items of a resource.
2516 ee3aedff Michael Hanselmann

2517 ee3aedff Michael Hanselmann
  @param resource: One of L{constants.QR_OP_LUXI}
2518 ee3aedff Michael Hanselmann
  @type fields: list of strings
2519 ee3aedff Michael Hanselmann
  @param fields: List of fields to query for
2520 ee3aedff Michael Hanselmann
  @type names: list of strings
2521 ee3aedff Michael Hanselmann
  @param names: Names of items to query for
2522 ee3aedff Michael Hanselmann
  @type unit: string or None
2523 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT} or
2524 ee3aedff Michael Hanselmann
    None for automatic choice (human-readable for non-separator usage,
2525 ee3aedff Michael Hanselmann
    otherwise megabytes); this is a one-letter string
2526 ee3aedff Michael Hanselmann
  @type separator: string or None
2527 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2528 ee3aedff Michael Hanselmann
  @type header: bool
2529 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2530 ee3aedff Michael Hanselmann
  @type format_override: dict
2531 ee3aedff Michael Hanselmann
  @param format_override: Dictionary for overriding field formatting functions,
2532 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2533 f0b1bafe Iustin Pop
  @type verbose: boolean
2534 f0b1bafe Iustin Pop
  @param verbose: whether to use verbose field descriptions or not
2535 ee3aedff Michael Hanselmann

2536 ee3aedff Michael Hanselmann
  """
2537 ee3aedff Michael Hanselmann
  if cl is None:
2538 ee3aedff Michael Hanselmann
    cl = GetClient()
2539 ee3aedff Michael Hanselmann
2540 ee3aedff Michael Hanselmann
  if not names:
2541 ee3aedff Michael Hanselmann
    names = None
2542 ee3aedff Michael Hanselmann
2543 ee3aedff Michael Hanselmann
  response = cl.Query(resource, fields, qlang.MakeSimpleFilter("name", names))
2544 ee3aedff Michael Hanselmann
2545 ee3aedff Michael Hanselmann
  found_unknown = _WarnUnknownFields(response.fields)
2546 ee3aedff Michael Hanselmann
2547 ee3aedff Michael Hanselmann
  (status, data) = FormatQueryResult(response, unit=unit, separator=separator,
2548 ee3aedff Michael Hanselmann
                                     header=header,
2549 f0b1bafe Iustin Pop
                                     format_override=format_override,
2550 f0b1bafe Iustin Pop
                                     verbose=verbose)
2551 ee3aedff Michael Hanselmann
2552 ee3aedff Michael Hanselmann
  for line in data:
2553 ee3aedff Michael Hanselmann
    ToStdout(line)
2554 ee3aedff Michael Hanselmann
2555 ee3aedff Michael Hanselmann
  assert ((found_unknown and status == QR_UNKNOWN) or
2556 ee3aedff Michael Hanselmann
          (not found_unknown and status != QR_UNKNOWN))
2557 ee3aedff Michael Hanselmann
2558 ee3aedff Michael Hanselmann
  if status == QR_UNKNOWN:
2559 ee3aedff Michael Hanselmann
    return constants.EXIT_UNKNOWN_FIELD
2560 ee3aedff Michael Hanselmann
2561 ee3aedff Michael Hanselmann
  # TODO: Should the list command fail if not all data could be collected?
2562 ee3aedff Michael Hanselmann
  return constants.EXIT_SUCCESS
2563 ee3aedff Michael Hanselmann
2564 ee3aedff Michael Hanselmann
2565 ee3aedff Michael Hanselmann
def GenericListFields(resource, fields, separator, header, cl=None):
2566 ee3aedff Michael Hanselmann
  """Generic implementation for listing fields for a resource.
2567 ee3aedff Michael Hanselmann

2568 ee3aedff Michael Hanselmann
  @param resource: One of L{constants.QR_OP_LUXI}
2569 ee3aedff Michael Hanselmann
  @type fields: list of strings
2570 ee3aedff Michael Hanselmann
  @param fields: List of fields to query for
2571 ee3aedff Michael Hanselmann
  @type separator: string or None
2572 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2573 ee3aedff Michael Hanselmann
  @type header: bool
2574 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2575 ee3aedff Michael Hanselmann

2576 ee3aedff Michael Hanselmann
  """
2577 ee3aedff Michael Hanselmann
  if cl is None:
2578 ee3aedff Michael Hanselmann
    cl = GetClient()
2579 ee3aedff Michael Hanselmann
2580 ee3aedff Michael Hanselmann
  if not fields:
2581 ee3aedff Michael Hanselmann
    fields = None
2582 ee3aedff Michael Hanselmann
2583 ee3aedff Michael Hanselmann
  response = cl.QueryFields(resource, fields)
2584 ee3aedff Michael Hanselmann
2585 ee3aedff Michael Hanselmann
  found_unknown = _WarnUnknownFields(response.fields)
2586 ee3aedff Michael Hanselmann
2587 ee3aedff Michael Hanselmann
  columns = [
2588 ee3aedff Michael Hanselmann
    TableColumn("Name", str, False),
2589 ee3aedff Michael Hanselmann
    TableColumn("Title", str, False),
2590 ee3aedff Michael Hanselmann
    # TODO: Add field description to master daemon
2591 ee3aedff Michael Hanselmann
    ]
2592 ee3aedff Michael Hanselmann
2593 ee3aedff Michael Hanselmann
  rows = [[fdef.name, fdef.title] for fdef in response.fields]
2594 ee3aedff Michael Hanselmann
2595 ee3aedff Michael Hanselmann
  for line in FormatTable(rows, columns, header, separator):
2596 ee3aedff Michael Hanselmann
    ToStdout(line)
2597 ee3aedff Michael Hanselmann
2598 ee3aedff Michael Hanselmann
  if found_unknown:
2599 ee3aedff Michael Hanselmann
    return constants.EXIT_UNKNOWN_FIELD
2600 ee3aedff Michael Hanselmann
2601 ee3aedff Michael Hanselmann
  return constants.EXIT_SUCCESS
2602 ee3aedff Michael Hanselmann
2603 ee3aedff Michael Hanselmann
2604 ee3aedff Michael Hanselmann
class TableColumn:
2605 ee3aedff Michael Hanselmann
  """Describes a column for L{FormatTable}.
2606 ee3aedff Michael Hanselmann

2607 ee3aedff Michael Hanselmann
  """
2608 ee3aedff Michael Hanselmann
  def __init__(self, title, fn, align_right):
2609 ee3aedff Michael Hanselmann
    """Initializes this class.
2610 ee3aedff Michael Hanselmann

2611 ee3aedff Michael Hanselmann
    @type title: string
2612 ee3aedff Michael Hanselmann
    @param title: Column title
2613 ee3aedff Michael Hanselmann
    @type fn: callable
2614 ee3aedff Michael Hanselmann
    @param fn: Formatting function
2615 ee3aedff Michael Hanselmann
    @type align_right: bool
2616 ee3aedff Michael Hanselmann
    @param align_right: Whether to align values on the right-hand side
2617 ee3aedff Michael Hanselmann

2618 ee3aedff Michael Hanselmann
    """
2619 ee3aedff Michael Hanselmann
    self.title = title
2620 ee3aedff Michael Hanselmann
    self.format = fn
2621 ee3aedff Michael Hanselmann
    self.align_right = align_right
2622 ee3aedff Michael Hanselmann
2623 ee3aedff Michael Hanselmann
2624 ee3aedff Michael Hanselmann
def _GetColFormatString(width, align_right):
2625 ee3aedff Michael Hanselmann
  """Returns the format string for a field.
2626 ee3aedff Michael Hanselmann

2627 ee3aedff Michael Hanselmann
  """
2628 ee3aedff Michael Hanselmann
  if align_right:
2629 ee3aedff Michael Hanselmann
    sign = ""
2630 ee3aedff Michael Hanselmann
  else:
2631 ee3aedff Michael Hanselmann
    sign = "-"
2632 ee3aedff Michael Hanselmann
2633 ee3aedff Michael Hanselmann
  return "%%%s%ss" % (sign, width)
2634 ee3aedff Michael Hanselmann
2635 ee3aedff Michael Hanselmann
2636 ee3aedff Michael Hanselmann
def FormatTable(rows, columns, header, separator):
2637 ee3aedff Michael Hanselmann
  """Formats data as a table.
2638 ee3aedff Michael Hanselmann

2639 ee3aedff Michael Hanselmann
  @type rows: list of lists
2640 ee3aedff Michael Hanselmann
  @param rows: Row data, one list per row
2641 ee3aedff Michael Hanselmann
  @type columns: list of L{TableColumn}
2642 ee3aedff Michael Hanselmann
  @param columns: Column descriptions
2643 ee3aedff Michael Hanselmann
  @type header: bool
2644 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2645 ee3aedff Michael Hanselmann
  @type separator: string or None
2646 ee3aedff Michael Hanselmann
  @param separator: String used to separate columns
2647 ee3aedff Michael Hanselmann

2648 ee3aedff Michael Hanselmann
  """
2649 ee3aedff Michael Hanselmann
  if header:
2650 ee3aedff Michael Hanselmann
    data = [[col.title for col in columns]]
2651 ee3aedff Michael Hanselmann
    colwidth = [len(col.title) for col in columns]
2652 ee3aedff Michael Hanselmann
  else:
2653 ee3aedff Michael Hanselmann
    data = []
2654 ee3aedff Michael Hanselmann
    colwidth = [0 for _ in columns]
2655 ee3aedff Michael Hanselmann
2656 ee3aedff Michael Hanselmann
  # Format row data
2657 ee3aedff Michael Hanselmann
  for row in rows:
2658 ee3aedff Michael Hanselmann
    assert len(row) == len(columns)
2659 ee3aedff Michael Hanselmann
2660 ee3aedff Michael Hanselmann
    formatted = [col.format(value) for value, col in zip(row, columns)]
2661 ee3aedff Michael Hanselmann
2662 ee3aedff Michael Hanselmann
    if separator is None:
2663 ee3aedff Michael Hanselmann
      # Update column widths
2664 ee3aedff Michael Hanselmann
      for idx, (oldwidth, value) in enumerate(zip(colwidth, formatted)):
2665 ee3aedff Michael Hanselmann
        # Modifying a list's items while iterating is fine
2666 ee3aedff Michael Hanselmann
        colwidth[idx] = max(oldwidth, len(value))
2667 ee3aedff Michael Hanselmann
2668 ee3aedff Michael Hanselmann
    data.append(formatted)
2669 ee3aedff Michael Hanselmann
2670 ee3aedff Michael Hanselmann
  if separator is not None:
2671 ee3aedff Michael Hanselmann
    # Return early if a separator is used
2672 ee3aedff Michael Hanselmann
    return [separator.join(row) for row in data]
2673 ee3aedff Michael Hanselmann
2674 ee3aedff Michael Hanselmann
  if columns and not columns[-1].align_right:
2675 ee3aedff Michael Hanselmann
    # Avoid unnecessary spaces at end of line
2676 ee3aedff Michael Hanselmann
    colwidth[-1] = 0
2677 ee3aedff Michael Hanselmann
2678 ee3aedff Michael Hanselmann
  # Build format string
2679 ee3aedff Michael Hanselmann
  fmt = " ".join([_GetColFormatString(width, col.align_right)
2680 ee3aedff Michael Hanselmann
                  for col, width in zip(columns, colwidth)])
2681 ee3aedff Michael Hanselmann
2682 ee3aedff Michael Hanselmann
  return [fmt % tuple(row) for row in data]
2683 ee3aedff Michael Hanselmann
2684 ee3aedff Michael Hanselmann
2685 3386e7a9 Iustin Pop
def FormatTimestamp(ts):
2686 3386e7a9 Iustin Pop
  """Formats a given timestamp.
2687 3386e7a9 Iustin Pop

2688 3386e7a9 Iustin Pop
  @type ts: timestamp
2689 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
2690 3386e7a9 Iustin Pop

2691 3386e7a9 Iustin Pop
  @rtype: string
2692 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
2693 3386e7a9 Iustin Pop

2694 3386e7a9 Iustin Pop
  """
2695 e0ec0ff6 Iustin Pop
  if not isinstance (ts, (tuple, list)) or len(ts) != 2:
2696 e0ec0ff6 Iustin Pop
    return '?'
2697 3386e7a9 Iustin Pop
  sec, usec = ts
2698 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
2699 2241e2b9 Iustin Pop
2700 2241e2b9 Iustin Pop
2701 2241e2b9 Iustin Pop
def ParseTimespec(value):
2702 2241e2b9 Iustin Pop
  """Parse a time specification.
2703 2241e2b9 Iustin Pop

2704 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
2705 2241e2b9 Iustin Pop

2706 2241e2b9 Iustin Pop
    - s: seconds
2707 2241e2b9 Iustin Pop
    - m: minutes
2708 2241e2b9 Iustin Pop
    - h: hours
2709 2241e2b9 Iustin Pop
    - d: day
2710 2241e2b9 Iustin Pop
    - w: weeks
2711 2241e2b9 Iustin Pop

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

2714 2241e2b9 Iustin Pop
  """
2715 2241e2b9 Iustin Pop
  value = str(value)
2716 2241e2b9 Iustin Pop
  if not value:
2717 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
2718 2241e2b9 Iustin Pop
  suffix_map = {
2719 2241e2b9 Iustin Pop
    's': 1,
2720 2241e2b9 Iustin Pop
    'm': 60,
2721 2241e2b9 Iustin Pop
    'h': 3600,
2722 2241e2b9 Iustin Pop
    'd': 86400,
2723 2241e2b9 Iustin Pop
    'w': 604800,
2724 2241e2b9 Iustin Pop
    }
2725 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
2726 2241e2b9 Iustin Pop
    try:
2727 2241e2b9 Iustin Pop
      value = int(value)
2728 691744c4 Iustin Pop
    except (TypeError, ValueError):
2729 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2730 2241e2b9 Iustin Pop
  else:
2731 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
2732 2241e2b9 Iustin Pop
    value = value[:-1]
2733 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
2734 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
2735 2241e2b9 Iustin Pop
                                 " suffix passed)")
2736 2241e2b9 Iustin Pop
    try:
2737 2241e2b9 Iustin Pop
      value = int(value) * multiplier
2738 691744c4 Iustin Pop
    except (TypeError, ValueError):
2739 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2740 2241e2b9 Iustin Pop
  return value
2741 46fbdd04 Iustin Pop
2742 46fbdd04 Iustin Pop
2743 e9e26bb3 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False, secondary_ips=False,
2744 e9e26bb3 Iustin Pop
                   filter_master=False):
2745 4040a784 Iustin Pop
  """Returns the names of online nodes.
2746 4040a784 Iustin Pop

2747 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
2748 4040a784 Iustin Pop
  the online nodes.
2749 4040a784 Iustin Pop

2750 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
2751 4040a784 Iustin Pop
      offline ones)
2752 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
2753 4040a784 Iustin Pop
  @type nowarn: boolean
2754 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
2755 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
2756 4040a784 Iustin Pop
      note is not displayed
2757 e9e26bb3 Iustin Pop
  @type secondary_ips: boolean
2758 e9e26bb3 Iustin Pop
  @param secondary_ips: if True, return the secondary IPs instead of the
2759 e9e26bb3 Iustin Pop
      names, useful for doing network traffic over the replication interface
2760 e9e26bb3 Iustin Pop
      (if any)
2761 e9e26bb3 Iustin Pop
  @type filter_master: boolean
2762 e9e26bb3 Iustin Pop
  @param filter_master: if True, do not return the master node in the list
2763 e9e26bb3 Iustin Pop
      (useful in coordination with secondary_ips where we cannot check our
2764 e9e26bb3 Iustin Pop
      node name against the list)
2765 4040a784 Iustin Pop

2766 4040a784 Iustin Pop
  """
2767 4040a784 Iustin Pop
  if cl is None:
2768 4040a784 Iustin Pop
    cl = GetClient()
2769 4040a784 Iustin Pop
2770 e9e26bb3 Iustin Pop
  if secondary_ips:
2771 e9e26bb3 Iustin Pop
    name_idx = 2
2772 e9e26bb3 Iustin Pop
  else:
2773 e9e26bb3 Iustin Pop
    name_idx = 0
2774 e9e26bb3 Iustin Pop
2775 e9e26bb3 Iustin Pop
  if filter_master:
2776 e9e26bb3 Iustin Pop
    master_node = cl.QueryConfigValues(["master_node"])[0]
2777 e9e26bb3 Iustin Pop
    filter_fn = lambda x: x != master_node
2778 e9e26bb3 Iustin Pop
  else:
2779 e9e26bb3 Iustin Pop
    filter_fn = lambda _: True
2780 e9e26bb3 Iustin Pop
2781 e9e26bb3 Iustin Pop
  result = cl.QueryNodes(names=nodes, fields=["name", "offline", "sip"],
2782 2e7b8369 Iustin Pop
                         use_locking=False)
2783 4040a784 Iustin Pop
  offline = [row[0] for row in result if row[1]]
2784 4040a784 Iustin Pop
  if offline and not nowarn:
2785 1f864b60 Iustin Pop
    ToStderr("Note: skipping offline node(s): %s" % utils.CommaJoin(offline))
2786 e9e26bb3 Iustin Pop
  return [row[name_idx] for row in result if not row[1] and filter_fn(row[0])]
2787 4040a784 Iustin Pop
2788 4040a784 Iustin Pop
2789 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
2790 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
2791 46fbdd04 Iustin Pop

2792 46fbdd04 Iustin Pop
  @type stream: file object
2793 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
2794 46fbdd04 Iustin Pop
  @type txt: str
2795 46fbdd04 Iustin Pop
  @param txt: the message
2796 46fbdd04 Iustin Pop

2797 46fbdd04 Iustin Pop
  """
2798 46fbdd04 Iustin Pop
  if args:
2799 46fbdd04 Iustin Pop
    args = tuple(args)
2800 46fbdd04 Iustin Pop
    stream.write(txt % args)
2801 46fbdd04 Iustin Pop
  else:
2802 46fbdd04 Iustin Pop
    stream.write(txt)
2803 46fbdd04 Iustin Pop
  stream.write('\n')
2804 46fbdd04 Iustin Pop
  stream.flush()
2805 46fbdd04 Iustin Pop
2806 46fbdd04 Iustin Pop
2807 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
2808 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
2809 46fbdd04 Iustin Pop

2810 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2811 46fbdd04 Iustin Pop

2812 46fbdd04 Iustin Pop
  @type txt: str
2813 46fbdd04 Iustin Pop
  @param txt: the message
2814 46fbdd04 Iustin Pop

2815 46fbdd04 Iustin Pop
  """
2816 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
2817 46fbdd04 Iustin Pop
2818 46fbdd04 Iustin Pop
2819 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
2820 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
2821 46fbdd04 Iustin Pop

2822 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2823 46fbdd04 Iustin Pop

2824 46fbdd04 Iustin Pop
  @type txt: str
2825 46fbdd04 Iustin Pop
  @param txt: the message
2826 46fbdd04 Iustin Pop

2827 46fbdd04 Iustin Pop
  """
2828 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
2829 479636a3 Iustin Pop
2830 479636a3 Iustin Pop
2831 479636a3 Iustin Pop
class JobExecutor(object):
2832 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
2833 479636a3 Iustin Pop

2834 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
2835 479636a3 Iustin Pop
  GetResults() calls.
2836 479636a3 Iustin Pop

2837 479636a3 Iustin Pop
  """
2838 919ca415 Iustin Pop
  def __init__(self, cl=None, verbose=True, opts=None, feedback_fn=None):
2839 479636a3 Iustin Pop
    self.queue = []
2840 479636a3 Iustin Pop
    if cl is None:
2841 479636a3 Iustin Pop
      cl = GetClient()
2842 479636a3 Iustin Pop
    self.cl = cl
2843 479636a3 Iustin Pop
    self.verbose = verbose
2844 23b4b983 Iustin Pop
    self.jobs = []
2845 cff5fa7f Iustin Pop
    self.opts = opts
2846 919ca415 Iustin Pop
    self.feedback_fn = feedback_fn
2847 479636a3 Iustin Pop
2848 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
2849 23b4b983 Iustin Pop
    """Record a job for later submit.
2850 479636a3 Iustin Pop

2851 479636a3 Iustin Pop
    @type name: string
2852 479636a3 Iustin Pop
    @param name: a description of the job, will be used in WaitJobSet
2853 479636a3 Iustin Pop
    """
2854 cff5fa7f Iustin Pop
    SetGenericOpcodeOpts(ops, self.opts)
2855 23b4b983 Iustin Pop
    self.queue.append((name, ops))
2856 23b4b983 Iustin Pop
2857 66ecc479 Guido Trotter
  def SubmitPending(self, each=False):
2858 23b4b983 Iustin Pop
    """Submit all pending jobs.
2859 23b4b983 Iustin Pop

2860 23b4b983 Iustin Pop
    """
2861 66ecc479 Guido Trotter
    if each:
2862 66ecc479 Guido Trotter
      results = []
2863 66ecc479 Guido Trotter
      for row in self.queue:
2864 66ecc479 Guido Trotter
        # SubmitJob will remove the success status, but raise an exception if
2865 66ecc479 Guido Trotter
        # the submission fails, so we'll notice that anyway.
2866 66ecc479 Guido Trotter
        results.append([True, self.cl.SubmitJob(row[1])])
2867 66ecc479 Guido Trotter
    else:
2868 66ecc479 Guido Trotter
      results = self.cl.SubmitManyJobs([row[1] for row in self.queue])
2869 5299e61f Iustin Pop
    for (idx, ((status, data), (name, _))) in enumerate(zip(results,
2870 5299e61f Iustin Pop
                                                            self.queue)):
2871 5299e61f Iustin Pop
      self.jobs.append((idx, status, data, name))
2872 5299e61f Iustin Pop
2873 5299e61f Iustin Pop
  def _ChooseJob(self):
2874 5299e61f Iustin Pop
    """Choose a non-waiting/queued job to poll next.
2875 5299e61f Iustin Pop

2876 5299e61f Iustin Pop
    """
2877 5299e61f Iustin Pop
    assert self.jobs, "_ChooseJob called with empty job list"
2878 5299e61f Iustin Pop
2879 5299e61f Iustin Pop
    result = self.cl.QueryJobs([i[2] for i in self.jobs], ["status"])
2880 5299e61f Iustin Pop
    assert result
2881 5299e61f Iustin Pop
2882 5299e61f Iustin Pop
    for job_data, status in zip(self.jobs, result):
2883 91c622a8 Iustin Pop
      if (isinstance(status, list) and status and
2884 91c622a8 Iustin Pop
          status[0] in (constants.JOB_STATUS_QUEUED,
2885 91c622a8 Iustin Pop
                        constants.JOB_STATUS_WAITLOCK,
2886 91c622a8 Iustin Pop
                        constants.JOB_STATUS_CANCELING)):
2887 91c622a8 Iustin Pop
        # job is still present and waiting
2888 5299e61f Iustin Pop
        continue
2889 91c622a8 Iustin Pop
      # good candidate found (either running job or lost job)
2890 5299e61f Iustin Pop
      self.jobs.remove(job_data)
2891 5299e61f Iustin Pop
      return job_data
2892 5299e61f Iustin Pop
2893 5299e61f Iustin Pop
    # no job found
2894 5299e61f Iustin Pop
    return self.jobs.pop(0)
2895 479636a3 Iustin Pop
2896 479636a3 Iustin Pop
  def GetResults(self):
2897 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
2898 479636a3 Iustin Pop

2899 479636a3 Iustin Pop
    @rtype: list
2900 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
2901 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
2902 479636a3 Iustin Pop
        there will be the error message
2903 479636a3 Iustin Pop

2904 479636a3 Iustin Pop
    """
2905 23b4b983 Iustin Pop
    if not self.jobs:
2906 23b4b983 Iustin Pop
      self.SubmitPending()
2907 479636a3 Iustin Pop
    results = []
2908 479636a3 Iustin Pop
    if self.verbose:
2909 5299e61f Iustin Pop
      ok_jobs = [row[2] for row in self.jobs if row[1]]
2910 23b4b983 Iustin Pop
      if ok_jobs:
2911 1f864b60 Iustin Pop
        ToStdout("Submitted jobs %s", utils.CommaJoin(ok_jobs))
2912 5299e61f Iustin Pop
2913 5299e61f Iustin Pop
    # first, remove any non-submitted jobs
2914 cea881e5 Michael Hanselmann
    self.jobs, failures = compat.partition(self.jobs, lambda x: x[1])
2915 5299e61f Iustin Pop
    for idx, _, jid, name in failures:
2916 c63355f2 Iustin Pop
      ToStderr("Failed to submit job for %s: %s", name, jid)
2917 c63355f2 Iustin Pop
      results.append((idx, False, jid))
2918 5299e61f Iustin Pop
2919 5299e61f Iustin Pop
    while self.jobs:
2920 5299e61f Iustin Pop
      (idx, _, jid, name) = self._ChooseJob()
2921 5299e61f Iustin Pop
      ToStdout("Waiting for job %s for %s...", jid, name)
2922 479636a3 Iustin Pop
      try:
2923 919ca415 Iustin Pop
        job_result = PollJob(jid, cl=self.cl, feedback_fn=self.feedback_fn)
2924 479636a3 Iustin Pop
        success = True
2925 91c622a8 Iustin Pop
      except errors.JobLost, err:
2926 91c622a8 Iustin Pop
        _, job_result = FormatError(err)
2927 91c622a8 Iustin Pop
        ToStderr("Job %s for %s has been archived, cannot check its result",
2928 91c622a8 Iustin Pop
                 jid, name)
2929 91c622a8 Iustin Pop
        success = False
2930 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
2931 479636a3 Iustin Pop
        _, job_result = FormatError(err)
2932 479636a3 Iustin Pop
        success = False
2933 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
2934 479636a3 Iustin Pop
        ToStderr("Job %s for %s has failed: %s", jid, name, job_result)
2935 479636a3 Iustin Pop
2936 5299e61f Iustin Pop
      results.append((idx, success, job_result))
2937 5299e61f Iustin Pop
2938 5299e61f Iustin Pop
    # sort based on the index, then drop it
2939 5299e61f Iustin Pop
    results.sort()
2940 5299e61f Iustin Pop
    results = [i[1:] for i in results]
2941 5299e61f Iustin Pop
2942 479636a3 Iustin Pop
    return results
2943 479636a3 Iustin Pop
2944 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
2945 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
2946 479636a3 Iustin Pop

2947 479636a3 Iustin Pop
    @type wait: boolean
2948 479636a3 Iustin Pop
    @param wait: whether to wait or not
2949 479636a3 Iustin Pop

2950 479636a3 Iustin Pop
    """
2951 479636a3 Iustin Pop
    if wait:
2952 479636a3 Iustin Pop
      return self.GetResults()
2953 479636a3 Iustin Pop
    else:
2954 23b4b983 Iustin Pop
      if not self.jobs:
2955 23b4b983 Iustin Pop
        self.SubmitPending()
2956 71834b2a Guido Trotter
      for _, status, result, name in self.jobs:
2957 23b4b983 Iustin Pop
        if status:
2958 23b4b983 Iustin Pop
          ToStdout("%s: %s", result, name)
2959 23b4b983 Iustin Pop
        else:
2960 23b4b983 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)
2961 53a8a54d Iustin Pop
      return [row[1:3] for row in self.jobs]
2962 acd19189 René Nussbaumer
2963 acd19189 René Nussbaumer
2964 acd19189 René Nussbaumer
def FormatParameterDict(buf, param_dict, actual, level=1):
2965 acd19189 René Nussbaumer
  """Formats a parameter dictionary.
2966 acd19189 René Nussbaumer

2967 acd19189 René Nussbaumer
  @type buf: L{StringIO}
2968 acd19189 René Nussbaumer
  @param buf: the buffer into which to write
2969 acd19189 René Nussbaumer
  @type param_dict: dict
2970 acd19189 René Nussbaumer
  @param param_dict: the own parameters
2971 acd19189 René Nussbaumer
  @type actual: dict
2972 acd19189 René Nussbaumer
  @param actual: the current parameter set (including defaults)
2973 acd19189 René Nussbaumer
  @param level: Level of indent
2974 acd19189 René Nussbaumer

2975 acd19189 René Nussbaumer
  """
2976 acd19189 René Nussbaumer
  indent = "  " * level
2977 acd19189 René Nussbaumer
  for key in sorted(actual):
2978 acd19189 René Nussbaumer
    val = param_dict.get(key, "default (%s)" % actual[key])
2979 acd19189 René Nussbaumer
    buf.write("%s- %s: %s\n" % (indent, key, val))