Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ b4fcee5b

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

272 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor.
273 863d7f46 Michael Hanselmann

274 863d7f46 Michael Hanselmann
  """
275 7260cfbe Iustin Pop
  # pylint: disable-msg=W0622
276 863d7f46 Michael Hanselmann
  def __init__(self, min=0, max=None, choices=None):
277 863d7f46 Michael Hanselmann
    _Argument.__init__(self, min=min, max=max)
278 863d7f46 Michael Hanselmann
    self.choices = choices
279 863d7f46 Michael Hanselmann
280 863d7f46 Michael Hanselmann
  def __repr__(self):
281 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s choices=%r>" %
282 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max, self.choices))
283 863d7f46 Michael Hanselmann
284 863d7f46 Michael Hanselmann
285 863d7f46 Michael Hanselmann
class ArgChoice(ArgSuggest):
286 863d7f46 Michael Hanselmann
  """Choice argument.
287 863d7f46 Michael Hanselmann

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

291 863d7f46 Michael Hanselmann
  """
292 863d7f46 Michael Hanselmann
293 863d7f46 Michael Hanselmann
294 863d7f46 Michael Hanselmann
class ArgUnknown(_Argument):
295 863d7f46 Michael Hanselmann
  """Unknown argument to program (e.g. determined at runtime).
296 863d7f46 Michael Hanselmann

297 863d7f46 Michael Hanselmann
  """
298 863d7f46 Michael Hanselmann
299 863d7f46 Michael Hanselmann
300 863d7f46 Michael Hanselmann
class ArgInstance(_Argument):
301 863d7f46 Michael Hanselmann
  """Instances argument.
302 863d7f46 Michael Hanselmann

303 863d7f46 Michael Hanselmann
  """
304 863d7f46 Michael Hanselmann
305 863d7f46 Michael Hanselmann
306 863d7f46 Michael Hanselmann
class ArgNode(_Argument):
307 863d7f46 Michael Hanselmann
  """Node argument.
308 863d7f46 Michael Hanselmann

309 863d7f46 Michael Hanselmann
  """
310 863d7f46 Michael Hanselmann
311 667dbd6b Adeodato Simo
312 667dbd6b Adeodato Simo
class ArgGroup(_Argument):
313 667dbd6b Adeodato Simo
  """Node group argument.
314 667dbd6b Adeodato Simo

315 667dbd6b Adeodato Simo
  """
316 667dbd6b Adeodato Simo
317 667dbd6b Adeodato Simo
318 863d7f46 Michael Hanselmann
class ArgJobId(_Argument):
319 863d7f46 Michael Hanselmann
  """Job ID argument.
320 863d7f46 Michael Hanselmann

321 863d7f46 Michael Hanselmann
  """
322 863d7f46 Michael Hanselmann
323 863d7f46 Michael Hanselmann
324 863d7f46 Michael Hanselmann
class ArgFile(_Argument):
325 863d7f46 Michael Hanselmann
  """File path argument.
326 863d7f46 Michael Hanselmann

327 863d7f46 Michael Hanselmann
  """
328 863d7f46 Michael Hanselmann
329 863d7f46 Michael Hanselmann
330 863d7f46 Michael Hanselmann
class ArgCommand(_Argument):
331 863d7f46 Michael Hanselmann
  """Command argument.
332 863d7f46 Michael Hanselmann

333 863d7f46 Michael Hanselmann
  """
334 863d7f46 Michael Hanselmann
335 863d7f46 Michael Hanselmann
336 83ec7961 Michael Hanselmann
class ArgHost(_Argument):
337 83ec7961 Michael Hanselmann
  """Host argument.
338 83ec7961 Michael Hanselmann

339 83ec7961 Michael Hanselmann
  """
340 83ec7961 Michael Hanselmann
341 83ec7961 Michael Hanselmann
342 f9faf9c3 René Nussbaumer
class ArgOs(_Argument):
343 f9faf9c3 René Nussbaumer
  """OS argument.
344 f9faf9c3 René Nussbaumer

345 f9faf9c3 René Nussbaumer
  """
346 f9faf9c3 René Nussbaumer
347 f9faf9c3 René Nussbaumer
348 4a265c08 Michael Hanselmann
ARGS_NONE = []
349 4a265c08 Michael Hanselmann
ARGS_MANY_INSTANCES = [ArgInstance()]
350 4a265c08 Michael Hanselmann
ARGS_MANY_NODES = [ArgNode()]
351 667dbd6b Adeodato Simo
ARGS_MANY_GROUPS = [ArgGroup()]
352 4a265c08 Michael Hanselmann
ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
353 4a265c08 Michael Hanselmann
ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
354 dadf6b7d Michael Hanselmann
# TODO
355 dadf6b7d Michael Hanselmann
ARGS_ONE_GROUP = [ArgGroup(min=1, max=1)]
356 f9faf9c3 René Nussbaumer
ARGS_ONE_OS = [ArgOs(min=1, max=1)]
357 4a265c08 Michael Hanselmann
358 4a265c08 Michael Hanselmann
359 846baef9 Iustin Pop
def _ExtractTagsObject(opts, args):
360 846baef9 Iustin Pop
  """Extract the tag type object.
361 846baef9 Iustin Pop

362 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
363 846baef9 Iustin Pop

364 846baef9 Iustin Pop
  """
365 846baef9 Iustin Pop
  if not hasattr(opts, "tag_type"):
366 846baef9 Iustin Pop
    raise errors.ProgrammerError("tag_type not passed to _ExtractTagsObject")
367 846baef9 Iustin Pop
  kind = opts.tag_type
368 846baef9 Iustin Pop
  if kind == constants.TAG_CLUSTER:
369 846baef9 Iustin Pop
    retval = kind, kind
370 819cbfe5 Michael Hanselmann
  elif kind in (constants.TAG_NODEGROUP,
371 819cbfe5 Michael Hanselmann
                constants.TAG_NODE,
372 819cbfe5 Michael Hanselmann
                constants.TAG_INSTANCE):
373 846baef9 Iustin Pop
    if not args:
374 0c434948 Iustin Pop
      raise errors.OpPrereqError("no arguments passed to the command")
375 846baef9 Iustin Pop
    name = args.pop(0)
376 846baef9 Iustin Pop
    retval = kind, name
377 846baef9 Iustin Pop
  else:
378 846baef9 Iustin Pop
    raise errors.ProgrammerError("Unhandled tag type '%s'" % kind)
379 846baef9 Iustin Pop
  return retval
380 846baef9 Iustin Pop
381 846baef9 Iustin Pop
382 810c50b7 Iustin Pop
def _ExtendTags(opts, args):
383 810c50b7 Iustin Pop
  """Extend the args if a source file has been given.
384 810c50b7 Iustin Pop

385 810c50b7 Iustin Pop
  This function will extend the tags with the contents of the file
386 810c50b7 Iustin Pop
  passed in the 'tags_source' attribute of the opts parameter. A file
387 810c50b7 Iustin Pop
  named '-' will be replaced by stdin.
388 810c50b7 Iustin Pop

389 810c50b7 Iustin Pop
  """
390 810c50b7 Iustin Pop
  fname = opts.tags_source
391 810c50b7 Iustin Pop
  if fname is None:
392 810c50b7 Iustin Pop
    return
393 810c50b7 Iustin Pop
  if fname == "-":
394 810c50b7 Iustin Pop
    new_fh = sys.stdin
395 810c50b7 Iustin Pop
  else:
396 810c50b7 Iustin Pop
    new_fh = open(fname, "r")
397 810c50b7 Iustin Pop
  new_data = []
398 810c50b7 Iustin Pop
  try:
399 810c50b7 Iustin Pop
    # we don't use the nice 'new_data = [line.strip() for line in fh]'
400 810c50b7 Iustin Pop
    # because of python bug 1633941
401 810c50b7 Iustin Pop
    while True:
402 810c50b7 Iustin Pop
      line = new_fh.readline()
403 810c50b7 Iustin Pop
      if not line:
404 810c50b7 Iustin Pop
        break
405 810c50b7 Iustin Pop
      new_data.append(line.strip())
406 810c50b7 Iustin Pop
  finally:
407 810c50b7 Iustin Pop
    new_fh.close()
408 810c50b7 Iustin Pop
  args.extend(new_data)
409 810c50b7 Iustin Pop
410 810c50b7 Iustin Pop
411 846baef9 Iustin Pop
def ListTags(opts, args):
412 846baef9 Iustin Pop
  """List the tags on a given object.
413 846baef9 Iustin Pop

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

419 846baef9 Iustin Pop
  """
420 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
421 7699c3af Iustin Pop
  cl = GetClient()
422 7699c3af Iustin Pop
  result = cl.QueryTags(kind, name)
423 846baef9 Iustin Pop
  result = list(result)
424 846baef9 Iustin Pop
  result.sort()
425 846baef9 Iustin Pop
  for tag in result:
426 03298ebe Michael Hanselmann
    ToStdout(tag)
427 846baef9 Iustin Pop
428 846baef9 Iustin Pop
429 846baef9 Iustin Pop
def AddTags(opts, args):
430 846baef9 Iustin Pop
  """Add tags on a given object.
431 846baef9 Iustin Pop

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

437 846baef9 Iustin Pop
  """
438 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
439 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
440 846baef9 Iustin Pop
  if not args:
441 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be added")
442 d1602edc Iustin Pop
  op = opcodes.OpTagsSet(kind=kind, name=name, tags=args)
443 af1a81d1 Michael Hanselmann
  SubmitOpCode(op, opts=opts)
444 846baef9 Iustin Pop
445 846baef9 Iustin Pop
446 846baef9 Iustin Pop
def RemoveTags(opts, args):
447 846baef9 Iustin Pop
  """Remove tags from a given object.
448 846baef9 Iustin Pop

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

454 846baef9 Iustin Pop
  """
455 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
456 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
457 846baef9 Iustin Pop
  if not args:
458 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be removed")
459 3f0ab95f Iustin Pop
  op = opcodes.OpTagsDel(kind=kind, name=name, tags=args)
460 af1a81d1 Michael Hanselmann
  SubmitOpCode(op, opts=opts)
461 846baef9 Iustin Pop
462 a8083063 Iustin Pop
463 8929d28c Iustin Pop
def check_unit(option, opt, value): # pylint: disable-msg=W0613
464 65fe4693 Iustin Pop
  """OptParsers custom converter for units.
465 65fe4693 Iustin Pop

466 65fe4693 Iustin Pop
  """
467 a8083063 Iustin Pop
  try:
468 a8083063 Iustin Pop
    return utils.ParseUnit(value)
469 a8083063 Iustin Pop
  except errors.UnitParseError, err:
470 3ecf6786 Iustin Pop
    raise OptionValueError("option %s: %s" % (opt, err))
471 a8083063 Iustin Pop
472 a8083063 Iustin Pop
473 a8469393 Iustin Pop
def _SplitKeyVal(opt, data):
474 a8469393 Iustin Pop
  """Convert a KeyVal string into a dict.
475 a8469393 Iustin Pop

476 a8469393 Iustin Pop
  This function will convert a key=val[,...] string into a dict. Empty
477 a8469393 Iustin Pop
  values will be converted specially: keys which have the prefix 'no_'
478 a8469393 Iustin Pop
  will have the value=False and the prefix stripped, the others will
479 a8469393 Iustin Pop
  have value=True.
480 a8469393 Iustin Pop

481 a8469393 Iustin Pop
  @type opt: string
482 a8469393 Iustin Pop
  @param opt: a string holding the option name for which we process the
483 a8469393 Iustin Pop
      data, used in building error messages
484 a8469393 Iustin Pop
  @type data: string
485 a8469393 Iustin Pop
  @param data: a string of the format key=val,key=val,...
486 a8469393 Iustin Pop
  @rtype: dict
487 a8469393 Iustin Pop
  @return: {key=val, key=val}
488 a8469393 Iustin Pop
  @raises errors.ParameterError: if there are duplicate keys
489 a8469393 Iustin Pop

490 a8469393 Iustin Pop
  """
491 a8469393 Iustin Pop
  kv_dict = {}
492 4f31882e Guido Trotter
  if data:
493 1b3a7656 Iustin Pop
    for elem in utils.UnescapeAndSplit(data, sep=","):
494 4f31882e Guido Trotter
      if "=" in elem:
495 4f31882e Guido Trotter
        key, val = elem.split("=", 1)
496 a8469393 Iustin Pop
      else:
497 4f31882e Guido Trotter
        if elem.startswith(NO_PREFIX):
498 4f31882e Guido Trotter
          key, val = elem[len(NO_PREFIX):], False
499 4f31882e Guido Trotter
        elif elem.startswith(UN_PREFIX):
500 4f31882e Guido Trotter
          key, val = elem[len(UN_PREFIX):], None
501 4f31882e Guido Trotter
        else:
502 4f31882e Guido Trotter
          key, val = elem, True
503 4f31882e Guido Trotter
      if key in kv_dict:
504 4f31882e Guido Trotter
        raise errors.ParameterError("Duplicate key '%s' in option %s" %
505 4f31882e Guido Trotter
                                    (key, opt))
506 4f31882e Guido Trotter
      kv_dict[key] = val
507 a8469393 Iustin Pop
  return kv_dict
508 a8469393 Iustin Pop
509 a8469393 Iustin Pop
510 8929d28c Iustin Pop
def check_ident_key_val(option, opt, value):  # pylint: disable-msg=W0613
511 552c8dff Michael Hanselmann
  """Custom parser for ident:key=val,key=val options.
512 552c8dff Michael Hanselmann

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

516 a8469393 Iustin Pop
  """
517 a8469393 Iustin Pop
  if ":" not in value:
518 8b46606c Guido Trotter
    ident, rest = value, ''
519 a8469393 Iustin Pop
  else:
520 a8469393 Iustin Pop
    ident, rest = value.split(":", 1)
521 8b46606c Guido Trotter
522 8b46606c Guido Trotter
  if ident.startswith(NO_PREFIX):
523 8b46606c Guido Trotter
    if rest:
524 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
525 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
526 8b46606c Guido Trotter
    retval = (ident[len(NO_PREFIX):], False)
527 8b46606c Guido Trotter
  elif ident.startswith(UN_PREFIX):
528 8b46606c Guido Trotter
    if rest:
529 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
530 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
531 8b46606c Guido Trotter
    retval = (ident[len(UN_PREFIX):], None)
532 8b46606c Guido Trotter
  else:
533 a8469393 Iustin Pop
    kv_dict = _SplitKeyVal(opt, rest)
534 a8469393 Iustin Pop
    retval = (ident, kv_dict)
535 a8469393 Iustin Pop
  return retval
536 a8469393 Iustin Pop
537 a8469393 Iustin Pop
538 8929d28c Iustin Pop
def check_key_val(option, opt, value):  # pylint: disable-msg=W0613
539 552c8dff Michael Hanselmann
  """Custom parser class for key=val,key=val options.
540 552c8dff Michael Hanselmann

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

543 a8469393 Iustin Pop
  """
544 a8469393 Iustin Pop
  return _SplitKeyVal(opt, value)
545 a8469393 Iustin Pop
546 a8469393 Iustin Pop
547 e7b61bb0 Iustin Pop
def check_bool(option, opt, value): # pylint: disable-msg=W0613
548 e7b61bb0 Iustin Pop
  """Custom parser for yes/no options.
549 e7b61bb0 Iustin Pop

550 e7b61bb0 Iustin Pop
  This will store the parsed value as either True or False.
551 e7b61bb0 Iustin Pop

552 e7b61bb0 Iustin Pop
  """
553 e7b61bb0 Iustin Pop
  value = value.lower()
554 e7b61bb0 Iustin Pop
  if value == constants.VALUE_FALSE or value == "no":
555 e7b61bb0 Iustin Pop
    return False
556 e7b61bb0 Iustin Pop
  elif value == constants.VALUE_TRUE or value == "yes":
557 e7b61bb0 Iustin Pop
    return True
558 e7b61bb0 Iustin Pop
  else:
559 e7b61bb0 Iustin Pop
    raise errors.ParameterError("Invalid boolean value '%s'" % value)
560 e7b61bb0 Iustin Pop
561 e7b61bb0 Iustin Pop
562 63d44c55 Michael Hanselmann
# completion_suggestion is normally a list. Using numeric values not evaluating
563 63d44c55 Michael Hanselmann
# to False for dynamic completion.
564 63d44c55 Michael Hanselmann
(OPT_COMPL_MANY_NODES,
565 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_NODE,
566 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_INSTANCE,
567 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_OS,
568 2d3ed64b Michael Hanselmann
 OPT_COMPL_ONE_IALLOCATOR,
569 36e247e1 Guido Trotter
 OPT_COMPL_INST_ADD_NODES,
570 36e247e1 Guido Trotter
 OPT_COMPL_ONE_NODEGROUP) = range(100, 107)
571 63d44c55 Michael Hanselmann
572 63d44c55 Michael Hanselmann
OPT_COMPL_ALL = frozenset([
573 63d44c55 Michael Hanselmann
  OPT_COMPL_MANY_NODES,
574 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_NODE,
575 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_INSTANCE,
576 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_OS,
577 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_IALLOCATOR,
578 2d3ed64b Michael Hanselmann
  OPT_COMPL_INST_ADD_NODES,
579 36e247e1 Guido Trotter
  OPT_COMPL_ONE_NODEGROUP,
580 63d44c55 Michael Hanselmann
  ])
581 63d44c55 Michael Hanselmann
582 63d44c55 Michael Hanselmann
583 552c8dff Michael Hanselmann
class CliOption(Option):
584 552c8dff Michael Hanselmann
  """Custom option class for optparse.
585 a8469393 Iustin Pop

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

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

1261 c41eea6e Iustin Pop
  @param argv: the command line
1262 c41eea6e Iustin Pop
  @param commands: dictionary with special contents, see the design
1263 c41eea6e Iustin Pop
      doc for cmdline handling
1264 c41eea6e Iustin Pop
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
1265 098c0958 Michael Hanselmann

1266 a8083063 Iustin Pop
  """
1267 a8083063 Iustin Pop
  if len(argv) == 0:
1268 a8083063 Iustin Pop
    binary = "<command>"
1269 a8083063 Iustin Pop
  else:
1270 a8083063 Iustin Pop
    binary = argv[0].split("/")[-1]
1271 a8083063 Iustin Pop
1272 a8083063 Iustin Pop
  if len(argv) > 1 and argv[1] == "--version":
1273 84a12e40 Iustin Pop
    ToStdout("%s (ganeti %s) %s", binary, constants.VCS_VERSION,
1274 84a12e40 Iustin Pop
             constants.RELEASE_VERSION)
1275 a8083063 Iustin Pop
    # Quit right away. That way we don't have to care about this special
1276 a8083063 Iustin Pop
    # argument. optparse.py does it the same.
1277 a8083063 Iustin Pop
    sys.exit(0)
1278 a8083063 Iustin Pop
1279 de47cf8f Guido Trotter
  if len(argv) < 2 or not (argv[1] in commands or
1280 70a35b6f Guido Trotter
                           argv[1] in aliases):
1281 a8083063 Iustin Pop
    # let's do a nice thing
1282 a8083063 Iustin Pop
    sortedcmds = commands.keys()
1283 a8083063 Iustin Pop
    sortedcmds.sort()
1284 03298ebe Michael Hanselmann
1285 03298ebe Michael Hanselmann
    ToStdout("Usage: %s {command} [options...] [argument...]", binary)
1286 03298ebe Michael Hanselmann
    ToStdout("%s <command> --help to see details, or man %s", binary, binary)
1287 03298ebe Michael Hanselmann
    ToStdout("")
1288 03298ebe Michael Hanselmann
1289 a8083063 Iustin Pop
    # compute the max line length for cmd + usage
1290 4e713df6 Iustin Pop
    mlen = max([len(" %s" % cmd) for cmd in commands])
1291 a8083063 Iustin Pop
    mlen = min(60, mlen) # should not get here...
1292 03298ebe Michael Hanselmann
1293 a8083063 Iustin Pop
    # and format a nice command list
1294 03298ebe Michael Hanselmann
    ToStdout("Commands:")
1295 a8083063 Iustin Pop
    for cmd in sortedcmds:
1296 4e713df6 Iustin Pop
      cmdstr = " %s" % (cmd,)
1297 9a033156 Iustin Pop
      help_text = commands[cmd][4]
1298 03298ebe Michael Hanselmann
      help_lines = textwrap.wrap(help_text, 79 - 3 - mlen)
1299 03298ebe Michael Hanselmann
      ToStdout("%-*s - %s", mlen, cmdstr, help_lines.pop(0))
1300 a8083063 Iustin Pop
      for line in help_lines:
1301 03298ebe Michael Hanselmann
        ToStdout("%-*s   %s", mlen, "", line)
1302 03298ebe Michael Hanselmann
1303 03298ebe Michael Hanselmann
    ToStdout("")
1304 03298ebe Michael Hanselmann
1305 a8083063 Iustin Pop
    return None, None, None
1306 de47cf8f Guido Trotter
1307 de47cf8f Guido Trotter
  # get command, unalias it, and look it up in commands
1308 a8083063 Iustin Pop
  cmd = argv.pop(1)
1309 de47cf8f Guido Trotter
  if cmd in aliases:
1310 de47cf8f Guido Trotter
    if cmd in commands:
1311 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' overrides an existing"
1312 de47cf8f Guido Trotter
                                   " command" % cmd)
1313 de47cf8f Guido Trotter
1314 de47cf8f Guido Trotter
    if aliases[cmd] not in commands:
1315 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' maps to non-existing"
1316 de47cf8f Guido Trotter
                                   " command '%s'" % (cmd, aliases[cmd]))
1317 de47cf8f Guido Trotter
1318 de47cf8f Guido Trotter
    cmd = aliases[cmd]
1319 de47cf8f Guido Trotter
1320 a8005e17 Michael Hanselmann
  func, args_def, parser_opts, usage, description = commands[cmd]
1321 5786c087 Michael Hanselmann
  parser = OptionParser(option_list=parser_opts + COMMON_OPTS,
1322 a8083063 Iustin Pop
                        description=description,
1323 a8083063 Iustin Pop
                        formatter=TitledHelpFormatter(),
1324 a8083063 Iustin Pop
                        usage="%%prog %s %s" % (cmd, usage))
1325 a8083063 Iustin Pop
  parser.disable_interspersed_args()
1326 a8083063 Iustin Pop
  options, args = parser.parse_args()
1327 a8005e17 Michael Hanselmann
1328 a8005e17 Michael Hanselmann
  if not _CheckArguments(cmd, args_def, args):
1329 a8083063 Iustin Pop
    return None, None, None
1330 a8083063 Iustin Pop
1331 a8083063 Iustin Pop
  return func, options, args
1332 a8083063 Iustin Pop
1333 a8083063 Iustin Pop
1334 a8005e17 Michael Hanselmann
def _CheckArguments(cmd, args_def, args):
1335 a8005e17 Michael Hanselmann
  """Verifies the arguments using the argument definition.
1336 a8005e17 Michael Hanselmann

1337 a8005e17 Michael Hanselmann
  Algorithm:
1338 a8005e17 Michael Hanselmann

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

1341 a8005e17 Michael Hanselmann
    1. For each argument in definition
1342 a8005e17 Michael Hanselmann

1343 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
1344 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
1345 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
1346 a8005e17 Michael Hanselmann

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

1349 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
1350 a8005e17 Michael Hanselmann

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

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

1355 a8005e17 Michael Hanselmann
  """
1356 a8005e17 Michael Hanselmann
  if args and not args_def:
1357 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects no arguments", cmd)
1358 a8005e17 Michael Hanselmann
    return False
1359 a8005e17 Michael Hanselmann
1360 a8005e17 Michael Hanselmann
  min_count = None
1361 a8005e17 Michael Hanselmann
  max_count = None
1362 a8005e17 Michael Hanselmann
  check_max = None
1363 a8005e17 Michael Hanselmann
1364 a8005e17 Michael Hanselmann
  last_idx = len(args_def) - 1
1365 a8005e17 Michael Hanselmann
1366 a8005e17 Michael Hanselmann
  for idx, arg in enumerate(args_def):
1367 a8005e17 Michael Hanselmann
    if min_count is None:
1368 a8005e17 Michael Hanselmann
      min_count = arg.min
1369 a8005e17 Michael Hanselmann
    elif arg.min is not None:
1370 a8005e17 Michael Hanselmann
      min_count += arg.min
1371 a8005e17 Michael Hanselmann
1372 a8005e17 Michael Hanselmann
    if max_count is None:
1373 a8005e17 Michael Hanselmann
      max_count = arg.max
1374 a8005e17 Michael Hanselmann
    elif arg.max is not None:
1375 a8005e17 Michael Hanselmann
      max_count += arg.max
1376 a8005e17 Michael Hanselmann
1377 a8005e17 Michael Hanselmann
    if idx == last_idx:
1378 a8005e17 Michael Hanselmann
      check_max = (arg.max is not None)
1379 a8005e17 Michael Hanselmann
1380 a8005e17 Michael Hanselmann
    elif arg.max is None:
1381 a8005e17 Michael Hanselmann
      raise errors.ProgrammerError("Only the last argument can have max=None")
1382 a8005e17 Michael Hanselmann
1383 a8005e17 Michael Hanselmann
  if check_max:
1384 a8005e17 Michael Hanselmann
    # Command with exact number of arguments
1385 a8005e17 Michael Hanselmann
    if (min_count is not None and max_count is not None and
1386 a8005e17 Michael Hanselmann
        min_count == max_count and len(args) != min_count):
1387 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects %d argument(s)", cmd, min_count)
1388 a8005e17 Michael Hanselmann
      return False
1389 a8005e17 Michael Hanselmann
1390 a8005e17 Michael Hanselmann
    # Command with limited number of arguments
1391 a8005e17 Michael Hanselmann
    if max_count is not None and len(args) > max_count:
1392 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects only %d argument(s)",
1393 a8005e17 Michael Hanselmann
               cmd, max_count)
1394 a8005e17 Michael Hanselmann
      return False
1395 a8005e17 Michael Hanselmann
1396 a8005e17 Michael Hanselmann
  # Command with some required arguments
1397 a8005e17 Michael Hanselmann
  if min_count is not None and len(args) < min_count:
1398 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects at least %d argument(s)",
1399 a8005e17 Michael Hanselmann
             cmd, min_count)
1400 a8005e17 Michael Hanselmann
    return False
1401 a8005e17 Michael Hanselmann
1402 a8005e17 Michael Hanselmann
  return True
1403 a8005e17 Michael Hanselmann
1404 a8005e17 Michael Hanselmann
1405 60d49723 Michael Hanselmann
def SplitNodeOption(value):
1406 60d49723 Michael Hanselmann
  """Splits the value of a --node option.
1407 60d49723 Michael Hanselmann

1408 60d49723 Michael Hanselmann
  """
1409 60d49723 Michael Hanselmann
  if value and ':' in value:
1410 60d49723 Michael Hanselmann
    return value.split(':', 1)
1411 60d49723 Michael Hanselmann
  else:
1412 60d49723 Michael Hanselmann
    return (value, None)
1413 60d49723 Michael Hanselmann
1414 60d49723 Michael Hanselmann
1415 07150497 Guido Trotter
def CalculateOSNames(os_name, os_variants):
1416 07150497 Guido Trotter
  """Calculates all the names an OS can be called, according to its variants.
1417 07150497 Guido Trotter

1418 07150497 Guido Trotter
  @type os_name: string
1419 07150497 Guido Trotter
  @param os_name: base name of the os
1420 07150497 Guido Trotter
  @type os_variants: list or None
1421 07150497 Guido Trotter
  @param os_variants: list of supported variants
1422 07150497 Guido Trotter
  @rtype: list
1423 07150497 Guido Trotter
  @return: list of valid names
1424 07150497 Guido Trotter

1425 07150497 Guido Trotter
  """
1426 07150497 Guido Trotter
  if os_variants:
1427 07150497 Guido Trotter
    return ['%s+%s' % (os_name, v) for v in os_variants]
1428 07150497 Guido Trotter
  else:
1429 07150497 Guido Trotter
    return [os_name]
1430 07150497 Guido Trotter
1431 07150497 Guido Trotter
1432 a4ebd726 Michael Hanselmann
def ParseFields(selected, default):
1433 a4ebd726 Michael Hanselmann
  """Parses the values of "--field"-like options.
1434 a4ebd726 Michael Hanselmann

1435 a4ebd726 Michael Hanselmann
  @type selected: string or None
1436 a4ebd726 Michael Hanselmann
  @param selected: User-selected options
1437 a4ebd726 Michael Hanselmann
  @type default: list
1438 a4ebd726 Michael Hanselmann
  @param default: Default fields
1439 a4ebd726 Michael Hanselmann

1440 a4ebd726 Michael Hanselmann
  """
1441 a4ebd726 Michael Hanselmann
  if selected is None:
1442 a4ebd726 Michael Hanselmann
    return default
1443 a4ebd726 Michael Hanselmann
1444 a4ebd726 Michael Hanselmann
  if selected.startswith("+"):
1445 a4ebd726 Michael Hanselmann
    return default + selected[1:].split(",")
1446 a4ebd726 Michael Hanselmann
1447 a4ebd726 Michael Hanselmann
  return selected.split(",")
1448 a4ebd726 Michael Hanselmann
1449 a4ebd726 Michael Hanselmann
1450 e0e916fe Iustin Pop
UsesRPC = rpc.RunWithRPC
1451 4331f6cd Michael Hanselmann
1452 4331f6cd Michael Hanselmann
1453 47988778 Iustin Pop
def AskUser(text, choices=None):
1454 47988778 Iustin Pop
  """Ask the user a question.
1455 a8083063 Iustin Pop

1456 c41eea6e Iustin Pop
  @param text: the question to ask
1457 a8083063 Iustin Pop

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

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

1467 a8083063 Iustin Pop
  """
1468 47988778 Iustin Pop
  if choices is None:
1469 47988778 Iustin Pop
    choices = [('y', True, 'Perform the operation'),
1470 47988778 Iustin Pop
               ('n', False, 'Do not perform the operation')]
1471 47988778 Iustin Pop
  if not choices or not isinstance(choices, list):
1472 5bbd3f7f Michael Hanselmann
    raise errors.ProgrammerError("Invalid choices argument to AskUser")
1473 47988778 Iustin Pop
  for entry in choices:
1474 47988778 Iustin Pop
    if not isinstance(entry, tuple) or len(entry) < 3 or entry[0] == '?':
1475 5bbd3f7f Michael Hanselmann
      raise errors.ProgrammerError("Invalid choices element to AskUser")
1476 47988778 Iustin Pop
1477 47988778 Iustin Pop
  answer = choices[-1][1]
1478 47988778 Iustin Pop
  new_text = []
1479 47988778 Iustin Pop
  for line in text.splitlines():
1480 47988778 Iustin Pop
    new_text.append(textwrap.fill(line, 70, replace_whitespace=False))
1481 47988778 Iustin Pop
  text = "\n".join(new_text)
1482 a8083063 Iustin Pop
  try:
1483 3023170f Iustin Pop
    f = file("/dev/tty", "a+")
1484 a8083063 Iustin Pop
  except IOError:
1485 47988778 Iustin Pop
    return answer
1486 a8083063 Iustin Pop
  try:
1487 47988778 Iustin Pop
    chars = [entry[0] for entry in choices]
1488 47988778 Iustin Pop
    chars[-1] = "[%s]" % chars[-1]
1489 47988778 Iustin Pop
    chars.append('?')
1490 47988778 Iustin Pop
    maps = dict([(entry[0], entry[1]) for entry in choices])
1491 47988778 Iustin Pop
    while True:
1492 47988778 Iustin Pop
      f.write(text)
1493 47988778 Iustin Pop
      f.write('\n')
1494 47988778 Iustin Pop
      f.write("/".join(chars))
1495 47988778 Iustin Pop
      f.write(": ")
1496 47988778 Iustin Pop
      line = f.readline(2).strip().lower()
1497 47988778 Iustin Pop
      if line in maps:
1498 47988778 Iustin Pop
        answer = maps[line]
1499 47988778 Iustin Pop
        break
1500 47988778 Iustin Pop
      elif line == '?':
1501 47988778 Iustin Pop
        for entry in choices:
1502 47988778 Iustin Pop
          f.write(" %s - %s\n" % (entry[0], entry[2]))
1503 47988778 Iustin Pop
        f.write("\n")
1504 47988778 Iustin Pop
        continue
1505 a8083063 Iustin Pop
  finally:
1506 a8083063 Iustin Pop
    f.close()
1507 a8083063 Iustin Pop
  return answer
1508 a8083063 Iustin Pop
1509 a8083063 Iustin Pop
1510 e9d741b6 Iustin Pop
class JobSubmittedException(Exception):
1511 e9d741b6 Iustin Pop
  """Job was submitted, client should exit.
1512 e9d741b6 Iustin Pop

1513 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1514 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1515 e9d741b6 Iustin Pop

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

1518 e9d741b6 Iustin Pop
  """
1519 e9d741b6 Iustin Pop
1520 e9d741b6 Iustin Pop
1521 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1522 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1523 a8083063 Iustin Pop

1524 0a1e74d9 Iustin Pop
  @type ops: list
1525 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1526 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1527 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1528 0a1e74d9 Iustin Pop
             if None, a new client will be created
1529 a8083063 Iustin Pop

1530 a8083063 Iustin Pop
  """
1531 e2212007 Iustin Pop
  if cl is None:
1532 b33e986b Iustin Pop
    cl = GetClient()
1533 685ee993 Iustin Pop
1534 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1535 0a1e74d9 Iustin Pop
1536 0a1e74d9 Iustin Pop
  return job_id
1537 0a1e74d9 Iustin Pop
1538 0a1e74d9 Iustin Pop
1539 4e338533 Michael Hanselmann
def GenericPollJob(job_id, cbs, report_cbs):
1540 4e338533 Michael Hanselmann
  """Generic job-polling function.
1541 0a1e74d9 Iustin Pop

1542 4e338533 Michael Hanselmann
  @type job_id: number
1543 4e338533 Michael Hanselmann
  @param job_id: Job ID
1544 4e338533 Michael Hanselmann
  @type cbs: Instance of L{JobPollCbBase}
1545 4e338533 Michael Hanselmann
  @param cbs: Data callbacks
1546 4e338533 Michael Hanselmann
  @type report_cbs: Instance of L{JobPollReportCbBase}
1547 4e338533 Michael Hanselmann
  @param report_cbs: Reporting callbacks
1548 0a1e74d9 Iustin Pop

1549 0a1e74d9 Iustin Pop
  """
1550 6c5a7090 Michael Hanselmann
  prev_job_info = None
1551 6c5a7090 Michael Hanselmann
  prev_logmsg_serial = None
1552 6c5a7090 Michael Hanselmann
1553 f4484122 Michael Hanselmann
  status = None
1554 f4484122 Michael Hanselmann
1555 685ee993 Iustin Pop
  while True:
1556 4e338533 Michael Hanselmann
    result = cbs.WaitForJobChangeOnce(job_id, ["status"], prev_job_info,
1557 4e338533 Michael Hanselmann
                                      prev_logmsg_serial)
1558 6c5a7090 Michael Hanselmann
    if not result:
1559 685ee993 Iustin Pop
      # job not found, go away!
1560 0bbe448c Michael Hanselmann
      raise errors.JobLost("Job with id %s lost" % job_id)
1561 4e338533 Michael Hanselmann
1562 4e338533 Michael Hanselmann
    if result == constants.JOB_NOTCHANGED:
1563 4e338533 Michael Hanselmann
      report_cbs.ReportNotChanged(job_id, status)
1564 f4484122 Michael Hanselmann
1565 f4484122 Michael Hanselmann
      # Wait again
1566 f4484122 Michael Hanselmann
      continue
1567 685ee993 Iustin Pop
1568 6c5a7090 Michael Hanselmann
    # Split result, a tuple of (field values, log entries)
1569 6c5a7090 Michael Hanselmann
    (job_info, log_entries) = result
1570 6c5a7090 Michael Hanselmann
    (status, ) = job_info
1571 6c5a7090 Michael Hanselmann
1572 6c5a7090 Michael Hanselmann
    if log_entries:
1573 6c5a7090 Michael Hanselmann
      for log_entry in log_entries:
1574 4e338533 Michael Hanselmann
        (serial, timestamp, log_type, message) = log_entry
1575 4e338533 Michael Hanselmann
        report_cbs.ReportLogMessage(job_id, serial, timestamp,
1576 4e338533 Michael Hanselmann
                                    log_type, message)
1577 6c5a7090 Michael Hanselmann
        prev_logmsg_serial = max(prev_logmsg_serial, serial)
1578 6c5a7090 Michael Hanselmann
1579 0bbe448c Michael Hanselmann
    # TODO: Handle canceled and archived jobs
1580 fbf0262f Michael Hanselmann
    elif status in (constants.JOB_STATUS_SUCCESS,
1581 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_ERROR,
1582 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELING,
1583 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELED):
1584 685ee993 Iustin Pop
      break
1585 6c5a7090 Michael Hanselmann
1586 6c5a7090 Michael Hanselmann
    prev_job_info = job_info
1587 685ee993 Iustin Pop
1588 4e338533 Michael Hanselmann
  jobs = cbs.QueryJobs([job_id], ["status", "opstatus", "opresult"])
1589 0bbe448c Michael Hanselmann
  if not jobs:
1590 0bbe448c Michael Hanselmann
    raise errors.JobLost("Job with id %s lost" % job_id)
1591 685ee993 Iustin Pop
1592 0e050889 Iustin Pop
  status, opstatus, result = jobs[0]
1593 4e338533 Michael Hanselmann
1594 0bbe448c Michael Hanselmann
  if status == constants.JOB_STATUS_SUCCESS:
1595 53c04d04 Iustin Pop
    return result
1596 4e338533 Michael Hanselmann
1597 4e338533 Michael Hanselmann
  if status in (constants.JOB_STATUS_CANCELING, constants.JOB_STATUS_CANCELED):
1598 fbf0262f Michael Hanselmann
    raise errors.OpExecError("Job was canceled")
1599 4e338533 Michael Hanselmann
1600 4e338533 Michael Hanselmann
  has_ok = False
1601 4e338533 Michael Hanselmann
  for idx, (status, msg) in enumerate(zip(opstatus, result)):
1602 4e338533 Michael Hanselmann
    if status == constants.OP_STATUS_SUCCESS:
1603 4e338533 Michael Hanselmann
      has_ok = True
1604 4e338533 Michael Hanselmann
    elif status == constants.OP_STATUS_ERROR:
1605 4e338533 Michael Hanselmann
      errors.MaybeRaise(msg)
1606 4e338533 Michael Hanselmann
1607 4e338533 Michael Hanselmann
      if has_ok:
1608 4e338533 Michael Hanselmann
        raise errors.OpExecError("partial failure (opcode %d): %s" %
1609 4e338533 Michael Hanselmann
                                 (idx, msg))
1610 4e338533 Michael Hanselmann
1611 4e338533 Michael Hanselmann
      raise errors.OpExecError(str(msg))
1612 4e338533 Michael Hanselmann
1613 4e338533 Michael Hanselmann
  # default failure mode
1614 4e338533 Michael Hanselmann
  raise errors.OpExecError(result)
1615 4e338533 Michael Hanselmann
1616 4e338533 Michael Hanselmann
1617 4e338533 Michael Hanselmann
class JobPollCbBase:
1618 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} callbacks.
1619 4e338533 Michael Hanselmann

1620 4e338533 Michael Hanselmann
  """
1621 4e338533 Michael Hanselmann
  def __init__(self):
1622 4e338533 Michael Hanselmann
    """Initializes this class.
1623 4e338533 Michael Hanselmann

1624 4e338533 Michael Hanselmann
    """
1625 4e338533 Michael Hanselmann
1626 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1627 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1628 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1629 4e338533 Michael Hanselmann

1630 4e338533 Michael Hanselmann
    """
1631 4e338533 Michael Hanselmann
    raise NotImplementedError()
1632 4e338533 Michael Hanselmann
1633 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1634 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1635 4e338533 Michael Hanselmann

1636 4e338533 Michael Hanselmann
    @type job_ids: list of numbers
1637 4e338533 Michael Hanselmann
    @param job_ids: Job IDs
1638 4e338533 Michael Hanselmann
    @type fields: list of strings
1639 4e338533 Michael Hanselmann
    @param fields: Fields
1640 4e338533 Michael Hanselmann

1641 4e338533 Michael Hanselmann
    """
1642 4e338533 Michael Hanselmann
    raise NotImplementedError()
1643 4e338533 Michael Hanselmann
1644 4e338533 Michael Hanselmann
1645 4e338533 Michael Hanselmann
class JobPollReportCbBase:
1646 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} reporting callbacks.
1647 4e338533 Michael Hanselmann

1648 4e338533 Michael Hanselmann
  """
1649 4e338533 Michael Hanselmann
  def __init__(self):
1650 4e338533 Michael Hanselmann
    """Initializes this class.
1651 4e338533 Michael Hanselmann

1652 4e338533 Michael Hanselmann
    """
1653 4e338533 Michael Hanselmann
1654 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1655 4e338533 Michael Hanselmann
    """Handles a log message.
1656 4e338533 Michael Hanselmann

1657 4e338533 Michael Hanselmann
    """
1658 4e338533 Michael Hanselmann
    raise NotImplementedError()
1659 4e338533 Michael Hanselmann
1660 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1661 4e338533 Michael Hanselmann
    """Called for if a job hasn't changed in a while.
1662 4e338533 Michael Hanselmann

1663 4e338533 Michael Hanselmann
    @type job_id: number
1664 4e338533 Michael Hanselmann
    @param job_id: Job ID
1665 4e338533 Michael Hanselmann
    @type status: string or None
1666 4e338533 Michael Hanselmann
    @param status: Job status if available
1667 4e338533 Michael Hanselmann

1668 4e338533 Michael Hanselmann
    """
1669 4e338533 Michael Hanselmann
    raise NotImplementedError()
1670 4e338533 Michael Hanselmann
1671 4e338533 Michael Hanselmann
1672 4e338533 Michael Hanselmann
class _LuxiJobPollCb(JobPollCbBase):
1673 4e338533 Michael Hanselmann
  def __init__(self, cl):
1674 4e338533 Michael Hanselmann
    """Initializes this class.
1675 4e338533 Michael Hanselmann

1676 4e338533 Michael Hanselmann
    """
1677 4e338533 Michael Hanselmann
    JobPollCbBase.__init__(self)
1678 4e338533 Michael Hanselmann
    self.cl = cl
1679 4e338533 Michael Hanselmann
1680 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1681 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1682 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1683 4e338533 Michael Hanselmann

1684 4e338533 Michael Hanselmann
    """
1685 4e338533 Michael Hanselmann
    return self.cl.WaitForJobChangeOnce(job_id, fields,
1686 4e338533 Michael Hanselmann
                                        prev_job_info, prev_log_serial)
1687 4e338533 Michael Hanselmann
1688 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1689 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1690 4e338533 Michael Hanselmann

1691 4e338533 Michael Hanselmann
    """
1692 4e338533 Michael Hanselmann
    return self.cl.QueryJobs(job_ids, fields)
1693 4e338533 Michael Hanselmann
1694 4e338533 Michael Hanselmann
1695 4e338533 Michael Hanselmann
class FeedbackFnJobPollReportCb(JobPollReportCbBase):
1696 4e338533 Michael Hanselmann
  def __init__(self, feedback_fn):
1697 4e338533 Michael Hanselmann
    """Initializes this class.
1698 4e338533 Michael Hanselmann

1699 4e338533 Michael Hanselmann
    """
1700 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1701 4e338533 Michael Hanselmann
1702 4e338533 Michael Hanselmann
    self.feedback_fn = feedback_fn
1703 4e338533 Michael Hanselmann
1704 4e338533 Michael Hanselmann
    assert callable(feedback_fn)
1705 4e338533 Michael Hanselmann
1706 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1707 4e338533 Michael Hanselmann
    """Handles a log message.
1708 4e338533 Michael Hanselmann

1709 4e338533 Michael Hanselmann
    """
1710 4e338533 Michael Hanselmann
    self.feedback_fn((timestamp, log_type, log_msg))
1711 4e338533 Michael Hanselmann
1712 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1713 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1714 4e338533 Michael Hanselmann

1715 4e338533 Michael Hanselmann
    """
1716 4e338533 Michael Hanselmann
    # Ignore
1717 4e338533 Michael Hanselmann
1718 4e338533 Michael Hanselmann
1719 4e338533 Michael Hanselmann
class StdioJobPollReportCb(JobPollReportCbBase):
1720 4e338533 Michael Hanselmann
  def __init__(self):
1721 4e338533 Michael Hanselmann
    """Initializes this class.
1722 4e338533 Michael Hanselmann

1723 4e338533 Michael Hanselmann
    """
1724 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1725 4e338533 Michael Hanselmann
1726 4e338533 Michael Hanselmann
    self.notified_queued = False
1727 4e338533 Michael Hanselmann
    self.notified_waitlock = False
1728 4e338533 Michael Hanselmann
1729 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1730 4e338533 Michael Hanselmann
    """Handles a log message.
1731 4e338533 Michael Hanselmann

1732 4e338533 Michael Hanselmann
    """
1733 4e338533 Michael Hanselmann
    ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)),
1734 8a7f1c61 Michael Hanselmann
             FormatLogMessage(log_type, log_msg))
1735 4e338533 Michael Hanselmann
1736 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1737 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1738 4e338533 Michael Hanselmann

1739 4e338533 Michael Hanselmann
    """
1740 4e338533 Michael Hanselmann
    if status is None:
1741 4e338533 Michael Hanselmann
      return
1742 4e338533 Michael Hanselmann
1743 4e338533 Michael Hanselmann
    if status == constants.JOB_STATUS_QUEUED and not self.notified_queued:
1744 4e338533 Michael Hanselmann
      ToStderr("Job %s is waiting in queue", job_id)
1745 4e338533 Michael Hanselmann
      self.notified_queued = True
1746 4e338533 Michael Hanselmann
1747 4e338533 Michael Hanselmann
    elif status == constants.JOB_STATUS_WAITLOCK and not self.notified_waitlock:
1748 4e338533 Michael Hanselmann
      ToStderr("Job %s is trying to acquire all necessary locks", job_id)
1749 4e338533 Michael Hanselmann
      self.notified_waitlock = True
1750 4e338533 Michael Hanselmann
1751 4e338533 Michael Hanselmann
1752 8a7f1c61 Michael Hanselmann
def FormatLogMessage(log_type, log_msg):
1753 8a7f1c61 Michael Hanselmann
  """Formats a job message according to its type.
1754 8a7f1c61 Michael Hanselmann

1755 8a7f1c61 Michael Hanselmann
  """
1756 8a7f1c61 Michael Hanselmann
  if log_type != constants.ELOG_MESSAGE:
1757 8a7f1c61 Michael Hanselmann
    log_msg = str(log_msg)
1758 8a7f1c61 Michael Hanselmann
1759 8a7f1c61 Michael Hanselmann
  return utils.SafeEncode(log_msg)
1760 8a7f1c61 Michael Hanselmann
1761 8a7f1c61 Michael Hanselmann
1762 583163a6 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None, reporter=None):
1763 4e338533 Michael Hanselmann
  """Function to poll for the result of a job.
1764 4e338533 Michael Hanselmann

1765 4e338533 Michael Hanselmann
  @type job_id: job identified
1766 4e338533 Michael Hanselmann
  @param job_id: the job to poll for results
1767 4e338533 Michael Hanselmann
  @type cl: luxi.Client
1768 4e338533 Michael Hanselmann
  @param cl: the luxi client to use for communicating with the master;
1769 4e338533 Michael Hanselmann
             if None, a new client will be created
1770 4e338533 Michael Hanselmann

1771 4e338533 Michael Hanselmann
  """
1772 4e338533 Michael Hanselmann
  if cl is None:
1773 4e338533 Michael Hanselmann
    cl = GetClient()
1774 4e338533 Michael Hanselmann
1775 583163a6 Michael Hanselmann
  if reporter is None:
1776 583163a6 Michael Hanselmann
    if feedback_fn:
1777 583163a6 Michael Hanselmann
      reporter = FeedbackFnJobPollReportCb(feedback_fn)
1778 583163a6 Michael Hanselmann
    else:
1779 583163a6 Michael Hanselmann
      reporter = StdioJobPollReportCb()
1780 583163a6 Michael Hanselmann
  elif feedback_fn:
1781 583163a6 Michael Hanselmann
    raise errors.ProgrammerError("Can't specify reporter and feedback function")
1782 4e338533 Michael Hanselmann
1783 4e338533 Michael Hanselmann
  return GenericPollJob(job_id, _LuxiJobPollCb(cl), reporter)
1784 ceab32dd Iustin Pop
1785 ceab32dd Iustin Pop
1786 583163a6 Michael Hanselmann
def SubmitOpCode(op, cl=None, feedback_fn=None, opts=None, reporter=None):
1787 0a1e74d9 Iustin Pop
  """Legacy function to submit an opcode.
1788 0a1e74d9 Iustin Pop

1789 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1790 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1791 0a1e74d9 Iustin Pop
  interaction functions.
1792 0a1e74d9 Iustin Pop

1793 0a1e74d9 Iustin Pop
  """
1794 0a1e74d9 Iustin Pop
  if cl is None:
1795 0a1e74d9 Iustin Pop
    cl = GetClient()
1796 0a1e74d9 Iustin Pop
1797 293ba2d8 Iustin Pop
  SetGenericOpcodeOpts([op], opts)
1798 293ba2d8 Iustin Pop
1799 5d297d8a Michael Hanselmann
  job_id = SendJob([op], cl=cl)
1800 0a1e74d9 Iustin Pop
1801 583163a6 Michael Hanselmann
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn,
1802 583163a6 Michael Hanselmann
                       reporter=reporter)
1803 53c04d04 Iustin Pop
1804 53c04d04 Iustin Pop
  return op_results[0]
1805 0a1e74d9 Iustin Pop
1806 0a1e74d9 Iustin Pop
1807 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1808 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1809 94428652 Iustin Pop

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

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

1818 94428652 Iustin Pop
  """
1819 94428652 Iustin Pop
  if opts and opts.submit_only:
1820 293ba2d8 Iustin Pop
    job = [op]
1821 293ba2d8 Iustin Pop
    SetGenericOpcodeOpts(job, opts)
1822 293ba2d8 Iustin Pop
    job_id = SendJob(job, cl=cl)
1823 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
1824 94428652 Iustin Pop
  else:
1825 293ba2d8 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
1826 293ba2d8 Iustin Pop
1827 293ba2d8 Iustin Pop
1828 293ba2d8 Iustin Pop
def SetGenericOpcodeOpts(opcode_list, options):
1829 293ba2d8 Iustin Pop
  """Processor for generic options.
1830 293ba2d8 Iustin Pop

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

1834 293ba2d8 Iustin Pop
  @param opcode_list: list of opcodes
1835 293ba2d8 Iustin Pop
  @param options: command line options or None
1836 293ba2d8 Iustin Pop
  @return: None (in-place modification)
1837 293ba2d8 Iustin Pop

1838 293ba2d8 Iustin Pop
  """
1839 293ba2d8 Iustin Pop
  if not options:
1840 293ba2d8 Iustin Pop
    return
1841 293ba2d8 Iustin Pop
  for op in opcode_list:
1842 aa06f8c6 Michael Hanselmann
    op.debug_level = options.debug
1843 a0a6ff34 Iustin Pop
    if hasattr(options, "dry_run"):
1844 a0a6ff34 Iustin Pop
      op.dry_run = options.dry_run
1845 aa06f8c6 Michael Hanselmann
    if getattr(options, "priority", None) is not None:
1846 aa06f8c6 Michael Hanselmann
      op.priority = _PRIONAME_TO_VALUE[options.priority]
1847 94428652 Iustin Pop
1848 94428652 Iustin Pop
1849 af30b2fd Michael Hanselmann
def GetClient():
1850 af30b2fd Michael Hanselmann
  # TODO: Cache object?
1851 b33e986b Iustin Pop
  try:
1852 b33e986b Iustin Pop
    client = luxi.Client()
1853 b33e986b Iustin Pop
  except luxi.NoMasterError:
1854 d9a51679 Michael Hanselmann
    ss = ssconf.SimpleStore()
1855 d9a51679 Michael Hanselmann
1856 d9a51679 Michael Hanselmann
    # Try to read ssconf file
1857 d9a51679 Michael Hanselmann
    try:
1858 d9a51679 Michael Hanselmann
      ss.GetMasterNode()
1859 d9a51679 Michael Hanselmann
    except errors.ConfigurationError:
1860 d9a51679 Michael Hanselmann
      raise errors.OpPrereqError("Cluster not initialized or this machine is"
1861 d9a51679 Michael Hanselmann
                                 " not part of a cluster")
1862 d9a51679 Michael Hanselmann
1863 d9a51679 Michael Hanselmann
    master, myself = ssconf.GetMasterAndMyself(ss=ss)
1864 b33e986b Iustin Pop
    if master != myself:
1865 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
1866 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
1867 b33e986b Iustin Pop
                                 master)
1868 d9a51679 Michael Hanselmann
    raise
1869 b33e986b Iustin Pop
  return client
1870 af30b2fd Michael Hanselmann
1871 af30b2fd Michael Hanselmann
1872 73702ee7 Iustin Pop
def FormatError(err):
1873 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
1874 73702ee7 Iustin Pop

1875 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
1876 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
1877 73702ee7 Iustin Pop
  second, a string describing the error message (not
1878 73702ee7 Iustin Pop
  newline-terminated).
1879 73702ee7 Iustin Pop

1880 73702ee7 Iustin Pop
  """
1881 73702ee7 Iustin Pop
  retcode = 1
1882 73702ee7 Iustin Pop
  obuf = StringIO()
1883 e2e521d0 Iustin Pop
  msg = str(err)
1884 73702ee7 Iustin Pop
  if isinstance(err, errors.ConfigurationError):
1885 e2e521d0 Iustin Pop
    txt = "Corrupt configuration file: %s" % msg
1886 46fbdd04 Iustin Pop
    logging.error(txt)
1887 e2e521d0 Iustin Pop
    obuf.write(txt + "\n")
1888 73702ee7 Iustin Pop
    obuf.write("Aborting.")
1889 73702ee7 Iustin Pop
    retcode = 2
1890 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksAbort):
1891 73702ee7 Iustin Pop
    obuf.write("Failure: hooks execution failed:\n")
1892 73702ee7 Iustin Pop
    for node, script, out in err.args[0]:
1893 73702ee7 Iustin Pop
      if out:
1894 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s, output: %s\n" %
1895 73702ee7 Iustin Pop
                   (node, script, out))
1896 73702ee7 Iustin Pop
      else:
1897 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s (no output)\n" %
1898 73702ee7 Iustin Pop
                   (node, script))
1899 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksFailure):
1900 e2e521d0 Iustin Pop
    obuf.write("Failure: hooks general failure: %s" % msg)
1901 73702ee7 Iustin Pop
  elif isinstance(err, errors.ResolverError):
1902 b705c7a6 Manuel Franceschini
    this_host = netutils.Hostname.GetSysName()
1903 73702ee7 Iustin Pop
    if err.args[0] == this_host:
1904 73702ee7 Iustin Pop
      msg = "Failure: can't resolve my own hostname ('%s')"
1905 73702ee7 Iustin Pop
    else:
1906 73702ee7 Iustin Pop
      msg = "Failure: can't resolve hostname '%s'"
1907 73702ee7 Iustin Pop
    obuf.write(msg % err.args[0])
1908 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpPrereqError):
1909 5c983ee5 Iustin Pop
    if len(err.args) == 2:
1910 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
1911 5c983ee5 Iustin Pop
               " operation:\nerror type: %s, error details:\n%s" %
1912 5c983ee5 Iustin Pop
                 (err.args[1], err.args[0]))
1913 5c983ee5 Iustin Pop
    else:
1914 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
1915 5c983ee5 Iustin Pop
                 " operation:\n%s" % msg)
1916 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpExecError):
1917 e2e521d0 Iustin Pop
    obuf.write("Failure: command execution error:\n%s" % msg)
1918 73702ee7 Iustin Pop
  elif isinstance(err, errors.TagError):
1919 e2e521d0 Iustin Pop
    obuf.write("Failure: invalid tag(s) given:\n%s" % msg)
1920 686d7433 Iustin Pop
  elif isinstance(err, errors.JobQueueDrainError):
1921 686d7433 Iustin Pop
    obuf.write("Failure: the job queue is marked for drain and doesn't"
1922 686d7433 Iustin Pop
               " accept new requests\n")
1923 f87b405e Michael Hanselmann
  elif isinstance(err, errors.JobQueueFull):
1924 f87b405e Michael Hanselmann
    obuf.write("Failure: the job queue is full and doesn't accept new"
1925 f87b405e Michael Hanselmann
               " job submissions until old jobs are archived\n")
1926 a5728081 Guido Trotter
  elif isinstance(err, errors.TypeEnforcementError):
1927 a5728081 Guido Trotter
    obuf.write("Parameter Error: %s" % msg)
1928 c1ce76bb Iustin Pop
  elif isinstance(err, errors.ParameterError):
1929 c1ce76bb Iustin Pop
    obuf.write("Failure: unknown/wrong parameter name '%s'" % msg)
1930 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.NoMasterError):
1931 03a8dbdc Iustin Pop
    obuf.write("Cannot communicate with the master daemon.\nIs it running"
1932 082c5adb Michael Hanselmann
               " and listening for connections?")
1933 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.TimeoutError):
1934 cd4c86a8 Michael Hanselmann
    obuf.write("Timeout while talking to the master daemon. Jobs might have"
1935 cd4c86a8 Michael Hanselmann
               " been submitted and will continue to run even if the call"
1936 cd4c86a8 Michael Hanselmann
               " timed out. Useful commands in this situation are \"gnt-job"
1937 cd4c86a8 Michael Hanselmann
               " list\", \"gnt-job cancel\" and \"gnt-job watch\". Error:\n")
1938 cd4c86a8 Michael Hanselmann
    obuf.write(msg)
1939 5a1c22fe Iustin Pop
  elif isinstance(err, luxi.PermissionError):
1940 5a1c22fe Iustin Pop
    obuf.write("It seems you don't have permissions to connect to the"
1941 5a1c22fe Iustin Pop
               " master daemon.\nPlease retry as a different user.")
1942 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.ProtocolError):
1943 03a8dbdc Iustin Pop
    obuf.write("Unhandled protocol error while talking to the master daemon:\n"
1944 03a8dbdc Iustin Pop
               "%s" % msg)
1945 91c622a8 Iustin Pop
  elif isinstance(err, errors.JobLost):
1946 91c622a8 Iustin Pop
    obuf.write("Error checking job status: %s" % msg)
1947 cb1e6c3c Michael Hanselmann
  elif isinstance(err, errors.QueryFilterParseError):
1948 cb1e6c3c Michael Hanselmann
    obuf.write("Error while parsing query filter: %s\n" % err.args[0])
1949 cb1e6c3c Michael Hanselmann
    obuf.write("\n".join(err.GetDetails()))
1950 797506fc Michael Hanselmann
  elif isinstance(err, errors.GenericError):
1951 797506fc Michael Hanselmann
    obuf.write("Unhandled Ganeti error: %s" % msg)
1952 e9d741b6 Iustin Pop
  elif isinstance(err, JobSubmittedException):
1953 e9d741b6 Iustin Pop
    obuf.write("JobID: %s\n" % err.args[0])
1954 e9d741b6 Iustin Pop
    retcode = 0
1955 73702ee7 Iustin Pop
  else:
1956 e2e521d0 Iustin Pop
    obuf.write("Unhandled exception: %s" % msg)
1957 73702ee7 Iustin Pop
  return retcode, obuf.getvalue().rstrip('\n')
1958 73702ee7 Iustin Pop
1959 73702ee7 Iustin Pop
1960 de47cf8f Guido Trotter
def GenericMain(commands, override=None, aliases=None):
1961 a8083063 Iustin Pop
  """Generic main function for all the gnt-* commands.
1962 a8083063 Iustin Pop

1963 334d1483 Iustin Pop
  Arguments:
1964 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
1965 334d1483 Iustin Pop
                for command line handling.
1966 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
1967 334d1483 Iustin Pop
                override command line options; this can be used to pass
1968 334d1483 Iustin Pop
                options from the scripts to generic functions
1969 de47cf8f Guido Trotter
    - aliases: dictionary with command aliases {'alias': 'target, ...}
1970 a8083063 Iustin Pop

1971 a8083063 Iustin Pop
  """
1972 a8083063 Iustin Pop
  # save the program name and the entire command line for later logging
1973 a8083063 Iustin Pop
  if sys.argv:
1974 a8083063 Iustin Pop
    binary = os.path.basename(sys.argv[0]) or sys.argv[0]
1975 a8083063 Iustin Pop
    if len(sys.argv) >= 2:
1976 a8083063 Iustin Pop
      binary += " " + sys.argv[1]
1977 a8083063 Iustin Pop
      old_cmdline = " ".join(sys.argv[2:])
1978 a8083063 Iustin Pop
    else:
1979 a8083063 Iustin Pop
      old_cmdline = ""
1980 a8083063 Iustin Pop
  else:
1981 a8083063 Iustin Pop
    binary = "<unknown program>"
1982 a8083063 Iustin Pop
    old_cmdline = ""
1983 a8083063 Iustin Pop
1984 de47cf8f Guido Trotter
  if aliases is None:
1985 de47cf8f Guido Trotter
    aliases = {}
1986 de47cf8f Guido Trotter
1987 3126878d Guido Trotter
  try:
1988 3126878d Guido Trotter
    func, options, args = _ParseArgs(sys.argv, commands, aliases)
1989 3126878d Guido Trotter
  except errors.ParameterError, err:
1990 3126878d Guido Trotter
    result, err_msg = FormatError(err)
1991 3126878d Guido Trotter
    ToStderr(err_msg)
1992 3126878d Guido Trotter
    return 1
1993 3126878d Guido Trotter
1994 a8083063 Iustin Pop
  if func is None: # parse error
1995 a8083063 Iustin Pop
    return 1
1996 a8083063 Iustin Pop
1997 334d1483 Iustin Pop
  if override is not None:
1998 334d1483 Iustin Pop
    for key, val in override.iteritems():
1999 334d1483 Iustin Pop
      setattr(options, key, val)
2000 334d1483 Iustin Pop
2001 cfcc79c6 Michael Hanselmann
  utils.SetupLogging(constants.LOG_COMMANDS, binary, debug=options.debug,
2002 cfcc79c6 Michael Hanselmann
                     stderr_logging=True)
2003 a8083063 Iustin Pop
2004 a8083063 Iustin Pop
  if old_cmdline:
2005 46fbdd04 Iustin Pop
    logging.info("run with arguments '%s'", old_cmdline)
2006 a8083063 Iustin Pop
  else:
2007 46fbdd04 Iustin Pop
    logging.info("run with no arguments")
2008 a8083063 Iustin Pop
2009 a8083063 Iustin Pop
  try:
2010 a4af651e Iustin Pop
    result = func(options, args)
2011 d8353c3a Iustin Pop
  except (errors.GenericError, luxi.ProtocolError,
2012 d8353c3a Iustin Pop
          JobSubmittedException), err:
2013 a4af651e Iustin Pop
    result, err_msg = FormatError(err)
2014 5bbd3f7f Michael Hanselmann
    logging.exception("Error during command processing")
2015 46fbdd04 Iustin Pop
    ToStderr(err_msg)
2016 8a53b55f Iustin Pop
  except KeyboardInterrupt:
2017 8a53b55f Iustin Pop
    result = constants.EXIT_FAILURE
2018 8a53b55f Iustin Pop
    ToStderr("Aborted. Note that if the operation created any jobs, they"
2019 8a53b55f Iustin Pop
             " might have been submitted and"
2020 8a53b55f Iustin Pop
             " will continue to run in the background.")
2021 225e2544 Iustin Pop
  except IOError, err:
2022 225e2544 Iustin Pop
    if err.errno == errno.EPIPE:
2023 225e2544 Iustin Pop
      # our terminal went away, we'll exit
2024 225e2544 Iustin Pop
      sys.exit(constants.EXIT_FAILURE)
2025 225e2544 Iustin Pop
    else:
2026 225e2544 Iustin Pop
      raise
2027 a8083063 Iustin Pop
2028 a8083063 Iustin Pop
  return result
2029 137161c9 Michael Hanselmann
2030 137161c9 Michael Hanselmann
2031 845c79d8 Michael Hanselmann
def ParseNicOption(optvalue):
2032 845c79d8 Michael Hanselmann
  """Parses the value of the --net option(s).
2033 845c79d8 Michael Hanselmann

2034 845c79d8 Michael Hanselmann
  """
2035 845c79d8 Michael Hanselmann
  try:
2036 845c79d8 Michael Hanselmann
    nic_max = max(int(nidx[0]) + 1 for nidx in optvalue)
2037 845c79d8 Michael Hanselmann
  except (TypeError, ValueError), err:
2038 845c79d8 Michael Hanselmann
    raise errors.OpPrereqError("Invalid NIC index passed: %s" % str(err))
2039 845c79d8 Michael Hanselmann
2040 845c79d8 Michael Hanselmann
  nics = [{}] * nic_max
2041 845c79d8 Michael Hanselmann
  for nidx, ndict in optvalue:
2042 845c79d8 Michael Hanselmann
    nidx = int(nidx)
2043 845c79d8 Michael Hanselmann
2044 845c79d8 Michael Hanselmann
    if not isinstance(ndict, dict):
2045 845c79d8 Michael Hanselmann
      raise errors.OpPrereqError("Invalid nic/%d value: expected dict,"
2046 845c79d8 Michael Hanselmann
                                 " got %s" % (nidx, ndict))
2047 845c79d8 Michael Hanselmann
2048 845c79d8 Michael Hanselmann
    utils.ForceDictType(ndict, constants.INIC_PARAMS_TYPES)
2049 845c79d8 Michael Hanselmann
2050 845c79d8 Michael Hanselmann
    nics[nidx] = ndict
2051 845c79d8 Michael Hanselmann
2052 845c79d8 Michael Hanselmann
  return nics
2053 845c79d8 Michael Hanselmann
2054 845c79d8 Michael Hanselmann
2055 d77490c5 Iustin Pop
def GenericInstanceCreate(mode, opts, args):
2056 d77490c5 Iustin Pop
  """Add an instance to the cluster via either creation or import.
2057 d77490c5 Iustin Pop

2058 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
2059 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
2060 d77490c5 Iustin Pop
  @type args: list
2061 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
2062 d77490c5 Iustin Pop
  @rtype: int
2063 d77490c5 Iustin Pop
  @return: the desired exit code
2064 d77490c5 Iustin Pop

2065 d77490c5 Iustin Pop
  """
2066 d77490c5 Iustin Pop
  instance = args[0]
2067 d77490c5 Iustin Pop
2068 d77490c5 Iustin Pop
  (pnode, snode) = SplitNodeOption(opts.node)
2069 d77490c5 Iustin Pop
2070 d77490c5 Iustin Pop
  hypervisor = None
2071 d77490c5 Iustin Pop
  hvparams = {}
2072 d77490c5 Iustin Pop
  if opts.hypervisor:
2073 d77490c5 Iustin Pop
    hypervisor, hvparams = opts.hypervisor
2074 d77490c5 Iustin Pop
2075 d77490c5 Iustin Pop
  if opts.nics:
2076 845c79d8 Michael Hanselmann
    nics = ParseNicOption(opts.nics)
2077 d77490c5 Iustin Pop
  elif opts.no_nics:
2078 d77490c5 Iustin Pop
    # no nics
2079 d77490c5 Iustin Pop
    nics = []
2080 0af0f641 Iustin Pop
  elif mode == constants.INSTANCE_CREATE:
2081 d77490c5 Iustin Pop
    # default of one nic, all auto
2082 d77490c5 Iustin Pop
    nics = [{}]
2083 0af0f641 Iustin Pop
  else:
2084 0af0f641 Iustin Pop
    # mode == import
2085 0af0f641 Iustin Pop
    nics = []
2086 d77490c5 Iustin Pop
2087 d77490c5 Iustin Pop
  if opts.disk_template == constants.DT_DISKLESS:
2088 d77490c5 Iustin Pop
    if opts.disks or opts.sd_size is not None:
2089 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Diskless instance but disk"
2090 d77490c5 Iustin Pop
                                 " information passed")
2091 d77490c5 Iustin Pop
    disks = []
2092 d77490c5 Iustin Pop
  else:
2093 9b12ed0f Iustin Pop
    if (not opts.disks and not opts.sd_size
2094 9b12ed0f Iustin Pop
        and mode == constants.INSTANCE_CREATE):
2095 d77490c5 Iustin Pop
      raise errors.OpPrereqError("No disk information specified")
2096 d77490c5 Iustin Pop
    if opts.disks and opts.sd_size is not None:
2097 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Please use either the '--disk' or"
2098 d77490c5 Iustin Pop
                                 " '-s' option")
2099 d77490c5 Iustin Pop
    if opts.sd_size is not None:
2100 ccfa86ba Michael Hanselmann
      opts.disks = [(0, {constants.IDISK_SIZE: opts.sd_size})]
2101 9b12ed0f Iustin Pop
2102 9b12ed0f Iustin Pop
    if opts.disks:
2103 9b12ed0f Iustin Pop
      try:
2104 9b12ed0f Iustin Pop
        disk_max = max(int(didx[0]) + 1 for didx in opts.disks)
2105 9b12ed0f Iustin Pop
      except ValueError, err:
2106 9b12ed0f Iustin Pop
        raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err))
2107 9b12ed0f Iustin Pop
      disks = [{}] * disk_max
2108 9b12ed0f Iustin Pop
    else:
2109 9b12ed0f Iustin Pop
      disks = []
2110 d77490c5 Iustin Pop
    for didx, ddict in opts.disks:
2111 d77490c5 Iustin Pop
      didx = int(didx)
2112 d77490c5 Iustin Pop
      if not isinstance(ddict, dict):
2113 d77490c5 Iustin Pop
        msg = "Invalid disk/%d value: expected dict, got %s" % (didx, ddict)
2114 d77490c5 Iustin Pop
        raise errors.OpPrereqError(msg)
2115 ccfa86ba Michael Hanselmann
      elif constants.IDISK_SIZE in ddict:
2116 ccfa86ba Michael Hanselmann
        if constants.IDISK_ADOPT in ddict:
2117 5029db65 Iustin Pop
          raise errors.OpPrereqError("Only one of 'size' and 'adopt' allowed"
2118 5029db65 Iustin Pop
                                     " (disk %d)" % didx)
2119 5029db65 Iustin Pop
        try:
2120 ccfa86ba Michael Hanselmann
          ddict[constants.IDISK_SIZE] = \
2121 ccfa86ba Michael Hanselmann
            utils.ParseUnit(ddict[constants.IDISK_SIZE])
2122 5029db65 Iustin Pop
        except ValueError, err:
2123 5029db65 Iustin Pop
          raise errors.OpPrereqError("Invalid disk size for disk %d: %s" %
2124 5029db65 Iustin Pop
                                     (didx, err))
2125 ccfa86ba Michael Hanselmann
      elif constants.IDISK_ADOPT in ddict:
2126 5029db65 Iustin Pop
        if mode == constants.INSTANCE_IMPORT:
2127 5029db65 Iustin Pop
          raise errors.OpPrereqError("Disk adoption not allowed for instance"
2128 5029db65 Iustin Pop
                                     " import")
2129 ccfa86ba Michael Hanselmann
        ddict[constants.IDISK_SIZE] = 0
2130 5029db65 Iustin Pop
      else:
2131 5029db65 Iustin Pop
        raise errors.OpPrereqError("Missing size or adoption source for"
2132 5029db65 Iustin Pop
                                   " disk %d" % didx)
2133 d77490c5 Iustin Pop
      disks[didx] = ddict
2134 d77490c5 Iustin Pop
2135 a57981c5 Apollon Oikonomopoulos
  if opts.tags is not None:
2136 0f8810df Michael Hanselmann
    tags = opts.tags.split(",")
2137 a57981c5 Apollon Oikonomopoulos
  else:
2138 a57981c5 Apollon Oikonomopoulos
    tags = []
2139 a57981c5 Apollon Oikonomopoulos
2140 d77490c5 Iustin Pop
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_TYPES)
2141 d77490c5 Iustin Pop
  utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
2142 d77490c5 Iustin Pop
2143 d77490c5 Iustin Pop
  if mode == constants.INSTANCE_CREATE:
2144 d77490c5 Iustin Pop
    start = opts.start
2145 d77490c5 Iustin Pop
    os_type = opts.os
2146 1ee8e01a Guido Trotter
    force_variant = opts.force_variant
2147 d77490c5 Iustin Pop
    src_node = None
2148 d77490c5 Iustin Pop
    src_path = None
2149 25a8792c Iustin Pop
    no_install = opts.no_install
2150 e588764d Iustin Pop
    identify_defaults = False
2151 d77490c5 Iustin Pop
  elif mode == constants.INSTANCE_IMPORT:
2152 d77490c5 Iustin Pop
    start = False
2153 d77490c5 Iustin Pop
    os_type = None
2154 1ee8e01a Guido Trotter
    force_variant = False
2155 d77490c5 Iustin Pop
    src_node = opts.src_node
2156 d77490c5 Iustin Pop
    src_path = opts.src_dir
2157 25a8792c Iustin Pop
    no_install = None
2158 e588764d Iustin Pop
    identify_defaults = opts.identify_defaults
2159 d77490c5 Iustin Pop
  else:
2160 d77490c5 Iustin Pop
    raise errors.ProgrammerError("Invalid creation mode %s" % mode)
2161 d77490c5 Iustin Pop
2162 e1530b10 Iustin Pop
  op = opcodes.OpInstanceCreate(instance_name=instance,
2163 d77490c5 Iustin Pop
                                disks=disks,
2164 d77490c5 Iustin Pop
                                disk_template=opts.disk_template,
2165 d77490c5 Iustin Pop
                                nics=nics,
2166 d77490c5 Iustin Pop
                                pnode=pnode, snode=snode,
2167 d77490c5 Iustin Pop
                                ip_check=opts.ip_check,
2168 460d22be Iustin Pop
                                name_check=opts.name_check,
2169 d77490c5 Iustin Pop
                                wait_for_sync=opts.wait_for_sync,
2170 d77490c5 Iustin Pop
                                file_storage_dir=opts.file_storage_dir,
2171 d77490c5 Iustin Pop
                                file_driver=opts.file_driver,
2172 d77490c5 Iustin Pop
                                iallocator=opts.iallocator,
2173 d77490c5 Iustin Pop
                                hypervisor=hypervisor,
2174 d77490c5 Iustin Pop
                                hvparams=hvparams,
2175 d77490c5 Iustin Pop
                                beparams=opts.beparams,
2176 062a7100 Iustin Pop
                                osparams=opts.osparams,
2177 d77490c5 Iustin Pop
                                mode=mode,
2178 d77490c5 Iustin Pop
                                start=start,
2179 d77490c5 Iustin Pop
                                os_type=os_type,
2180 1ee8e01a Guido Trotter
                                force_variant=force_variant,
2181 d77490c5 Iustin Pop
                                src_node=src_node,
2182 25a8792c Iustin Pop
                                src_path=src_path,
2183 a57981c5 Apollon Oikonomopoulos
                                tags=tags,
2184 e588764d Iustin Pop
                                no_install=no_install,
2185 e588764d Iustin Pop
                                identify_defaults=identify_defaults)
2186 d77490c5 Iustin Pop
2187 d77490c5 Iustin Pop
  SubmitOrSend(op, opts)
2188 d77490c5 Iustin Pop
  return 0
2189 d77490c5 Iustin Pop
2190 d77490c5 Iustin Pop
2191 7e49b6ce Michael Hanselmann
class _RunWhileClusterStoppedHelper:
2192 7e49b6ce Michael Hanselmann
  """Helper class for L{RunWhileClusterStopped} to simplify state management
2193 7e49b6ce Michael Hanselmann

2194 7e49b6ce Michael Hanselmann
  """
2195 7e49b6ce Michael Hanselmann
  def __init__(self, feedback_fn, cluster_name, master_node, online_nodes):
2196 7e49b6ce Michael Hanselmann
    """Initializes this class.
2197 7e49b6ce Michael Hanselmann

2198 7e49b6ce Michael Hanselmann
    @type feedback_fn: callable
2199 7e49b6ce Michael Hanselmann
    @param feedback_fn: Feedback function
2200 7e49b6ce Michael Hanselmann
    @type cluster_name: string
2201 7e49b6ce Michael Hanselmann
    @param cluster_name: Cluster name
2202 7e49b6ce Michael Hanselmann
    @type master_node: string
2203 7e49b6ce Michael Hanselmann
    @param master_node Master node name
2204 7e49b6ce Michael Hanselmann
    @type online_nodes: list
2205 7e49b6ce Michael Hanselmann
    @param online_nodes: List of names of online nodes
2206 7e49b6ce Michael Hanselmann

2207 7e49b6ce Michael Hanselmann
    """
2208 7e49b6ce Michael Hanselmann
    self.feedback_fn = feedback_fn
2209 7e49b6ce Michael Hanselmann
    self.cluster_name = cluster_name
2210 7e49b6ce Michael Hanselmann
    self.master_node = master_node
2211 7e49b6ce Michael Hanselmann
    self.online_nodes = online_nodes
2212 7e49b6ce Michael Hanselmann
2213 7e49b6ce Michael Hanselmann
    self.ssh = ssh.SshRunner(self.cluster_name)
2214 7e49b6ce Michael Hanselmann
2215 7e49b6ce Michael Hanselmann
    self.nonmaster_nodes = [name for name in online_nodes
2216 7e49b6ce Michael Hanselmann
                            if name != master_node]
2217 7e49b6ce Michael Hanselmann
2218 7e49b6ce Michael Hanselmann
    assert self.master_node not in self.nonmaster_nodes
2219 7e49b6ce Michael Hanselmann
2220 7e49b6ce Michael Hanselmann
  def _RunCmd(self, node_name, cmd):
2221 7e49b6ce Michael Hanselmann
    """Runs a command on the local or a remote machine.
2222 7e49b6ce Michael Hanselmann

2223 7e49b6ce Michael Hanselmann
    @type node_name: string
2224 7e49b6ce Michael Hanselmann
    @param node_name: Machine name
2225 7e49b6ce Michael Hanselmann
    @type cmd: list
2226 7e49b6ce Michael Hanselmann
    @param cmd: Command
2227 7e49b6ce Michael Hanselmann

2228 7e49b6ce Michael Hanselmann
    """
2229 7e49b6ce Michael Hanselmann
    if node_name is None or node_name == self.master_node:
2230 7e49b6ce Michael Hanselmann
      # No need to use SSH
2231 7e49b6ce Michael Hanselmann
      result = utils.RunCmd(cmd)
2232 7e49b6ce Michael Hanselmann
    else:
2233 7e49b6ce Michael Hanselmann
      result = self.ssh.Run(node_name, "root", utils.ShellQuoteArgs(cmd))
2234 7e49b6ce Michael Hanselmann
2235 7e49b6ce Michael Hanselmann
    if result.failed:
2236 7e49b6ce Michael Hanselmann
      errmsg = ["Failed to run command %s" % result.cmd]
2237 7e49b6ce Michael Hanselmann
      if node_name:
2238 7e49b6ce Michael Hanselmann
        errmsg.append("on node %s" % node_name)
2239 7e49b6ce Michael Hanselmann
      errmsg.append(": exitcode %s and error %s" %
2240 7e49b6ce Michael Hanselmann
                    (result.exit_code, result.output))
2241 7e49b6ce Michael Hanselmann
      raise errors.OpExecError(" ".join(errmsg))
2242 7e49b6ce Michael Hanselmann
2243 7e49b6ce Michael Hanselmann
  def Call(self, fn, *args):
2244 7e49b6ce Michael Hanselmann
    """Call function while all daemons are stopped.
2245 7e49b6ce Michael Hanselmann

2246 7e49b6ce Michael Hanselmann
    @type fn: callable
2247 7e49b6ce Michael Hanselmann
    @param fn: Function to be called
2248 7e49b6ce Michael Hanselmann

2249 7e49b6ce Michael Hanselmann
    """
2250 7e49b6ce Michael Hanselmann
    # Pause watcher by acquiring an exclusive lock on watcher state file
2251 7e49b6ce Michael Hanselmann
    self.feedback_fn("Blocking watcher")
2252 7e49b6ce Michael Hanselmann
    watcher_block = utils.FileLock.Open(constants.WATCHER_STATEFILE)
2253 7e49b6ce Michael Hanselmann
    try:
2254 7e49b6ce Michael Hanselmann
      # TODO: Currently, this just blocks. There's no timeout.
2255 7e49b6ce Michael Hanselmann
      # TODO: Should it be a shared lock?
2256 7e49b6ce Michael Hanselmann
      watcher_block.Exclusive(blocking=True)
2257 7e49b6ce Michael Hanselmann
2258 7e49b6ce Michael Hanselmann
      # Stop master daemons, so that no new jobs can come in and all running
2259 7e49b6ce Michael Hanselmann
      # ones are finished
2260 7e49b6ce Michael Hanselmann
      self.feedback_fn("Stopping master daemons")
2261 7e49b6ce Michael Hanselmann
      self._RunCmd(None, [constants.DAEMON_UTIL, "stop-master"])
2262 7e49b6ce Michael Hanselmann
      try:
2263 7e49b6ce Michael Hanselmann
        # Stop daemons on all nodes
2264 7e49b6ce Michael Hanselmann
        for node_name in self.online_nodes:
2265 7e49b6ce Michael Hanselmann
          self.feedback_fn("Stopping daemons on %s" % node_name)
2266 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "stop-all"])
2267 7e49b6ce Michael Hanselmann
2268 7e49b6ce Michael Hanselmann
        # All daemons are shut down now
2269 7e49b6ce Michael Hanselmann
        try:
2270 7e49b6ce Michael Hanselmann
          return fn(self, *args)
2271 d512e84b Michael Hanselmann
        except Exception, err:
2272 d512e84b Michael Hanselmann
          _, errmsg = FormatError(err)
2273 7e49b6ce Michael Hanselmann
          logging.exception("Caught exception")
2274 d512e84b Michael Hanselmann
          self.feedback_fn(errmsg)
2275 7e49b6ce Michael Hanselmann
          raise
2276 7e49b6ce Michael Hanselmann
      finally:
2277 7e49b6ce Michael Hanselmann
        # Start cluster again, master node last
2278 7e49b6ce Michael Hanselmann
        for node_name in self.nonmaster_nodes + [self.master_node]:
2279 7e49b6ce Michael Hanselmann
          self.feedback_fn("Starting daemons on %s" % node_name)
2280 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "start-all"])
2281 7e49b6ce Michael Hanselmann
    finally:
2282 7e49b6ce Michael Hanselmann
      # Resume watcher
2283 7e49b6ce Michael Hanselmann
      watcher_block.Close()
2284 7e49b6ce Michael Hanselmann
2285 7e49b6ce Michael Hanselmann
2286 7e49b6ce Michael Hanselmann
def RunWhileClusterStopped(feedback_fn, fn, *args):
2287 7e49b6ce Michael Hanselmann
  """Calls a function while all cluster daemons are stopped.
2288 7e49b6ce Michael Hanselmann

2289 7e49b6ce Michael Hanselmann
  @type feedback_fn: callable
2290 7e49b6ce Michael Hanselmann
  @param feedback_fn: Feedback function
2291 7e49b6ce Michael Hanselmann
  @type fn: callable
2292 7e49b6ce Michael Hanselmann
  @param fn: Function to be called when daemons are stopped
2293 7e49b6ce Michael Hanselmann

2294 7e49b6ce Michael Hanselmann
  """
2295 7e49b6ce Michael Hanselmann
  feedback_fn("Gathering cluster information")
2296 7e49b6ce Michael Hanselmann
2297 7e49b6ce Michael Hanselmann
  # This ensures we're running on the master daemon
2298 7e49b6ce Michael Hanselmann
  cl = GetClient()
2299 7e49b6ce Michael Hanselmann
2300 7e49b6ce Michael Hanselmann
  (cluster_name, master_node) = \
2301 7e49b6ce Michael Hanselmann
    cl.QueryConfigValues(["cluster_name", "master_node"])
2302 7e49b6ce Michael Hanselmann
2303 7e49b6ce Michael Hanselmann
  online_nodes = GetOnlineNodes([], cl=cl)
2304 7e49b6ce Michael Hanselmann
2305 7e49b6ce Michael Hanselmann
  # Don't keep a reference to the client. The master daemon will go away.
2306 7e49b6ce Michael Hanselmann
  del cl
2307 7e49b6ce Michael Hanselmann
2308 7e49b6ce Michael Hanselmann
  assert master_node in online_nodes
2309 7e49b6ce Michael Hanselmann
2310 7e49b6ce Michael Hanselmann
  return _RunWhileClusterStoppedHelper(feedback_fn, cluster_name, master_node,
2311 7e49b6ce Michael Hanselmann
                                       online_nodes).Call(fn, *args)
2312 7e49b6ce Michael Hanselmann
2313 7e49b6ce Michael Hanselmann
2314 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
2315 9fbfbb7b Iustin Pop
                  numfields=None, unitfields=None,
2316 9fbfbb7b Iustin Pop
                  units=None):
2317 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
2318 137161c9 Michael Hanselmann

2319 9fbfbb7b Iustin Pop
  @type headers: dict
2320 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
2321 9fbfbb7b Iustin Pop
      the table
2322 9fbfbb7b Iustin Pop
  @type fields: list
2323 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
2324 9fbfbb7b Iustin Pop
      the data field
2325 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
2326 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
2327 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
2328 9fbfbb7b Iustin Pop
      each field
2329 9fbfbb7b Iustin Pop
  @type data: list
2330 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
2331 9fbfbb7b Iustin Pop
  @type numfields: list
2332 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
2333 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
2334 9fbfbb7b Iustin Pop
  @type unitfields: list
2335 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
2336 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
2337 9fbfbb7b Iustin Pop
  @type units: string or None
2338 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
2339 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
2340 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
2341 137161c9 Michael Hanselmann

2342 137161c9 Michael Hanselmann
  """
2343 9fbfbb7b Iustin Pop
  if units is None:
2344 9fbfbb7b Iustin Pop
    if separator:
2345 9fbfbb7b Iustin Pop
      units = "m"
2346 9fbfbb7b Iustin Pop
    else:
2347 9fbfbb7b Iustin Pop
      units = "h"
2348 9fbfbb7b Iustin Pop
2349 137161c9 Michael Hanselmann
  if numfields is None:
2350 137161c9 Michael Hanselmann
    numfields = []
2351 137161c9 Michael Hanselmann
  if unitfields is None:
2352 137161c9 Michael Hanselmann
    unitfields = []
2353 137161c9 Michael Hanselmann
2354 fe267188 Iustin Pop
  numfields = utils.FieldSet(*numfields)   # pylint: disable-msg=W0142
2355 fe267188 Iustin Pop
  unitfields = utils.FieldSet(*unitfields) # pylint: disable-msg=W0142
2356 00430f8e Iustin Pop
2357 137161c9 Michael Hanselmann
  format_fields = []
2358 137161c9 Michael Hanselmann
  for field in fields:
2359 01ca31ae Iustin Pop
    if headers and field not in headers:
2360 ea5a5b74 Guido Trotter
      # TODO: handle better unknown fields (either revert to old
2361 71c1af58 Iustin Pop
      # style of raising exception, or deal more intelligently with
2362 71c1af58 Iustin Pop
      # variable fields)
2363 71c1af58 Iustin Pop
      headers[field] = field
2364 137161c9 Michael Hanselmann
    if separator is not None:
2365 137161c9 Michael Hanselmann
      format_fields.append("%s")
2366 00430f8e Iustin Pop
    elif numfields.Matches(field):
2367 137161c9 Michael Hanselmann
      format_fields.append("%*s")
2368 137161c9 Michael Hanselmann
    else:
2369 137161c9 Michael Hanselmann
      format_fields.append("%-*s")
2370 137161c9 Michael Hanselmann
2371 137161c9 Michael Hanselmann
  if separator is None:
2372 137161c9 Michael Hanselmann
    mlens = [0 for name in fields]
2373 c04bc777 Iustin Pop
    format_str = ' '.join(format_fields)
2374 137161c9 Michael Hanselmann
  else:
2375 c04bc777 Iustin Pop
    format_str = separator.replace("%", "%%").join(format_fields)
2376 137161c9 Michael Hanselmann
2377 137161c9 Michael Hanselmann
  for row in data:
2378 dcbd6288 Guido Trotter
    if row is None:
2379 dcbd6288 Guido Trotter
      continue
2380 137161c9 Michael Hanselmann
    for idx, val in enumerate(row):
2381 00430f8e Iustin Pop
      if unitfields.Matches(fields[idx]):
2382 137161c9 Michael Hanselmann
        try:
2383 137161c9 Michael Hanselmann
          val = int(val)
2384 691744c4 Iustin Pop
        except (TypeError, ValueError):
2385 137161c9 Michael Hanselmann
          pass
2386 137161c9 Michael Hanselmann
        else:
2387 9fbfbb7b Iustin Pop
          val = row[idx] = utils.FormatUnit(val, units)
2388 01ca31ae Iustin Pop
      val = row[idx] = str(val)
2389 137161c9 Michael Hanselmann
      if separator is None:
2390 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(val))
2391 137161c9 Michael Hanselmann
2392 16be8703 Iustin Pop
  result = []
2393 137161c9 Michael Hanselmann
  if headers:
2394 137161c9 Michael Hanselmann
    args = []
2395 137161c9 Michael Hanselmann
    for idx, name in enumerate(fields):
2396 137161c9 Michael Hanselmann
      hdr = headers[name]
2397 137161c9 Michael Hanselmann
      if separator is None:
2398 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(hdr))
2399 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2400 137161c9 Michael Hanselmann
      args.append(hdr)
2401 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2402 137161c9 Michael Hanselmann
2403 ec39d63c Michael Hanselmann
  if separator is None:
2404 ec39d63c Michael Hanselmann
    assert len(mlens) == len(fields)
2405 ec39d63c Michael Hanselmann
2406 ec39d63c Michael Hanselmann
    if fields and not numfields.Matches(fields[-1]):
2407 ec39d63c Michael Hanselmann
      mlens[-1] = 0
2408 ec39d63c Michael Hanselmann
2409 137161c9 Michael Hanselmann
  for line in data:
2410 137161c9 Michael Hanselmann
    args = []
2411 dcbd6288 Guido Trotter
    if line is None:
2412 dcbd6288 Guido Trotter
      line = ['-' for _ in fields]
2413 f1501b3f Michael Hanselmann
    for idx in range(len(fields)):
2414 137161c9 Michael Hanselmann
      if separator is None:
2415 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2416 137161c9 Michael Hanselmann
      args.append(line[idx])
2417 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2418 16be8703 Iustin Pop
2419 16be8703 Iustin Pop
  return result
2420 3386e7a9 Iustin Pop
2421 3386e7a9 Iustin Pop
2422 ee3aedff Michael Hanselmann
def _FormatBool(value):
2423 ee3aedff Michael Hanselmann
  """Formats a boolean value as a string.
2424 ee3aedff Michael Hanselmann

2425 ee3aedff Michael Hanselmann
  """
2426 ee3aedff Michael Hanselmann
  if value:
2427 ee3aedff Michael Hanselmann
    return "Y"
2428 ee3aedff Michael Hanselmann
  return "N"
2429 ee3aedff Michael Hanselmann
2430 ee3aedff Michael Hanselmann
2431 ee3aedff Michael Hanselmann
#: Default formatting for query results; (callback, align right)
2432 ee3aedff Michael Hanselmann
_DEFAULT_FORMAT_QUERY = {
2433 ee3aedff Michael Hanselmann
  constants.QFT_TEXT: (str, False),
2434 ee3aedff Michael Hanselmann
  constants.QFT_BOOL: (_FormatBool, False),
2435 ee3aedff Michael Hanselmann
  constants.QFT_NUMBER: (str, True),
2436 ee3aedff Michael Hanselmann
  constants.QFT_TIMESTAMP: (utils.FormatTime, False),
2437 ee3aedff Michael Hanselmann
  constants.QFT_OTHER: (str, False),
2438 ee3aedff Michael Hanselmann
  constants.QFT_UNKNOWN: (str, False),
2439 ee3aedff Michael Hanselmann
  }
2440 ee3aedff Michael Hanselmann
2441 ee3aedff Michael Hanselmann
2442 ee3aedff Michael Hanselmann
def _GetColumnFormatter(fdef, override, unit):
2443 ee3aedff Michael Hanselmann
  """Returns formatting function for a field.
2444 ee3aedff Michael Hanselmann

2445 ee3aedff Michael Hanselmann
  @type fdef: L{objects.QueryFieldDefinition}
2446 ee3aedff Michael Hanselmann
  @type override: dict
2447 ee3aedff Michael Hanselmann
  @param override: Dictionary for overriding field formatting functions,
2448 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2449 ee3aedff Michael Hanselmann
  @type unit: string
2450 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT}
2451 ee3aedff Michael Hanselmann
  @rtype: tuple; (callable, bool)
2452 ee3aedff Michael Hanselmann
  @return: Returns the function to format a value (takes one parameter) and a
2453 ee3aedff Michael Hanselmann
    boolean for aligning the value on the right-hand side
2454 ee3aedff Michael Hanselmann

2455 ee3aedff Michael Hanselmann
  """
2456 ee3aedff Michael Hanselmann
  fmt = override.get(fdef.name, None)
2457 ee3aedff Michael Hanselmann
  if fmt is not None:
2458 ee3aedff Michael Hanselmann
    return fmt
2459 ee3aedff Michael Hanselmann
2460 ee3aedff Michael Hanselmann
  assert constants.QFT_UNIT not in _DEFAULT_FORMAT_QUERY
2461 ee3aedff Michael Hanselmann
2462 ee3aedff Michael Hanselmann
  if fdef.kind == constants.QFT_UNIT:
2463 ee3aedff Michael Hanselmann
    # Can't keep this information in the static dictionary
2464 ee3aedff Michael Hanselmann
    return (lambda value: utils.FormatUnit(value, unit), True)
2465 ee3aedff Michael Hanselmann
2466 ee3aedff Michael Hanselmann
  fmt = _DEFAULT_FORMAT_QUERY.get(fdef.kind, None)
2467 ee3aedff Michael Hanselmann
  if fmt is not None:
2468 ee3aedff Michael Hanselmann
    return fmt
2469 ee3aedff Michael Hanselmann
2470 ee3aedff Michael Hanselmann
  raise NotImplementedError("Can't format column type '%s'" % fdef.kind)
2471 ee3aedff Michael Hanselmann
2472 ee3aedff Michael Hanselmann
2473 ee3aedff Michael Hanselmann
class _QueryColumnFormatter:
2474 ee3aedff Michael Hanselmann
  """Callable class for formatting fields of a query.
2475 ee3aedff Michael Hanselmann

2476 ee3aedff Michael Hanselmann
  """
2477 f0b1bafe Iustin Pop
  def __init__(self, fn, status_fn, verbose):
2478 ee3aedff Michael Hanselmann
    """Initializes this class.
2479 ee3aedff Michael Hanselmann

2480 ee3aedff Michael Hanselmann
    @type fn: callable
2481 ee3aedff Michael Hanselmann
    @param fn: Formatting function
2482 ee3aedff Michael Hanselmann
    @type status_fn: callable
2483 ee3aedff Michael Hanselmann
    @param status_fn: Function to report fields' status
2484 f0b1bafe Iustin Pop
    @type verbose: boolean
2485 f0b1bafe Iustin Pop
    @param verbose: whether to use verbose field descriptions or not
2486 ee3aedff Michael Hanselmann

2487 ee3aedff Michael Hanselmann
    """
2488 ee3aedff Michael Hanselmann
    self._fn = fn
2489 ee3aedff Michael Hanselmann
    self._status_fn = status_fn
2490 cbfa4f0f Michael Hanselmann
    self._verbose = verbose
2491 ee3aedff Michael Hanselmann
2492 ee3aedff Michael Hanselmann
  def __call__(self, data):
2493 ee3aedff Michael Hanselmann
    """Returns a field's string representation.
2494 ee3aedff Michael Hanselmann

2495 ee3aedff Michael Hanselmann
    """
2496 ee3aedff Michael Hanselmann
    (status, value) = data
2497 ee3aedff Michael Hanselmann
2498 ee3aedff Michael Hanselmann
    # Report status
2499 ee3aedff Michael Hanselmann
    self._status_fn(status)
2500 ee3aedff Michael Hanselmann
2501 cfb084ae René Nussbaumer
    if status == constants.RS_NORMAL:
2502 ee3aedff Michael Hanselmann
      return self._fn(value)
2503 ee3aedff Michael Hanselmann
2504 ee3aedff Michael Hanselmann
    assert value is None, \
2505 ee3aedff Michael Hanselmann
           "Found value %r for abnormal status %s" % (value, status)
2506 ee3aedff Michael Hanselmann
2507 f2c6673d Michael Hanselmann
    return FormatResultError(status, self._verbose)
2508 ee3aedff Michael Hanselmann
2509 ee3aedff Michael Hanselmann
2510 f2c6673d Michael Hanselmann
def FormatResultError(status, verbose):
2511 ae95e419 René Nussbaumer
  """Formats result status other than L{constants.RS_NORMAL}.
2512 ee3aedff Michael Hanselmann

2513 ae95e419 René Nussbaumer
  @param status: The result status
2514 f2c6673d Michael Hanselmann
  @type verbose: boolean
2515 f2c6673d Michael Hanselmann
  @param verbose: Whether to return the verbose text
2516 ae95e419 René Nussbaumer
  @return: Text of result status
2517 a6070ef7 Michael Hanselmann

2518 ae95e419 René Nussbaumer
  """
2519 ae95e419 René Nussbaumer
  assert status != constants.RS_NORMAL, \
2520 cbfa4f0f Michael Hanselmann
         "FormatResultError called with status equal to constants.RS_NORMAL"
2521 ae95e419 René Nussbaumer
  try:
2522 cbfa4f0f Michael Hanselmann
    (verbose_text, normal_text) = constants.RSS_DESCRIPTION[status]
2523 ae95e419 René Nussbaumer
  except KeyError:
2524 ee3aedff Michael Hanselmann
    raise NotImplementedError("Unknown status %s" % status)
2525 cbfa4f0f Michael Hanselmann
  else:
2526 cbfa4f0f Michael Hanselmann
    if verbose:
2527 cbfa4f0f Michael Hanselmann
      return verbose_text
2528 cbfa4f0f Michael Hanselmann
    return normal_text
2529 ee3aedff Michael Hanselmann
2530 ee3aedff Michael Hanselmann
2531 ee3aedff Michael Hanselmann
def FormatQueryResult(result, unit=None, format_override=None, separator=None,
2532 f0b1bafe Iustin Pop
                      header=False, verbose=False):
2533 ee3aedff Michael Hanselmann
  """Formats data in L{objects.QueryResponse}.
2534 ee3aedff Michael Hanselmann

2535 ee3aedff Michael Hanselmann
  @type result: L{objects.QueryResponse}
2536 ee3aedff Michael Hanselmann
  @param result: result of query operation
2537 ee3aedff Michael Hanselmann
  @type unit: string
2538 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT},
2539 18009c1e Iustin Pop
    see L{utils.text.FormatUnit}
2540 ee3aedff Michael Hanselmann
  @type format_override: dict
2541 ee3aedff Michael Hanselmann
  @param format_override: Dictionary for overriding field formatting functions,
2542 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2543 ee3aedff Michael Hanselmann
  @type separator: string or None
2544 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2545 ee3aedff Michael Hanselmann
  @type header: bool
2546 ee3aedff Michael Hanselmann
  @param header: Whether to output header row
2547 f0b1bafe Iustin Pop
  @type verbose: boolean
2548 f0b1bafe Iustin Pop
  @param verbose: whether to use verbose field descriptions or not
2549 ee3aedff Michael Hanselmann

2550 ee3aedff Michael Hanselmann
  """
2551 ee3aedff Michael Hanselmann
  if unit is None:
2552 ee3aedff Michael Hanselmann
    if separator:
2553 ee3aedff Michael Hanselmann
      unit = "m"
2554 ee3aedff Michael Hanselmann
    else:
2555 ee3aedff Michael Hanselmann
      unit = "h"
2556 ee3aedff Michael Hanselmann
2557 ee3aedff Michael Hanselmann
  if format_override is None:
2558 ee3aedff Michael Hanselmann
    format_override = {}
2559 ee3aedff Michael Hanselmann
2560 cfb084ae René Nussbaumer
  stats = dict.fromkeys(constants.RS_ALL, 0)
2561 ee3aedff Michael Hanselmann
2562 ee3aedff Michael Hanselmann
  def _RecordStatus(status):
2563 ee3aedff Michael Hanselmann
    if status in stats:
2564 ee3aedff Michael Hanselmann
      stats[status] += 1
2565 ee3aedff Michael Hanselmann
2566 ee3aedff Michael Hanselmann
  columns = []
2567 ee3aedff Michael Hanselmann
  for fdef in result.fields:
2568 ee3aedff Michael Hanselmann
    assert fdef.title and fdef.name
2569 ee3aedff Michael Hanselmann
    (fn, align_right) = _GetColumnFormatter(fdef, format_override, unit)
2570 ee3aedff Michael Hanselmann
    columns.append(TableColumn(fdef.title,
2571 f0b1bafe Iustin Pop
                               _QueryColumnFormatter(fn, _RecordStatus,
2572 f0b1bafe Iustin Pop
                                                     verbose),
2573 ee3aedff Michael Hanselmann
                               align_right))
2574 ee3aedff Michael Hanselmann
2575 ee3aedff Michael Hanselmann
  table = FormatTable(result.data, columns, header, separator)
2576 ee3aedff Michael Hanselmann
2577 ee3aedff Michael Hanselmann
  # Collect statistics
2578 cfb084ae René Nussbaumer
  assert len(stats) == len(constants.RS_ALL)
2579 ee3aedff Michael Hanselmann
  assert compat.all(count >= 0 for count in stats.values())
2580 ee3aedff Michael Hanselmann
2581 ee3aedff Michael Hanselmann
  # Determine overall status. If there was no data, unknown fields must be
2582 ee3aedff Michael Hanselmann
  # detected via the field definitions.
2583 cfb084ae René Nussbaumer
  if (stats[constants.RS_UNKNOWN] or
2584 ee3aedff Michael Hanselmann
      (not result.data and _GetUnknownFields(result.fields))):
2585 ee3aedff Michael Hanselmann
    status = QR_UNKNOWN
2586 ee3aedff Michael Hanselmann
  elif compat.any(count > 0 for key, count in stats.items()
2587 cfb084ae René Nussbaumer
                  if key != constants.RS_NORMAL):
2588 ee3aedff Michael Hanselmann
    status = QR_INCOMPLETE
2589 ee3aedff Michael Hanselmann
  else:
2590 ee3aedff Michael Hanselmann
    status = QR_NORMAL
2591 ee3aedff Michael Hanselmann
2592 ee3aedff Michael Hanselmann
  return (status, table)
2593 ee3aedff Michael Hanselmann
2594 ee3aedff Michael Hanselmann
2595 ee3aedff Michael Hanselmann
def _GetUnknownFields(fdefs):
2596 ee3aedff Michael Hanselmann
  """Returns list of unknown fields included in C{fdefs}.
2597 ee3aedff Michael Hanselmann

2598 ee3aedff Michael Hanselmann
  @type fdefs: list of L{objects.QueryFieldDefinition}
2599 ee3aedff Michael Hanselmann

2600 ee3aedff Michael Hanselmann
  """
2601 ee3aedff Michael Hanselmann
  return [fdef for fdef in fdefs
2602 ee3aedff Michael Hanselmann
          if fdef.kind == constants.QFT_UNKNOWN]
2603 ee3aedff Michael Hanselmann
2604 ee3aedff Michael Hanselmann
2605 ee3aedff Michael Hanselmann
def _WarnUnknownFields(fdefs):
2606 ee3aedff Michael Hanselmann
  """Prints a warning to stderr if a query included unknown fields.
2607 ee3aedff Michael Hanselmann

2608 ee3aedff Michael Hanselmann
  @type fdefs: list of L{objects.QueryFieldDefinition}
2609 ee3aedff Michael Hanselmann

2610 ee3aedff Michael Hanselmann
  """
2611 ee3aedff Michael Hanselmann
  unknown = _GetUnknownFields(fdefs)
2612 ee3aedff Michael Hanselmann
  if unknown:
2613 ee3aedff Michael Hanselmann
    ToStderr("Warning: Queried for unknown fields %s",
2614 ee3aedff Michael Hanselmann
             utils.CommaJoin(fdef.name for fdef in unknown))
2615 ee3aedff Michael Hanselmann
    return True
2616 ee3aedff Michael Hanselmann
2617 ee3aedff Michael Hanselmann
  return False
2618 ee3aedff Michael Hanselmann
2619 ee3aedff Michael Hanselmann
2620 ee3aedff Michael Hanselmann
def GenericList(resource, fields, names, unit, separator, header, cl=None,
2621 2928de47 Michael Hanselmann
                format_override=None, verbose=False, force_filter=False):
2622 ee3aedff Michael Hanselmann
  """Generic implementation for listing all items of a resource.
2623 ee3aedff Michael Hanselmann

2624 abd66bf8 Michael Hanselmann
  @param resource: One of L{constants.QR_VIA_LUXI}
2625 ee3aedff Michael Hanselmann
  @type fields: list of strings
2626 ee3aedff Michael Hanselmann
  @param fields: List of fields to query for
2627 ee3aedff Michael Hanselmann
  @type names: list of strings
2628 ee3aedff Michael Hanselmann
  @param names: Names of items to query for
2629 ee3aedff Michael Hanselmann
  @type unit: string or None
2630 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT} or
2631 ee3aedff Michael Hanselmann
    None for automatic choice (human-readable for non-separator usage,
2632 ee3aedff Michael Hanselmann
    otherwise megabytes); this is a one-letter string
2633 ee3aedff Michael Hanselmann
  @type separator: string or None
2634 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2635 ee3aedff Michael Hanselmann
  @type header: bool
2636 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2637 2928de47 Michael Hanselmann
  @type force_filter: bool
2638 2928de47 Michael Hanselmann
  @param force_filter: Whether to always treat names as filter
2639 ee3aedff Michael Hanselmann
  @type format_override: dict
2640 ee3aedff Michael Hanselmann
  @param format_override: Dictionary for overriding field formatting functions,
2641 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2642 f0b1bafe Iustin Pop
  @type verbose: boolean
2643 f0b1bafe Iustin Pop
  @param verbose: whether to use verbose field descriptions or not
2644 ee3aedff Michael Hanselmann

2645 ee3aedff Michael Hanselmann
  """
2646 ee3aedff Michael Hanselmann
  if cl is None:
2647 ee3aedff Michael Hanselmann
    cl = GetClient()
2648 ee3aedff Michael Hanselmann
2649 ee3aedff Michael Hanselmann
  if not names:
2650 ee3aedff Michael Hanselmann
    names = None
2651 ee3aedff Michael Hanselmann
2652 2928de47 Michael Hanselmann
  if (force_filter or
2653 2928de47 Michael Hanselmann
      (names and len(names) == 1 and qlang.MaybeFilter(names[0]))):
2654 2928de47 Michael Hanselmann
    try:
2655 2928de47 Michael Hanselmann
      (filter_text, ) = names
2656 2928de47 Michael Hanselmann
    except ValueError:
2657 2928de47 Michael Hanselmann
      raise errors.OpPrereqError("Exactly one argument must be given as a"
2658 2928de47 Michael Hanselmann
                                 " filter")
2659 2928de47 Michael Hanselmann
2660 2928de47 Michael Hanselmann
    logging.debug("Parsing '%s' as filter", filter_text)
2661 2928de47 Michael Hanselmann
    filter_ = qlang.ParseFilter(filter_text)
2662 2928de47 Michael Hanselmann
  else:
2663 2928de47 Michael Hanselmann
    filter_ = qlang.MakeSimpleFilter("name", names)
2664 2928de47 Michael Hanselmann
2665 2928de47 Michael Hanselmann
  response = cl.Query(resource, fields, filter_)
2666 ee3aedff Michael Hanselmann
2667 ee3aedff Michael Hanselmann
  found_unknown = _WarnUnknownFields(response.fields)
2668 ee3aedff Michael Hanselmann
2669 ee3aedff Michael Hanselmann
  (status, data) = FormatQueryResult(response, unit=unit, separator=separator,
2670 ee3aedff Michael Hanselmann
                                     header=header,
2671 f0b1bafe Iustin Pop
                                     format_override=format_override,
2672 f0b1bafe Iustin Pop
                                     verbose=verbose)
2673 ee3aedff Michael Hanselmann
2674 ee3aedff Michael Hanselmann
  for line in data:
2675 ee3aedff Michael Hanselmann
    ToStdout(line)
2676 ee3aedff Michael Hanselmann
2677 ee3aedff Michael Hanselmann
  assert ((found_unknown and status == QR_UNKNOWN) or
2678 ee3aedff Michael Hanselmann
          (not found_unknown and status != QR_UNKNOWN))
2679 ee3aedff Michael Hanselmann
2680 ee3aedff Michael Hanselmann
  if status == QR_UNKNOWN:
2681 ee3aedff Michael Hanselmann
    return constants.EXIT_UNKNOWN_FIELD
2682 ee3aedff Michael Hanselmann
2683 ee3aedff Michael Hanselmann
  # TODO: Should the list command fail if not all data could be collected?
2684 ee3aedff Michael Hanselmann
  return constants.EXIT_SUCCESS
2685 ee3aedff Michael Hanselmann
2686 ee3aedff Michael Hanselmann
2687 ee3aedff Michael Hanselmann
def GenericListFields(resource, fields, separator, header, cl=None):
2688 ee3aedff Michael Hanselmann
  """Generic implementation for listing fields for a resource.
2689 ee3aedff Michael Hanselmann

2690 abd66bf8 Michael Hanselmann
  @param resource: One of L{constants.QR_VIA_LUXI}
2691 ee3aedff Michael Hanselmann
  @type fields: list of strings
2692 ee3aedff Michael Hanselmann
  @param fields: List of fields to query for
2693 ee3aedff Michael Hanselmann
  @type separator: string or None
2694 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2695 ee3aedff Michael Hanselmann
  @type header: bool
2696 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2697 ee3aedff Michael Hanselmann

2698 ee3aedff Michael Hanselmann
  """
2699 ee3aedff Michael Hanselmann
  if cl is None:
2700 ee3aedff Michael Hanselmann
    cl = GetClient()
2701 ee3aedff Michael Hanselmann
2702 ee3aedff Michael Hanselmann
  if not fields:
2703 ee3aedff Michael Hanselmann
    fields = None
2704 ee3aedff Michael Hanselmann
2705 ee3aedff Michael Hanselmann
  response = cl.QueryFields(resource, fields)
2706 ee3aedff Michael Hanselmann
2707 ee3aedff Michael Hanselmann
  found_unknown = _WarnUnknownFields(response.fields)
2708 ee3aedff Michael Hanselmann
2709 ee3aedff Michael Hanselmann
  columns = [
2710 ee3aedff Michael Hanselmann
    TableColumn("Name", str, False),
2711 ee3aedff Michael Hanselmann
    TableColumn("Title", str, False),
2712 ea1440c1 Michael Hanselmann
    TableColumn("Description", str, False),
2713 ee3aedff Michael Hanselmann
    ]
2714 ee3aedff Michael Hanselmann
2715 ea1440c1 Michael Hanselmann
  rows = [[fdef.name, fdef.title, fdef.doc] for fdef in response.fields]
2716 ee3aedff Michael Hanselmann
2717 ee3aedff Michael Hanselmann
  for line in FormatTable(rows, columns, header, separator):
2718 ee3aedff Michael Hanselmann
    ToStdout(line)
2719 ee3aedff Michael Hanselmann
2720 ee3aedff Michael Hanselmann
  if found_unknown:
2721 ee3aedff Michael Hanselmann
    return constants.EXIT_UNKNOWN_FIELD
2722 ee3aedff Michael Hanselmann
2723 ee3aedff Michael Hanselmann
  return constants.EXIT_SUCCESS
2724 ee3aedff Michael Hanselmann
2725 ee3aedff Michael Hanselmann
2726 ee3aedff Michael Hanselmann
class TableColumn:
2727 ee3aedff Michael Hanselmann
  """Describes a column for L{FormatTable}.
2728 ee3aedff Michael Hanselmann

2729 ee3aedff Michael Hanselmann
  """
2730 ee3aedff Michael Hanselmann
  def __init__(self, title, fn, align_right):
2731 ee3aedff Michael Hanselmann
    """Initializes this class.
2732 ee3aedff Michael Hanselmann

2733 ee3aedff Michael Hanselmann
    @type title: string
2734 ee3aedff Michael Hanselmann
    @param title: Column title
2735 ee3aedff Michael Hanselmann
    @type fn: callable
2736 ee3aedff Michael Hanselmann
    @param fn: Formatting function
2737 ee3aedff Michael Hanselmann
    @type align_right: bool
2738 ee3aedff Michael Hanselmann
    @param align_right: Whether to align values on the right-hand side
2739 ee3aedff Michael Hanselmann

2740 ee3aedff Michael Hanselmann
    """
2741 ee3aedff Michael Hanselmann
    self.title = title
2742 ee3aedff Michael Hanselmann
    self.format = fn
2743 ee3aedff Michael Hanselmann
    self.align_right = align_right
2744 ee3aedff Michael Hanselmann
2745 ee3aedff Michael Hanselmann
2746 ee3aedff Michael Hanselmann
def _GetColFormatString(width, align_right):
2747 ee3aedff Michael Hanselmann
  """Returns the format string for a field.
2748 ee3aedff Michael Hanselmann

2749 ee3aedff Michael Hanselmann
  """
2750 ee3aedff Michael Hanselmann
  if align_right:
2751 ee3aedff Michael Hanselmann
    sign = ""
2752 ee3aedff Michael Hanselmann
  else:
2753 ee3aedff Michael Hanselmann
    sign = "-"
2754 ee3aedff Michael Hanselmann
2755 ee3aedff Michael Hanselmann
  return "%%%s%ss" % (sign, width)
2756 ee3aedff Michael Hanselmann
2757 ee3aedff Michael Hanselmann
2758 ee3aedff Michael Hanselmann
def FormatTable(rows, columns, header, separator):
2759 ee3aedff Michael Hanselmann
  """Formats data as a table.
2760 ee3aedff Michael Hanselmann

2761 ee3aedff Michael Hanselmann
  @type rows: list of lists
2762 ee3aedff Michael Hanselmann
  @param rows: Row data, one list per row
2763 ee3aedff Michael Hanselmann
  @type columns: list of L{TableColumn}
2764 ee3aedff Michael Hanselmann
  @param columns: Column descriptions
2765 ee3aedff Michael Hanselmann
  @type header: bool
2766 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2767 ee3aedff Michael Hanselmann
  @type separator: string or None
2768 ee3aedff Michael Hanselmann
  @param separator: String used to separate columns
2769 ee3aedff Michael Hanselmann

2770 ee3aedff Michael Hanselmann
  """
2771 ee3aedff Michael Hanselmann
  if header:
2772 ee3aedff Michael Hanselmann
    data = [[col.title for col in columns]]
2773 ee3aedff Michael Hanselmann
    colwidth = [len(col.title) for col in columns]
2774 ee3aedff Michael Hanselmann
  else:
2775 ee3aedff Michael Hanselmann
    data = []
2776 ee3aedff Michael Hanselmann
    colwidth = [0 for _ in columns]
2777 ee3aedff Michael Hanselmann
2778 ee3aedff Michael Hanselmann
  # Format row data
2779 ee3aedff Michael Hanselmann
  for row in rows:
2780 ee3aedff Michael Hanselmann
    assert len(row) == len(columns)
2781 ee3aedff Michael Hanselmann
2782 ee3aedff Michael Hanselmann
    formatted = [col.format(value) for value, col in zip(row, columns)]
2783 ee3aedff Michael Hanselmann
2784 ee3aedff Michael Hanselmann
    if separator is None:
2785 ee3aedff Michael Hanselmann
      # Update column widths
2786 ee3aedff Michael Hanselmann
      for idx, (oldwidth, value) in enumerate(zip(colwidth, formatted)):
2787 ee3aedff Michael Hanselmann
        # Modifying a list's items while iterating is fine
2788 ee3aedff Michael Hanselmann
        colwidth[idx] = max(oldwidth, len(value))
2789 ee3aedff Michael Hanselmann
2790 ee3aedff Michael Hanselmann
    data.append(formatted)
2791 ee3aedff Michael Hanselmann
2792 ee3aedff Michael Hanselmann
  if separator is not None:
2793 ee3aedff Michael Hanselmann
    # Return early if a separator is used
2794 ee3aedff Michael Hanselmann
    return [separator.join(row) for row in data]
2795 ee3aedff Michael Hanselmann
2796 ee3aedff Michael Hanselmann
  if columns and not columns[-1].align_right:
2797 ee3aedff Michael Hanselmann
    # Avoid unnecessary spaces at end of line
2798 ee3aedff Michael Hanselmann
    colwidth[-1] = 0
2799 ee3aedff Michael Hanselmann
2800 ee3aedff Michael Hanselmann
  # Build format string
2801 ee3aedff Michael Hanselmann
  fmt = " ".join([_GetColFormatString(width, col.align_right)
2802 ee3aedff Michael Hanselmann
                  for col, width in zip(columns, colwidth)])
2803 ee3aedff Michael Hanselmann
2804 ee3aedff Michael Hanselmann
  return [fmt % tuple(row) for row in data]
2805 ee3aedff Michael Hanselmann
2806 ee3aedff Michael Hanselmann
2807 3386e7a9 Iustin Pop
def FormatTimestamp(ts):
2808 3386e7a9 Iustin Pop
  """Formats a given timestamp.
2809 3386e7a9 Iustin Pop

2810 3386e7a9 Iustin Pop
  @type ts: timestamp
2811 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
2812 3386e7a9 Iustin Pop

2813 3386e7a9 Iustin Pop
  @rtype: string
2814 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
2815 3386e7a9 Iustin Pop

2816 3386e7a9 Iustin Pop
  """
2817 e0ec0ff6 Iustin Pop
  if not isinstance (ts, (tuple, list)) or len(ts) != 2:
2818 e0ec0ff6 Iustin Pop
    return '?'
2819 3386e7a9 Iustin Pop
  sec, usec = ts
2820 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
2821 2241e2b9 Iustin Pop
2822 2241e2b9 Iustin Pop
2823 2241e2b9 Iustin Pop
def ParseTimespec(value):
2824 2241e2b9 Iustin Pop
  """Parse a time specification.
2825 2241e2b9 Iustin Pop

2826 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
2827 2241e2b9 Iustin Pop

2828 2241e2b9 Iustin Pop
    - s: seconds
2829 2241e2b9 Iustin Pop
    - m: minutes
2830 2241e2b9 Iustin Pop
    - h: hours
2831 2241e2b9 Iustin Pop
    - d: day
2832 2241e2b9 Iustin Pop
    - w: weeks
2833 2241e2b9 Iustin Pop

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

2836 2241e2b9 Iustin Pop
  """
2837 2241e2b9 Iustin Pop
  value = str(value)
2838 2241e2b9 Iustin Pop
  if not value:
2839 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
2840 2241e2b9 Iustin Pop
  suffix_map = {
2841 2241e2b9 Iustin Pop
    's': 1,
2842 2241e2b9 Iustin Pop
    'm': 60,
2843 2241e2b9 Iustin Pop
    'h': 3600,
2844 2241e2b9 Iustin Pop
    'd': 86400,
2845 2241e2b9 Iustin Pop
    'w': 604800,
2846 2241e2b9 Iustin Pop
    }
2847 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
2848 2241e2b9 Iustin Pop
    try:
2849 2241e2b9 Iustin Pop
      value = int(value)
2850 691744c4 Iustin Pop
    except (TypeError, ValueError):
2851 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2852 2241e2b9 Iustin Pop
  else:
2853 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
2854 2241e2b9 Iustin Pop
    value = value[:-1]
2855 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
2856 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
2857 2241e2b9 Iustin Pop
                                 " suffix passed)")
2858 2241e2b9 Iustin Pop
    try:
2859 2241e2b9 Iustin Pop
      value = int(value) * multiplier
2860 691744c4 Iustin Pop
    except (TypeError, ValueError):
2861 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2862 2241e2b9 Iustin Pop
  return value
2863 46fbdd04 Iustin Pop
2864 46fbdd04 Iustin Pop
2865 e9e26bb3 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False, secondary_ips=False,
2866 e9e26bb3 Iustin Pop
                   filter_master=False):
2867 4040a784 Iustin Pop
  """Returns the names of online nodes.
2868 4040a784 Iustin Pop

2869 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
2870 4040a784 Iustin Pop
  the online nodes.
2871 4040a784 Iustin Pop

2872 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
2873 4040a784 Iustin Pop
      offline ones)
2874 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
2875 4040a784 Iustin Pop
  @type nowarn: boolean
2876 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
2877 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
2878 4040a784 Iustin Pop
      note is not displayed
2879 e9e26bb3 Iustin Pop
  @type secondary_ips: boolean
2880 e9e26bb3 Iustin Pop
  @param secondary_ips: if True, return the secondary IPs instead of the
2881 e9e26bb3 Iustin Pop
      names, useful for doing network traffic over the replication interface
2882 e9e26bb3 Iustin Pop
      (if any)
2883 e9e26bb3 Iustin Pop
  @type filter_master: boolean
2884 e9e26bb3 Iustin Pop
  @param filter_master: if True, do not return the master node in the list
2885 e9e26bb3 Iustin Pop
      (useful in coordination with secondary_ips where we cannot check our
2886 e9e26bb3 Iustin Pop
      node name against the list)
2887 4040a784 Iustin Pop

2888 4040a784 Iustin Pop
  """
2889 4040a784 Iustin Pop
  if cl is None:
2890 4040a784 Iustin Pop
    cl = GetClient()
2891 4040a784 Iustin Pop
2892 e9e26bb3 Iustin Pop
  if secondary_ips:
2893 e9e26bb3 Iustin Pop
    name_idx = 2
2894 e9e26bb3 Iustin Pop
  else:
2895 e9e26bb3 Iustin Pop
    name_idx = 0
2896 e9e26bb3 Iustin Pop
2897 e9e26bb3 Iustin Pop
  if filter_master:
2898 e9e26bb3 Iustin Pop
    master_node = cl.QueryConfigValues(["master_node"])[0]
2899 e9e26bb3 Iustin Pop
    filter_fn = lambda x: x != master_node
2900 e9e26bb3 Iustin Pop
  else:
2901 e9e26bb3 Iustin Pop
    filter_fn = lambda _: True
2902 e9e26bb3 Iustin Pop
2903 e9e26bb3 Iustin Pop
  result = cl.QueryNodes(names=nodes, fields=["name", "offline", "sip"],
2904 2e7b8369 Iustin Pop
                         use_locking=False)
2905 4040a784 Iustin Pop
  offline = [row[0] for row in result if row[1]]
2906 4040a784 Iustin Pop
  if offline and not nowarn:
2907 1f864b60 Iustin Pop
    ToStderr("Note: skipping offline node(s): %s" % utils.CommaJoin(offline))
2908 e9e26bb3 Iustin Pop
  return [row[name_idx] for row in result if not row[1] and filter_fn(row[0])]
2909 4040a784 Iustin Pop
2910 4040a784 Iustin Pop
2911 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
2912 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
2913 46fbdd04 Iustin Pop

2914 46fbdd04 Iustin Pop
  @type stream: file object
2915 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
2916 46fbdd04 Iustin Pop
  @type txt: str
2917 46fbdd04 Iustin Pop
  @param txt: the message
2918 46fbdd04 Iustin Pop

2919 46fbdd04 Iustin Pop
  """
2920 225e2544 Iustin Pop
  try:
2921 225e2544 Iustin Pop
    if args:
2922 225e2544 Iustin Pop
      args = tuple(args)
2923 225e2544 Iustin Pop
      stream.write(txt % args)
2924 225e2544 Iustin Pop
    else:
2925 225e2544 Iustin Pop
      stream.write(txt)
2926 225e2544 Iustin Pop
    stream.write('\n')
2927 225e2544 Iustin Pop
    stream.flush()
2928 225e2544 Iustin Pop
  except IOError, err:
2929 225e2544 Iustin Pop
    if err.errno == errno.EPIPE:
2930 225e2544 Iustin Pop
      # our terminal went away, we'll exit
2931 225e2544 Iustin Pop
      sys.exit(constants.EXIT_FAILURE)
2932 225e2544 Iustin Pop
    else:
2933 225e2544 Iustin Pop
      raise
2934 46fbdd04 Iustin Pop
2935 46fbdd04 Iustin Pop
2936 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
2937 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
2938 46fbdd04 Iustin Pop

2939 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2940 46fbdd04 Iustin Pop

2941 46fbdd04 Iustin Pop
  @type txt: str
2942 46fbdd04 Iustin Pop
  @param txt: the message
2943 46fbdd04 Iustin Pop

2944 46fbdd04 Iustin Pop
  """
2945 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
2946 46fbdd04 Iustin Pop
2947 46fbdd04 Iustin Pop
2948 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
2949 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
2950 46fbdd04 Iustin Pop

2951 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2952 46fbdd04 Iustin Pop

2953 46fbdd04 Iustin Pop
  @type txt: str
2954 46fbdd04 Iustin Pop
  @param txt: the message
2955 46fbdd04 Iustin Pop

2956 46fbdd04 Iustin Pop
  """
2957 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
2958 479636a3 Iustin Pop
2959 479636a3 Iustin Pop
2960 479636a3 Iustin Pop
class JobExecutor(object):
2961 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
2962 479636a3 Iustin Pop

2963 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
2964 479636a3 Iustin Pop
  GetResults() calls.
2965 479636a3 Iustin Pop

2966 479636a3 Iustin Pop
  """
2967 919ca415 Iustin Pop
  def __init__(self, cl=None, verbose=True, opts=None, feedback_fn=None):
2968 479636a3 Iustin Pop
    self.queue = []
2969 479636a3 Iustin Pop
    if cl is None:
2970 479636a3 Iustin Pop
      cl = GetClient()
2971 479636a3 Iustin Pop
    self.cl = cl
2972 479636a3 Iustin Pop
    self.verbose = verbose
2973 23b4b983 Iustin Pop
    self.jobs = []
2974 cff5fa7f Iustin Pop
    self.opts = opts
2975 919ca415 Iustin Pop
    self.feedback_fn = feedback_fn
2976 60452edf Michael Hanselmann
    self._counter = itertools.count()
2977 479636a3 Iustin Pop
2978 8d99a8bf Michael Hanselmann
  @staticmethod
2979 8d99a8bf Michael Hanselmann
  def _IfName(name, fmt):
2980 8d99a8bf Michael Hanselmann
    """Helper function for formatting name.
2981 8d99a8bf Michael Hanselmann

2982 8d99a8bf Michael Hanselmann
    """
2983 8d99a8bf Michael Hanselmann
    if name:
2984 8d99a8bf Michael Hanselmann
      return fmt % name
2985 8d99a8bf Michael Hanselmann
2986 8d99a8bf Michael Hanselmann
    return ""
2987 8d99a8bf Michael Hanselmann
2988 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
2989 23b4b983 Iustin Pop
    """Record a job for later submit.
2990 479636a3 Iustin Pop

2991 479636a3 Iustin Pop
    @type name: string
2992 479636a3 Iustin Pop
    @param name: a description of the job, will be used in WaitJobSet
2993 8d99a8bf Michael Hanselmann

2994 479636a3 Iustin Pop
    """
2995 cff5fa7f Iustin Pop
    SetGenericOpcodeOpts(ops, self.opts)
2996 60452edf Michael Hanselmann
    self.queue.append((self._counter.next(), name, ops))
2997 23b4b983 Iustin Pop
2998 8d99a8bf Michael Hanselmann
  def AddJobId(self, name, status, job_id):
2999 8d99a8bf Michael Hanselmann
    """Adds a job ID to the internal queue.
3000 8d99a8bf Michael Hanselmann

3001 8d99a8bf Michael Hanselmann
    """
3002 8d99a8bf Michael Hanselmann
    self.jobs.append((self._counter.next(), status, job_id, name))
3003 8d99a8bf Michael Hanselmann
3004 66ecc479 Guido Trotter
  def SubmitPending(self, each=False):
3005 23b4b983 Iustin Pop
    """Submit all pending jobs.
3006 23b4b983 Iustin Pop

3007 23b4b983 Iustin Pop
    """
3008 66ecc479 Guido Trotter
    if each:
3009 66ecc479 Guido Trotter
      results = []
3010 60452edf Michael Hanselmann
      for (_, _, ops) in self.queue:
3011 66ecc479 Guido Trotter
        # SubmitJob will remove the success status, but raise an exception if
3012 66ecc479 Guido Trotter
        # the submission fails, so we'll notice that anyway.
3013 60452edf Michael Hanselmann
        results.append([True, self.cl.SubmitJob(ops)])
3014 66ecc479 Guido Trotter
    else:
3015 60452edf Michael Hanselmann
      results = self.cl.SubmitManyJobs([ops for (_, _, ops) in self.queue])
3016 60452edf Michael Hanselmann
    for ((status, data), (idx, name, _)) in zip(results, self.queue):
3017 5299e61f Iustin Pop
      self.jobs.append((idx, status, data, name))
3018 5299e61f Iustin Pop
3019 5299e61f Iustin Pop
  def _ChooseJob(self):
3020 5299e61f Iustin Pop
    """Choose a non-waiting/queued job to poll next.
3021 5299e61f Iustin Pop

3022 5299e61f Iustin Pop
    """
3023 5299e61f Iustin Pop
    assert self.jobs, "_ChooseJob called with empty job list"
3024 5299e61f Iustin Pop
3025 5299e61f Iustin Pop
    result = self.cl.QueryJobs([i[2] for i in self.jobs], ["status"])
3026 5299e61f Iustin Pop
    assert result
3027 5299e61f Iustin Pop
3028 5299e61f Iustin Pop
    for job_data, status in zip(self.jobs, result):
3029 91c622a8 Iustin Pop
      if (isinstance(status, list) and status and
3030 91c622a8 Iustin Pop
          status[0] in (constants.JOB_STATUS_QUEUED,
3031 91c622a8 Iustin Pop
                        constants.JOB_STATUS_WAITLOCK,
3032 91c622a8 Iustin Pop
                        constants.JOB_STATUS_CANCELING)):
3033 91c622a8 Iustin Pop
        # job is still present and waiting
3034 5299e61f Iustin Pop
        continue
3035 91c622a8 Iustin Pop
      # good candidate found (either running job or lost job)
3036 5299e61f Iustin Pop
      self.jobs.remove(job_data)
3037 5299e61f Iustin Pop
      return job_data
3038 5299e61f Iustin Pop
3039 5299e61f Iustin Pop
    # no job found
3040 5299e61f Iustin Pop
    return self.jobs.pop(0)
3041 479636a3 Iustin Pop
3042 479636a3 Iustin Pop
  def GetResults(self):
3043 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
3044 479636a3 Iustin Pop

3045 479636a3 Iustin Pop
    @rtype: list
3046 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
3047 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
3048 479636a3 Iustin Pop
        there will be the error message
3049 479636a3 Iustin Pop

3050 479636a3 Iustin Pop
    """
3051 23b4b983 Iustin Pop
    if not self.jobs:
3052 23b4b983 Iustin Pop
      self.SubmitPending()
3053 479636a3 Iustin Pop
    results = []
3054 479636a3 Iustin Pop
    if self.verbose:
3055 5299e61f Iustin Pop
      ok_jobs = [row[2] for row in self.jobs if row[1]]
3056 23b4b983 Iustin Pop
      if ok_jobs:
3057 1f864b60 Iustin Pop
        ToStdout("Submitted jobs %s", utils.CommaJoin(ok_jobs))
3058 5299e61f Iustin Pop
3059 5299e61f Iustin Pop
    # first, remove any non-submitted jobs
3060 cea881e5 Michael Hanselmann
    self.jobs, failures = compat.partition(self.jobs, lambda x: x[1])
3061 5299e61f Iustin Pop
    for idx, _, jid, name in failures:
3062 8d99a8bf Michael Hanselmann
      ToStderr("Failed to submit job%s: %s", self._IfName(name, " for %s"), jid)
3063 c63355f2 Iustin Pop
      results.append((idx, False, jid))
3064 5299e61f Iustin Pop
3065 5299e61f Iustin Pop
    while self.jobs:
3066 5299e61f Iustin Pop
      (idx, _, jid, name) = self._ChooseJob()
3067 8d99a8bf Michael Hanselmann
      ToStdout("Waiting for job %s%s ...", jid, self._IfName(name, " for %s"))
3068 479636a3 Iustin Pop
      try:
3069 919ca415 Iustin Pop
        job_result = PollJob(jid, cl=self.cl, feedback_fn=self.feedback_fn)
3070 479636a3 Iustin Pop
        success = True
3071 91c622a8 Iustin Pop
      except errors.JobLost, err:
3072 91c622a8 Iustin Pop
        _, job_result = FormatError(err)
3073 8d99a8bf Michael Hanselmann
        ToStderr("Job %s%s has been archived, cannot check its result",
3074 8d99a8bf Michael Hanselmann
                 jid, self._IfName(name, " for %s"))
3075 91c622a8 Iustin Pop
        success = False
3076 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
3077 479636a3 Iustin Pop
        _, job_result = FormatError(err)
3078 479636a3 Iustin Pop
        success = False
3079 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
3080 8d99a8bf Michael Hanselmann
        ToStderr("Job %s%s has failed: %s",
3081 8d99a8bf Michael Hanselmann
                 jid, self._IfName(name, " for %s"), job_result)
3082 479636a3 Iustin Pop
3083 5299e61f Iustin Pop
      results.append((idx, success, job_result))
3084 5299e61f Iustin Pop
3085 5299e61f Iustin Pop
    # sort based on the index, then drop it
3086 5299e61f Iustin Pop
    results.sort()
3087 5299e61f Iustin Pop
    results = [i[1:] for i in results]
3088 5299e61f Iustin Pop
3089 479636a3 Iustin Pop
    return results
3090 479636a3 Iustin Pop
3091 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
3092 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
3093 479636a3 Iustin Pop

3094 479636a3 Iustin Pop
    @type wait: boolean
3095 479636a3 Iustin Pop
    @param wait: whether to wait or not
3096 479636a3 Iustin Pop

3097 479636a3 Iustin Pop
    """
3098 479636a3 Iustin Pop
    if wait:
3099 479636a3 Iustin Pop
      return self.GetResults()
3100 479636a3 Iustin Pop
    else:
3101 23b4b983 Iustin Pop
      if not self.jobs:
3102 23b4b983 Iustin Pop
        self.SubmitPending()
3103 71834b2a Guido Trotter
      for _, status, result, name in self.jobs:
3104 23b4b983 Iustin Pop
        if status:
3105 23b4b983 Iustin Pop
          ToStdout("%s: %s", result, name)
3106 23b4b983 Iustin Pop
        else:
3107 23b4b983 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)
3108 53a8a54d Iustin Pop
      return [row[1:3] for row in self.jobs]
3109 acd19189 René Nussbaumer
3110 acd19189 René Nussbaumer
3111 acd19189 René Nussbaumer
def FormatParameterDict(buf, param_dict, actual, level=1):
3112 acd19189 René Nussbaumer
  """Formats a parameter dictionary.
3113 acd19189 René Nussbaumer

3114 acd19189 René Nussbaumer
  @type buf: L{StringIO}
3115 acd19189 René Nussbaumer
  @param buf: the buffer into which to write
3116 acd19189 René Nussbaumer
  @type param_dict: dict
3117 acd19189 René Nussbaumer
  @param param_dict: the own parameters
3118 acd19189 René Nussbaumer
  @type actual: dict
3119 acd19189 René Nussbaumer
  @param actual: the current parameter set (including defaults)
3120 acd19189 René Nussbaumer
  @param level: Level of indent
3121 acd19189 René Nussbaumer

3122 acd19189 René Nussbaumer
  """
3123 acd19189 René Nussbaumer
  indent = "  " * level
3124 acd19189 René Nussbaumer
  for key in sorted(actual):
3125 acd19189 René Nussbaumer
    val = param_dict.get(key, "default (%s)" % actual[key])
3126 acd19189 René Nussbaumer
    buf.write("%s- %s: %s\n" % (indent, key, val))
3127 25bd815c René Nussbaumer
3128 25bd815c René Nussbaumer
3129 25bd815c René Nussbaumer
def ConfirmOperation(names, list_type, text, extra=""):
3130 25bd815c René Nussbaumer
  """Ask the user to confirm an operation on a list of list_type.
3131 25bd815c René Nussbaumer

3132 25bd815c René Nussbaumer
  This function is used to request confirmation for doing an operation
3133 25bd815c René Nussbaumer
  on a given list of list_type.
3134 25bd815c René Nussbaumer

3135 25bd815c René Nussbaumer
  @type names: list
3136 25bd815c René Nussbaumer
  @param names: the list of names that we display when
3137 25bd815c René Nussbaumer
      we ask for confirmation
3138 25bd815c René Nussbaumer
  @type list_type: str
3139 25bd815c René Nussbaumer
  @param list_type: Human readable name for elements in the list (e.g. nodes)
3140 25bd815c René Nussbaumer
  @type text: str
3141 25bd815c René Nussbaumer
  @param text: the operation that the user should confirm
3142 25bd815c René Nussbaumer
  @rtype: boolean
3143 25bd815c René Nussbaumer
  @return: True or False depending on user's confirmation.
3144 25bd815c René Nussbaumer

3145 25bd815c René Nussbaumer
  """
3146 25bd815c René Nussbaumer
  count = len(names)
3147 25bd815c René Nussbaumer
  msg = ("The %s will operate on %d %s.\n%s"
3148 25bd815c René Nussbaumer
         "Do you want to continue?" % (text, count, list_type, extra))
3149 25bd815c René Nussbaumer
  affected = (("\nAffected %s:\n" % list_type) +
3150 25bd815c René Nussbaumer
              "\n".join(["  %s" % name for name in names]))
3151 25bd815c René Nussbaumer
3152 25bd815c René Nussbaumer
  choices = [("y", True, "Yes, execute the %s" % text),
3153 25bd815c René Nussbaumer
             ("n", False, "No, abort the %s" % text)]
3154 25bd815c René Nussbaumer
3155 25bd815c René Nussbaumer
  if count > 20:
3156 25bd815c René Nussbaumer
    choices.insert(1, ("v", "v", "View the list of affected %s" % list_type))
3157 25bd815c René Nussbaumer
    question = msg
3158 25bd815c René Nussbaumer
  else:
3159 25bd815c René Nussbaumer
    question = msg + affected
3160 25bd815c René Nussbaumer
3161 25bd815c René Nussbaumer
  choice = AskUser(question, choices)
3162 25bd815c René Nussbaumer
  if choice == "v":
3163 25bd815c René Nussbaumer
    choices.pop(1)
3164 25bd815c René Nussbaumer
    choice = AskUser(msg + affected, choices)
3165 25bd815c René Nussbaumer
  return choice