Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ 57ca011e

History | View | Annotate | Download (104.1 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 93f2399e Andrea Spadaccini
  "IGNORE_ERRORS_OPT",
96 b6e841a8 Iustin Pop
  "IGNORE_FAILURES_OPT",
97 b44bd844 Michael Hanselmann
  "IGNORE_OFFLINE_OPT",
98 8d8d650c Michael Hanselmann
  "IGNORE_REMOVE_FAILURES_OPT",
99 ee3f9578 Iustin Pop
  "IGNORE_SECONDARIES_OPT",
100 05586c90 Iustin Pop
  "IGNORE_SIZE_OPT",
101 19b9ba9a Michael Hanselmann
  "INTERVAL_OPT",
102 e3646f22 Iustin Pop
  "MAC_PREFIX_OPT",
103 3953242f Iustin Pop
  "MAINTAIN_NODE_HEALTH_OPT",
104 29392516 Iustin Pop
  "MASTER_NETDEV_OPT",
105 5a8648eb Andrea Spadaccini
  "MASTER_NETMASK_OPT",
106 771734c9 Iustin Pop
  "MC_OPT",
107 783a6c0b Iustin Pop
  "MIGRATION_MODE_OPT",
108 7d3a9fab Iustin Pop
  "NET_OPT",
109 6d4a1656 Michael Hanselmann
  "NEW_CLUSTER_CERT_OPT",
110 3db3eb2a Michael Hanselmann
  "NEW_CLUSTER_DOMAIN_SECRET_OPT",
111 6b7d5878 Michael Hanselmann
  "NEW_CONFD_HMAC_KEY_OPT",
112 6d4a1656 Michael Hanselmann
  "NEW_RAPI_CERT_OPT",
113 a14db5ff Iustin Pop
  "NEW_SECONDARY_OPT",
114 b6267745 Andrea Spadaccini
  "NEW_SPICE_CERT_OPT",
115 4fbc93dd Iustin Pop
  "NIC_PARAMS_OPT",
116 61413377 Stephen Shirley
  "NODE_FORCE_JOIN_OPT",
117 7edc4637 Iustin Pop
  "NODE_LIST_OPT",
118 990b7886 Iustin Pop
  "NODE_PLACEMENT_OPT",
119 5fbbd028 Guido Trotter
  "NODEGROUP_OPT",
120 a535cef7 René Nussbaumer
  "NODE_PARAMS_OPT",
121 dd94e9f6 René Nussbaumer
  "NODE_POWERED_OPT",
122 26591bfd Luca Bigliardi
  "NODRBD_STORAGE_OPT",
123 4abc4f1e Iustin Pop
  "NOHDR_OPT",
124 91e0748c Iustin Pop
  "NOIPCHECK_OPT",
125 25a8792c Iustin Pop
  "NO_INSTALL_OPT",
126 460d22be Iustin Pop
  "NONAMECHECK_OPT",
127 831040bf Iustin Pop
  "NOLVM_STORAGE_OPT",
128 29392516 Iustin Pop
  "NOMODIFY_ETCHOSTS_OPT",
129 b989b9d9 Ken Wehr
  "NOMODIFY_SSH_SETUP_OPT",
130 26023ecd Iustin Pop
  "NONICS_OPT",
131 f2a0828c Iustin Pop
  "NONLIVE_OPT",
132 14e9e7f3 Iustin Pop
  "NONPLUS1_OPT",
133 44c44832 Iustin Pop
  "NOSHUTDOWN_OPT",
134 edeb878a Iustin Pop
  "NOSTART_OPT",
135 fcdde7f2 Iustin Pop
  "NOSSH_KEYCHECK_OPT",
136 58371861 Iustin Pop
  "NOVOTING_OPT",
137 885a0fc4 Iustin Pop
  "NO_REMEMBER_OPT",
138 3f75b4f3 Iustin Pop
  "NWSYNC_OPT",
139 a72d0a79 Iustin Pop
  "ON_PRIMARY_OPT",
140 feb09e6a Iustin Pop
  "ON_SECONDARY_OPT",
141 771734c9 Iustin Pop
  "OFFLINE_OPT",
142 062a7100 Iustin Pop
  "OSPARAMS_OPT",
143 d3ed23ff Iustin Pop
  "OS_OPT",
144 ff00c1a7 Iustin Pop
  "OS_SIZE_OPT",
145 41543d8b René Nussbaumer
  "OOB_TIMEOUT_OPT",
146 0c086a13 René Nussbaumer
  "POWER_DELAY_OPT",
147 b883637f René Nussbaumer
  "PREALLOC_WIPE_DISKS_OPT",
148 e7323b5e Manuel Franceschini
  "PRIMARY_IP_VERSION_OPT",
149 aafee533 Michael Hanselmann
  "PRIMARY_ONLY_OPT",
150 84a5b33c Michael Hanselmann
  "PRIORITY_OPT",
151 6d4a1656 Michael Hanselmann
  "RAPI_CERT_OPT",
152 b8d0f938 Iustin Pop
  "READD_OPT",
153 12054861 Iustin Pop
  "REBOOT_TYPE_OPT",
154 8d8d650c Michael Hanselmann
  "REMOVE_INSTANCE_OPT",
155 fdad8c4d Balazs Lecz
  "REMOVE_UIDS_OPT",
156 f38ea602 Iustin Pop
  "RESERVED_LVS_OPT",
157 31d97b2a Guido Trotter
  "ROMAN_OPT",
158 8d823629 Iustin Pop
  "SECONDARY_IP_OPT",
159 aafee533 Michael Hanselmann
  "SECONDARY_ONLY_OPT",
160 67840b40 Iustin Pop
  "SELECT_OS_OPT",
161 4abc4f1e Iustin Pop
  "SEP_OPT",
162 fdcf4d84 Iustin Pop
  "SHOWCMD_OPT",
163 7e5eaaa8 Guido Trotter
  "SHUTDOWN_TIMEOUT_OPT",
164 f36d7d81 Iustin Pop
  "SINGLE_NODE_OPT",
165 b6267745 Andrea Spadaccini
  "SPICE_CACERT_OPT",
166 b6267745 Andrea Spadaccini
  "SPICE_CERT_OPT",
167 df62e5db Iustin Pop
  "SRC_DIR_OPT",
168 df62e5db Iustin Pop
  "SRC_NODE_OPT",
169 4abc4f1e Iustin Pop
  "SUBMIT_OPT",
170 323f9095 Stephen Shirley
  "STARTUP_PAUSED_OPT",
171 99a8c799 Iustin Pop
  "STATIC_OPT",
172 4abc4f1e Iustin Pop
  "SYNC_OPT",
173 a57981c5 Apollon Oikonomopoulos
  "TAG_ADD_OPT",
174 4abc4f1e Iustin Pop
  "TAG_SRC_OPT",
175 b5762e2a Guido Trotter
  "TIMEOUT_OPT",
176 f6eb380d Michael Hanselmann
  "TO_GROUP_OPT",
177 1338f2b4 Balazs Lecz
  "UIDPOOL_OPT",
178 4abc4f1e Iustin Pop
  "USEUNITS_OPT",
179 74adc100 Iustin Pop
  "USE_REPL_NET_OPT",
180 9cdb9578 Iustin Pop
  "VERBOSE_OPT",
181 b58726e8 Iustin Pop
  "VG_NAME_OPT",
182 1f587d3d Iustin Pop
  "YES_DOIT_OPT",
183 4abc4f1e Iustin Pop
  # Generic functions for CLI programs
184 25bd815c René Nussbaumer
  "ConfirmOperation",
185 4abc4f1e Iustin Pop
  "GenericMain",
186 d77490c5 Iustin Pop
  "GenericInstanceCreate",
187 ee3aedff Michael Hanselmann
  "GenericList",
188 ee3aedff Michael Hanselmann
  "GenericListFields",
189 4abc4f1e Iustin Pop
  "GetClient",
190 4abc4f1e Iustin Pop
  "GetOnlineNodes",
191 4abc4f1e Iustin Pop
  "JobExecutor",
192 4abc4f1e Iustin Pop
  "JobSubmittedException",
193 4abc4f1e Iustin Pop
  "ParseTimespec",
194 7e49b6ce Michael Hanselmann
  "RunWhileClusterStopped",
195 4abc4f1e Iustin Pop
  "SubmitOpCode",
196 4abc4f1e Iustin Pop
  "SubmitOrSend",
197 4abc4f1e Iustin Pop
  "UsesRPC",
198 4abc4f1e Iustin Pop
  # Formatting functions
199 4abc4f1e Iustin Pop
  "ToStderr", "ToStdout",
200 4abc4f1e Iustin Pop
  "FormatError",
201 ee3aedff Michael Hanselmann
  "FormatQueryResult",
202 acd19189 René Nussbaumer
  "FormatParameterDict",
203 4abc4f1e Iustin Pop
  "GenerateTable",
204 4abc4f1e Iustin Pop
  "AskUser",
205 4abc4f1e Iustin Pop
  "FormatTimestamp",
206 8a7f1c61 Michael Hanselmann
  "FormatLogMessage",
207 4abc4f1e Iustin Pop
  # Tags functions
208 4abc4f1e Iustin Pop
  "ListTags",
209 4abc4f1e Iustin Pop
  "AddTags",
210 4abc4f1e Iustin Pop
  "RemoveTags",
211 4abc4f1e Iustin Pop
  # command line options support infrastructure
212 4abc4f1e Iustin Pop
  "ARGS_MANY_INSTANCES",
213 4abc4f1e Iustin Pop
  "ARGS_MANY_NODES",
214 667dbd6b Adeodato Simo
  "ARGS_MANY_GROUPS",
215 4abc4f1e Iustin Pop
  "ARGS_NONE",
216 4abc4f1e Iustin Pop
  "ARGS_ONE_INSTANCE",
217 4abc4f1e Iustin Pop
  "ARGS_ONE_NODE",
218 667dbd6b Adeodato Simo
  "ARGS_ONE_GROUP",
219 f9faf9c3 René Nussbaumer
  "ARGS_ONE_OS",
220 4abc4f1e Iustin Pop
  "ArgChoice",
221 4abc4f1e Iustin Pop
  "ArgCommand",
222 4abc4f1e Iustin Pop
  "ArgFile",
223 667dbd6b Adeodato Simo
  "ArgGroup",
224 4abc4f1e Iustin Pop
  "ArgHost",
225 4abc4f1e Iustin Pop
  "ArgInstance",
226 4abc4f1e Iustin Pop
  "ArgJobId",
227 4abc4f1e Iustin Pop
  "ArgNode",
228 f9faf9c3 René Nussbaumer
  "ArgOs",
229 4abc4f1e Iustin Pop
  "ArgSuggest",
230 4abc4f1e Iustin Pop
  "ArgUnknown",
231 4abc4f1e Iustin Pop
  "OPT_COMPL_INST_ADD_NODES",
232 4abc4f1e Iustin Pop
  "OPT_COMPL_MANY_NODES",
233 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_IALLOCATOR",
234 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_INSTANCE",
235 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_NODE",
236 36e247e1 Guido Trotter
  "OPT_COMPL_ONE_NODEGROUP",
237 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_OS",
238 4abc4f1e Iustin Pop
  "cli_option",
239 4abc4f1e Iustin Pop
  "SplitNodeOption",
240 07150497 Guido Trotter
  "CalculateOSNames",
241 a4ebd726 Michael Hanselmann
  "ParseFields",
242 eb28ecf6 Guido Trotter
  "COMMON_CREATE_OPTS",
243 4abc4f1e Iustin Pop
  ]
244 846baef9 Iustin Pop
245 8b46606c Guido Trotter
NO_PREFIX = "no_"
246 8b46606c Guido Trotter
UN_PREFIX = "-"
247 846baef9 Iustin Pop
248 84a5b33c Michael Hanselmann
#: Priorities (sorted)
249 84a5b33c Michael Hanselmann
_PRIORITY_NAMES = [
250 84a5b33c Michael Hanselmann
  ("low", constants.OP_PRIO_LOW),
251 84a5b33c Michael Hanselmann
  ("normal", constants.OP_PRIO_NORMAL),
252 84a5b33c Michael Hanselmann
  ("high", constants.OP_PRIO_HIGH),
253 84a5b33c Michael Hanselmann
  ]
254 84a5b33c Michael Hanselmann
255 84a5b33c Michael Hanselmann
#: Priority dictionary for easier lookup
256 84a5b33c Michael Hanselmann
# TODO: Replace this and _PRIORITY_NAMES with a single sorted dictionary once
257 84a5b33c Michael Hanselmann
# we migrate to Python 2.6
258 84a5b33c Michael Hanselmann
_PRIONAME_TO_VALUE = dict(_PRIORITY_NAMES)
259 84a5b33c Michael Hanselmann
260 ee3aedff Michael Hanselmann
# Query result status for clients
261 ee3aedff Michael Hanselmann
(QR_NORMAL,
262 ee3aedff Michael Hanselmann
 QR_UNKNOWN,
263 ee3aedff Michael Hanselmann
 QR_INCOMPLETE) = range(3)
264 ee3aedff Michael Hanselmann
265 11705e3d Iustin Pop
#: Maximum batch size for ChooseJob
266 11705e3d Iustin Pop
_CHOOSE_BATCH = 25
267 11705e3d Iustin Pop
268 03298ebe Michael Hanselmann
269 863d7f46 Michael Hanselmann
class _Argument:
270 b459a848 Andrea Spadaccini
  def __init__(self, min=0, max=None): # pylint: disable=W0622
271 863d7f46 Michael Hanselmann
    self.min = min
272 863d7f46 Michael Hanselmann
    self.max = max
273 863d7f46 Michael Hanselmann
274 863d7f46 Michael Hanselmann
  def __repr__(self):
275 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s>" %
276 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max))
277 863d7f46 Michael Hanselmann
278 863d7f46 Michael Hanselmann
279 863d7f46 Michael Hanselmann
class ArgSuggest(_Argument):
280 863d7f46 Michael Hanselmann
  """Suggesting argument.
281 863d7f46 Michael Hanselmann

282 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor.
283 863d7f46 Michael Hanselmann

284 863d7f46 Michael Hanselmann
  """
285 b459a848 Andrea Spadaccini
  # pylint: disable=W0622
286 863d7f46 Michael Hanselmann
  def __init__(self, min=0, max=None, choices=None):
287 863d7f46 Michael Hanselmann
    _Argument.__init__(self, min=min, max=max)
288 863d7f46 Michael Hanselmann
    self.choices = choices
289 863d7f46 Michael Hanselmann
290 863d7f46 Michael Hanselmann
  def __repr__(self):
291 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s choices=%r>" %
292 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max, self.choices))
293 863d7f46 Michael Hanselmann
294 863d7f46 Michael Hanselmann
295 863d7f46 Michael Hanselmann
class ArgChoice(ArgSuggest):
296 863d7f46 Michael Hanselmann
  """Choice argument.
297 863d7f46 Michael Hanselmann

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

301 863d7f46 Michael Hanselmann
  """
302 863d7f46 Michael Hanselmann
303 863d7f46 Michael Hanselmann
304 863d7f46 Michael Hanselmann
class ArgUnknown(_Argument):
305 863d7f46 Michael Hanselmann
  """Unknown argument to program (e.g. determined at runtime).
306 863d7f46 Michael Hanselmann

307 863d7f46 Michael Hanselmann
  """
308 863d7f46 Michael Hanselmann
309 863d7f46 Michael Hanselmann
310 863d7f46 Michael Hanselmann
class ArgInstance(_Argument):
311 863d7f46 Michael Hanselmann
  """Instances argument.
312 863d7f46 Michael Hanselmann

313 863d7f46 Michael Hanselmann
  """
314 863d7f46 Michael Hanselmann
315 863d7f46 Michael Hanselmann
316 863d7f46 Michael Hanselmann
class ArgNode(_Argument):
317 863d7f46 Michael Hanselmann
  """Node argument.
318 863d7f46 Michael Hanselmann

319 863d7f46 Michael Hanselmann
  """
320 863d7f46 Michael Hanselmann
321 667dbd6b Adeodato Simo
322 667dbd6b Adeodato Simo
class ArgGroup(_Argument):
323 667dbd6b Adeodato Simo
  """Node group argument.
324 667dbd6b Adeodato Simo

325 667dbd6b Adeodato Simo
  """
326 667dbd6b Adeodato Simo
327 667dbd6b Adeodato Simo
328 863d7f46 Michael Hanselmann
class ArgJobId(_Argument):
329 863d7f46 Michael Hanselmann
  """Job ID argument.
330 863d7f46 Michael Hanselmann

331 863d7f46 Michael Hanselmann
  """
332 863d7f46 Michael Hanselmann
333 863d7f46 Michael Hanselmann
334 863d7f46 Michael Hanselmann
class ArgFile(_Argument):
335 863d7f46 Michael Hanselmann
  """File path argument.
336 863d7f46 Michael Hanselmann

337 863d7f46 Michael Hanselmann
  """
338 863d7f46 Michael Hanselmann
339 863d7f46 Michael Hanselmann
340 863d7f46 Michael Hanselmann
class ArgCommand(_Argument):
341 863d7f46 Michael Hanselmann
  """Command argument.
342 863d7f46 Michael Hanselmann

343 863d7f46 Michael Hanselmann
  """
344 863d7f46 Michael Hanselmann
345 863d7f46 Michael Hanselmann
346 83ec7961 Michael Hanselmann
class ArgHost(_Argument):
347 83ec7961 Michael Hanselmann
  """Host argument.
348 83ec7961 Michael Hanselmann

349 83ec7961 Michael Hanselmann
  """
350 83ec7961 Michael Hanselmann
351 83ec7961 Michael Hanselmann
352 f9faf9c3 René Nussbaumer
class ArgOs(_Argument):
353 f9faf9c3 René Nussbaumer
  """OS argument.
354 f9faf9c3 René Nussbaumer

355 f9faf9c3 René Nussbaumer
  """
356 f9faf9c3 René Nussbaumer
357 f9faf9c3 René Nussbaumer
358 4a265c08 Michael Hanselmann
ARGS_NONE = []
359 4a265c08 Michael Hanselmann
ARGS_MANY_INSTANCES = [ArgInstance()]
360 4a265c08 Michael Hanselmann
ARGS_MANY_NODES = [ArgNode()]
361 667dbd6b Adeodato Simo
ARGS_MANY_GROUPS = [ArgGroup()]
362 4a265c08 Michael Hanselmann
ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
363 4a265c08 Michael Hanselmann
ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
364 dadf6b7d Michael Hanselmann
# TODO
365 dadf6b7d Michael Hanselmann
ARGS_ONE_GROUP = [ArgGroup(min=1, max=1)]
366 f9faf9c3 René Nussbaumer
ARGS_ONE_OS = [ArgOs(min=1, max=1)]
367 4a265c08 Michael Hanselmann
368 4a265c08 Michael Hanselmann
369 846baef9 Iustin Pop
def _ExtractTagsObject(opts, args):
370 846baef9 Iustin Pop
  """Extract the tag type object.
371 846baef9 Iustin Pop

372 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
373 846baef9 Iustin Pop

374 846baef9 Iustin Pop
  """
375 846baef9 Iustin Pop
  if not hasattr(opts, "tag_type"):
376 846baef9 Iustin Pop
    raise errors.ProgrammerError("tag_type not passed to _ExtractTagsObject")
377 846baef9 Iustin Pop
  kind = opts.tag_type
378 846baef9 Iustin Pop
  if kind == constants.TAG_CLUSTER:
379 846baef9 Iustin Pop
    retval = kind, kind
380 819cbfe5 Michael Hanselmann
  elif kind in (constants.TAG_NODEGROUP,
381 819cbfe5 Michael Hanselmann
                constants.TAG_NODE,
382 819cbfe5 Michael Hanselmann
                constants.TAG_INSTANCE):
383 846baef9 Iustin Pop
    if not args:
384 0c434948 Iustin Pop
      raise errors.OpPrereqError("no arguments passed to the command")
385 846baef9 Iustin Pop
    name = args.pop(0)
386 846baef9 Iustin Pop
    retval = kind, name
387 846baef9 Iustin Pop
  else:
388 846baef9 Iustin Pop
    raise errors.ProgrammerError("Unhandled tag type '%s'" % kind)
389 846baef9 Iustin Pop
  return retval
390 846baef9 Iustin Pop
391 846baef9 Iustin Pop
392 810c50b7 Iustin Pop
def _ExtendTags(opts, args):
393 810c50b7 Iustin Pop
  """Extend the args if a source file has been given.
394 810c50b7 Iustin Pop

395 810c50b7 Iustin Pop
  This function will extend the tags with the contents of the file
396 810c50b7 Iustin Pop
  passed in the 'tags_source' attribute of the opts parameter. A file
397 810c50b7 Iustin Pop
  named '-' will be replaced by stdin.
398 810c50b7 Iustin Pop

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

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

429 846baef9 Iustin Pop
  """
430 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
431 7699c3af Iustin Pop
  cl = GetClient()
432 7699c3af Iustin Pop
  result = cl.QueryTags(kind, name)
433 846baef9 Iustin Pop
  result = list(result)
434 846baef9 Iustin Pop
  result.sort()
435 846baef9 Iustin Pop
  for tag in result:
436 03298ebe Michael Hanselmann
    ToStdout(tag)
437 846baef9 Iustin Pop
438 846baef9 Iustin Pop
439 846baef9 Iustin Pop
def AddTags(opts, args):
440 846baef9 Iustin Pop
  """Add tags on a given object.
441 846baef9 Iustin Pop

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

447 846baef9 Iustin Pop
  """
448 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
449 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
450 846baef9 Iustin Pop
  if not args:
451 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be added")
452 d1602edc Iustin Pop
  op = opcodes.OpTagsSet(kind=kind, name=name, tags=args)
453 af1a81d1 Michael Hanselmann
  SubmitOpCode(op, opts=opts)
454 846baef9 Iustin Pop
455 846baef9 Iustin Pop
456 846baef9 Iustin Pop
def RemoveTags(opts, args):
457 846baef9 Iustin Pop
  """Remove tags from a given object.
458 846baef9 Iustin Pop

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

464 846baef9 Iustin Pop
  """
465 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
466 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
467 846baef9 Iustin Pop
  if not args:
468 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be removed")
469 3f0ab95f Iustin Pop
  op = opcodes.OpTagsDel(kind=kind, name=name, tags=args)
470 af1a81d1 Michael Hanselmann
  SubmitOpCode(op, opts=opts)
471 846baef9 Iustin Pop
472 a8083063 Iustin Pop
473 b459a848 Andrea Spadaccini
def check_unit(option, opt, value): # pylint: disable=W0613
474 65fe4693 Iustin Pop
  """OptParsers custom converter for units.
475 65fe4693 Iustin Pop

476 65fe4693 Iustin Pop
  """
477 a8083063 Iustin Pop
  try:
478 a8083063 Iustin Pop
    return utils.ParseUnit(value)
479 a8083063 Iustin Pop
  except errors.UnitParseError, err:
480 3ecf6786 Iustin Pop
    raise OptionValueError("option %s: %s" % (opt, err))
481 a8083063 Iustin Pop
482 a8083063 Iustin Pop
483 a8469393 Iustin Pop
def _SplitKeyVal(opt, data):
484 a8469393 Iustin Pop
  """Convert a KeyVal string into a dict.
485 a8469393 Iustin Pop

486 a8469393 Iustin Pop
  This function will convert a key=val[,...] string into a dict. Empty
487 a8469393 Iustin Pop
  values will be converted specially: keys which have the prefix 'no_'
488 a8469393 Iustin Pop
  will have the value=False and the prefix stripped, the others will
489 a8469393 Iustin Pop
  have value=True.
490 a8469393 Iustin Pop

491 a8469393 Iustin Pop
  @type opt: string
492 a8469393 Iustin Pop
  @param opt: a string holding the option name for which we process the
493 a8469393 Iustin Pop
      data, used in building error messages
494 a8469393 Iustin Pop
  @type data: string
495 a8469393 Iustin Pop
  @param data: a string of the format key=val,key=val,...
496 a8469393 Iustin Pop
  @rtype: dict
497 a8469393 Iustin Pop
  @return: {key=val, key=val}
498 a8469393 Iustin Pop
  @raises errors.ParameterError: if there are duplicate keys
499 a8469393 Iustin Pop

500 a8469393 Iustin Pop
  """
501 a8469393 Iustin Pop
  kv_dict = {}
502 4f31882e Guido Trotter
  if data:
503 1b3a7656 Iustin Pop
    for elem in utils.UnescapeAndSplit(data, sep=","):
504 4f31882e Guido Trotter
      if "=" in elem:
505 4f31882e Guido Trotter
        key, val = elem.split("=", 1)
506 a8469393 Iustin Pop
      else:
507 4f31882e Guido Trotter
        if elem.startswith(NO_PREFIX):
508 4f31882e Guido Trotter
          key, val = elem[len(NO_PREFIX):], False
509 4f31882e Guido Trotter
        elif elem.startswith(UN_PREFIX):
510 4f31882e Guido Trotter
          key, val = elem[len(UN_PREFIX):], None
511 4f31882e Guido Trotter
        else:
512 4f31882e Guido Trotter
          key, val = elem, True
513 4f31882e Guido Trotter
      if key in kv_dict:
514 4f31882e Guido Trotter
        raise errors.ParameterError("Duplicate key '%s' in option %s" %
515 4f31882e Guido Trotter
                                    (key, opt))
516 4f31882e Guido Trotter
      kv_dict[key] = val
517 a8469393 Iustin Pop
  return kv_dict
518 a8469393 Iustin Pop
519 a8469393 Iustin Pop
520 b459a848 Andrea Spadaccini
def check_ident_key_val(option, opt, value):  # pylint: disable=W0613
521 552c8dff Michael Hanselmann
  """Custom parser for ident:key=val,key=val options.
522 552c8dff Michael Hanselmann

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

526 a8469393 Iustin Pop
  """
527 a8469393 Iustin Pop
  if ":" not in value:
528 d0c8c01d Iustin Pop
    ident, rest = value, ""
529 a8469393 Iustin Pop
  else:
530 a8469393 Iustin Pop
    ident, rest = value.split(":", 1)
531 8b46606c Guido Trotter
532 8b46606c Guido Trotter
  if ident.startswith(NO_PREFIX):
533 8b46606c Guido Trotter
    if rest:
534 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
535 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
536 8b46606c Guido Trotter
    retval = (ident[len(NO_PREFIX):], False)
537 8b46606c Guido Trotter
  elif ident.startswith(UN_PREFIX):
538 8b46606c Guido Trotter
    if rest:
539 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
540 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
541 8b46606c Guido Trotter
    retval = (ident[len(UN_PREFIX):], None)
542 8b46606c Guido Trotter
  else:
543 a8469393 Iustin Pop
    kv_dict = _SplitKeyVal(opt, rest)
544 a8469393 Iustin Pop
    retval = (ident, kv_dict)
545 a8469393 Iustin Pop
  return retval
546 a8469393 Iustin Pop
547 a8469393 Iustin Pop
548 b459a848 Andrea Spadaccini
def check_key_val(option, opt, value):  # pylint: disable=W0613
549 552c8dff Michael Hanselmann
  """Custom parser class for key=val,key=val options.
550 552c8dff Michael Hanselmann

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

553 a8469393 Iustin Pop
  """
554 a8469393 Iustin Pop
  return _SplitKeyVal(opt, value)
555 a8469393 Iustin Pop
556 a8469393 Iustin Pop
557 b459a848 Andrea Spadaccini
def check_bool(option, opt, value): # pylint: disable=W0613
558 e7b61bb0 Iustin Pop
  """Custom parser for yes/no options.
559 e7b61bb0 Iustin Pop

560 e7b61bb0 Iustin Pop
  This will store the parsed value as either True or False.
561 e7b61bb0 Iustin Pop

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

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

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

1306 c41eea6e Iustin Pop
  @param argv: the command line
1307 c41eea6e Iustin Pop
  @param commands: dictionary with special contents, see the design
1308 c41eea6e Iustin Pop
      doc for cmdline handling
1309 c41eea6e Iustin Pop
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
1310 098c0958 Michael Hanselmann

1311 a8083063 Iustin Pop
  """
1312 a8083063 Iustin Pop
  if len(argv) == 0:
1313 a8083063 Iustin Pop
    binary = "<command>"
1314 a8083063 Iustin Pop
  else:
1315 a8083063 Iustin Pop
    binary = argv[0].split("/")[-1]
1316 a8083063 Iustin Pop
1317 a8083063 Iustin Pop
  if len(argv) > 1 and argv[1] == "--version":
1318 84a12e40 Iustin Pop
    ToStdout("%s (ganeti %s) %s", binary, constants.VCS_VERSION,
1319 84a12e40 Iustin Pop
             constants.RELEASE_VERSION)
1320 a8083063 Iustin Pop
    # Quit right away. That way we don't have to care about this special
1321 a8083063 Iustin Pop
    # argument. optparse.py does it the same.
1322 a8083063 Iustin Pop
    sys.exit(0)
1323 a8083063 Iustin Pop
1324 de47cf8f Guido Trotter
  if len(argv) < 2 or not (argv[1] in commands or
1325 70a35b6f Guido Trotter
                           argv[1] in aliases):
1326 a8083063 Iustin Pop
    # let's do a nice thing
1327 a8083063 Iustin Pop
    sortedcmds = commands.keys()
1328 a8083063 Iustin Pop
    sortedcmds.sort()
1329 03298ebe Michael Hanselmann
1330 03298ebe Michael Hanselmann
    ToStdout("Usage: %s {command} [options...] [argument...]", binary)
1331 03298ebe Michael Hanselmann
    ToStdout("%s <command> --help to see details, or man %s", binary, binary)
1332 03298ebe Michael Hanselmann
    ToStdout("")
1333 03298ebe Michael Hanselmann
1334 a8083063 Iustin Pop
    # compute the max line length for cmd + usage
1335 4e713df6 Iustin Pop
    mlen = max([len(" %s" % cmd) for cmd in commands])
1336 a8083063 Iustin Pop
    mlen = min(60, mlen) # should not get here...
1337 03298ebe Michael Hanselmann
1338 a8083063 Iustin Pop
    # and format a nice command list
1339 03298ebe Michael Hanselmann
    ToStdout("Commands:")
1340 a8083063 Iustin Pop
    for cmd in sortedcmds:
1341 4e713df6 Iustin Pop
      cmdstr = " %s" % (cmd,)
1342 9a033156 Iustin Pop
      help_text = commands[cmd][4]
1343 03298ebe Michael Hanselmann
      help_lines = textwrap.wrap(help_text, 79 - 3 - mlen)
1344 03298ebe Michael Hanselmann
      ToStdout("%-*s - %s", mlen, cmdstr, help_lines.pop(0))
1345 a8083063 Iustin Pop
      for line in help_lines:
1346 03298ebe Michael Hanselmann
        ToStdout("%-*s   %s", mlen, "", line)
1347 03298ebe Michael Hanselmann
1348 03298ebe Michael Hanselmann
    ToStdout("")
1349 03298ebe Michael Hanselmann
1350 a8083063 Iustin Pop
    return None, None, None
1351 de47cf8f Guido Trotter
1352 de47cf8f Guido Trotter
  # get command, unalias it, and look it up in commands
1353 a8083063 Iustin Pop
  cmd = argv.pop(1)
1354 de47cf8f Guido Trotter
  if cmd in aliases:
1355 de47cf8f Guido Trotter
    if cmd in commands:
1356 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' overrides an existing"
1357 de47cf8f Guido Trotter
                                   " command" % cmd)
1358 de47cf8f Guido Trotter
1359 de47cf8f Guido Trotter
    if aliases[cmd] not in commands:
1360 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' maps to non-existing"
1361 de47cf8f Guido Trotter
                                   " command '%s'" % (cmd, aliases[cmd]))
1362 de47cf8f Guido Trotter
1363 de47cf8f Guido Trotter
    cmd = aliases[cmd]
1364 de47cf8f Guido Trotter
1365 a8005e17 Michael Hanselmann
  func, args_def, parser_opts, usage, description = commands[cmd]
1366 5786c087 Michael Hanselmann
  parser = OptionParser(option_list=parser_opts + COMMON_OPTS,
1367 a8083063 Iustin Pop
                        description=description,
1368 a8083063 Iustin Pop
                        formatter=TitledHelpFormatter(),
1369 a8083063 Iustin Pop
                        usage="%%prog %s %s" % (cmd, usage))
1370 a8083063 Iustin Pop
  parser.disable_interspersed_args()
1371 a8083063 Iustin Pop
  options, args = parser.parse_args()
1372 a8005e17 Michael Hanselmann
1373 a8005e17 Michael Hanselmann
  if not _CheckArguments(cmd, args_def, args):
1374 a8083063 Iustin Pop
    return None, None, None
1375 a8083063 Iustin Pop
1376 a8083063 Iustin Pop
  return func, options, args
1377 a8083063 Iustin Pop
1378 a8083063 Iustin Pop
1379 a8005e17 Michael Hanselmann
def _CheckArguments(cmd, args_def, args):
1380 a8005e17 Michael Hanselmann
  """Verifies the arguments using the argument definition.
1381 a8005e17 Michael Hanselmann

1382 a8005e17 Michael Hanselmann
  Algorithm:
1383 a8005e17 Michael Hanselmann

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

1386 a8005e17 Michael Hanselmann
    1. For each argument in definition
1387 a8005e17 Michael Hanselmann

1388 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
1389 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
1390 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
1391 a8005e17 Michael Hanselmann

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

1394 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
1395 a8005e17 Michael Hanselmann

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

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

1400 a8005e17 Michael Hanselmann
  """
1401 a8005e17 Michael Hanselmann
  if args and not args_def:
1402 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects no arguments", cmd)
1403 a8005e17 Michael Hanselmann
    return False
1404 a8005e17 Michael Hanselmann
1405 a8005e17 Michael Hanselmann
  min_count = None
1406 a8005e17 Michael Hanselmann
  max_count = None
1407 a8005e17 Michael Hanselmann
  check_max = None
1408 a8005e17 Michael Hanselmann
1409 a8005e17 Michael Hanselmann
  last_idx = len(args_def) - 1
1410 a8005e17 Michael Hanselmann
1411 a8005e17 Michael Hanselmann
  for idx, arg in enumerate(args_def):
1412 a8005e17 Michael Hanselmann
    if min_count is None:
1413 a8005e17 Michael Hanselmann
      min_count = arg.min
1414 a8005e17 Michael Hanselmann
    elif arg.min is not None:
1415 a8005e17 Michael Hanselmann
      min_count += arg.min
1416 a8005e17 Michael Hanselmann
1417 a8005e17 Michael Hanselmann
    if max_count is None:
1418 a8005e17 Michael Hanselmann
      max_count = arg.max
1419 a8005e17 Michael Hanselmann
    elif arg.max is not None:
1420 a8005e17 Michael Hanselmann
      max_count += arg.max
1421 a8005e17 Michael Hanselmann
1422 a8005e17 Michael Hanselmann
    if idx == last_idx:
1423 a8005e17 Michael Hanselmann
      check_max = (arg.max is not None)
1424 a8005e17 Michael Hanselmann
1425 a8005e17 Michael Hanselmann
    elif arg.max is None:
1426 a8005e17 Michael Hanselmann
      raise errors.ProgrammerError("Only the last argument can have max=None")
1427 a8005e17 Michael Hanselmann
1428 a8005e17 Michael Hanselmann
  if check_max:
1429 a8005e17 Michael Hanselmann
    # Command with exact number of arguments
1430 a8005e17 Michael Hanselmann
    if (min_count is not None and max_count is not None and
1431 a8005e17 Michael Hanselmann
        min_count == max_count and len(args) != min_count):
1432 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects %d argument(s)", cmd, min_count)
1433 a8005e17 Michael Hanselmann
      return False
1434 a8005e17 Michael Hanselmann
1435 a8005e17 Michael Hanselmann
    # Command with limited number of arguments
1436 a8005e17 Michael Hanselmann
    if max_count is not None and len(args) > max_count:
1437 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects only %d argument(s)",
1438 a8005e17 Michael Hanselmann
               cmd, max_count)
1439 a8005e17 Michael Hanselmann
      return False
1440 a8005e17 Michael Hanselmann
1441 a8005e17 Michael Hanselmann
  # Command with some required arguments
1442 a8005e17 Michael Hanselmann
  if min_count is not None and len(args) < min_count:
1443 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects at least %d argument(s)",
1444 a8005e17 Michael Hanselmann
             cmd, min_count)
1445 a8005e17 Michael Hanselmann
    return False
1446 a8005e17 Michael Hanselmann
1447 a8005e17 Michael Hanselmann
  return True
1448 a8005e17 Michael Hanselmann
1449 a8005e17 Michael Hanselmann
1450 60d49723 Michael Hanselmann
def SplitNodeOption(value):
1451 60d49723 Michael Hanselmann
  """Splits the value of a --node option.
1452 60d49723 Michael Hanselmann

1453 60d49723 Michael Hanselmann
  """
1454 d0c8c01d Iustin Pop
  if value and ":" in value:
1455 d0c8c01d Iustin Pop
    return value.split(":", 1)
1456 60d49723 Michael Hanselmann
  else:
1457 60d49723 Michael Hanselmann
    return (value, None)
1458 60d49723 Michael Hanselmann
1459 60d49723 Michael Hanselmann
1460 07150497 Guido Trotter
def CalculateOSNames(os_name, os_variants):
1461 07150497 Guido Trotter
  """Calculates all the names an OS can be called, according to its variants.
1462 07150497 Guido Trotter

1463 07150497 Guido Trotter
  @type os_name: string
1464 07150497 Guido Trotter
  @param os_name: base name of the os
1465 07150497 Guido Trotter
  @type os_variants: list or None
1466 07150497 Guido Trotter
  @param os_variants: list of supported variants
1467 07150497 Guido Trotter
  @rtype: list
1468 07150497 Guido Trotter
  @return: list of valid names
1469 07150497 Guido Trotter

1470 07150497 Guido Trotter
  """
1471 07150497 Guido Trotter
  if os_variants:
1472 d0c8c01d Iustin Pop
    return ["%s+%s" % (os_name, v) for v in os_variants]
1473 07150497 Guido Trotter
  else:
1474 07150497 Guido Trotter
    return [os_name]
1475 07150497 Guido Trotter
1476 07150497 Guido Trotter
1477 a4ebd726 Michael Hanselmann
def ParseFields(selected, default):
1478 a4ebd726 Michael Hanselmann
  """Parses the values of "--field"-like options.
1479 a4ebd726 Michael Hanselmann

1480 a4ebd726 Michael Hanselmann
  @type selected: string or None
1481 a4ebd726 Michael Hanselmann
  @param selected: User-selected options
1482 a4ebd726 Michael Hanselmann
  @type default: list
1483 a4ebd726 Michael Hanselmann
  @param default: Default fields
1484 a4ebd726 Michael Hanselmann

1485 a4ebd726 Michael Hanselmann
  """
1486 a4ebd726 Michael Hanselmann
  if selected is None:
1487 a4ebd726 Michael Hanselmann
    return default
1488 a4ebd726 Michael Hanselmann
1489 a4ebd726 Michael Hanselmann
  if selected.startswith("+"):
1490 a4ebd726 Michael Hanselmann
    return default + selected[1:].split(",")
1491 a4ebd726 Michael Hanselmann
1492 a4ebd726 Michael Hanselmann
  return selected.split(",")
1493 a4ebd726 Michael Hanselmann
1494 a4ebd726 Michael Hanselmann
1495 e0e916fe Iustin Pop
UsesRPC = rpc.RunWithRPC
1496 4331f6cd Michael Hanselmann
1497 4331f6cd Michael Hanselmann
1498 47988778 Iustin Pop
def AskUser(text, choices=None):
1499 47988778 Iustin Pop
  """Ask the user a question.
1500 a8083063 Iustin Pop

1501 c41eea6e Iustin Pop
  @param text: the question to ask
1502 a8083063 Iustin Pop

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

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

1512 a8083063 Iustin Pop
  """
1513 47988778 Iustin Pop
  if choices is None:
1514 d0c8c01d Iustin Pop
    choices = [("y", True, "Perform the operation"),
1515 d0c8c01d Iustin Pop
               ("n", False, "Do not perform the operation")]
1516 47988778 Iustin Pop
  if not choices or not isinstance(choices, list):
1517 5bbd3f7f Michael Hanselmann
    raise errors.ProgrammerError("Invalid choices argument to AskUser")
1518 47988778 Iustin Pop
  for entry in choices:
1519 d0c8c01d Iustin Pop
    if not isinstance(entry, tuple) or len(entry) < 3 or entry[0] == "?":
1520 5bbd3f7f Michael Hanselmann
      raise errors.ProgrammerError("Invalid choices element to AskUser")
1521 47988778 Iustin Pop
1522 47988778 Iustin Pop
  answer = choices[-1][1]
1523 47988778 Iustin Pop
  new_text = []
1524 47988778 Iustin Pop
  for line in text.splitlines():
1525 47988778 Iustin Pop
    new_text.append(textwrap.fill(line, 70, replace_whitespace=False))
1526 47988778 Iustin Pop
  text = "\n".join(new_text)
1527 a8083063 Iustin Pop
  try:
1528 3023170f Iustin Pop
    f = file("/dev/tty", "a+")
1529 a8083063 Iustin Pop
  except IOError:
1530 47988778 Iustin Pop
    return answer
1531 a8083063 Iustin Pop
  try:
1532 47988778 Iustin Pop
    chars = [entry[0] for entry in choices]
1533 47988778 Iustin Pop
    chars[-1] = "[%s]" % chars[-1]
1534 d0c8c01d Iustin Pop
    chars.append("?")
1535 47988778 Iustin Pop
    maps = dict([(entry[0], entry[1]) for entry in choices])
1536 47988778 Iustin Pop
    while True:
1537 47988778 Iustin Pop
      f.write(text)
1538 d0c8c01d Iustin Pop
      f.write("\n")
1539 47988778 Iustin Pop
      f.write("/".join(chars))
1540 47988778 Iustin Pop
      f.write(": ")
1541 47988778 Iustin Pop
      line = f.readline(2).strip().lower()
1542 47988778 Iustin Pop
      if line in maps:
1543 47988778 Iustin Pop
        answer = maps[line]
1544 47988778 Iustin Pop
        break
1545 d0c8c01d Iustin Pop
      elif line == "?":
1546 47988778 Iustin Pop
        for entry in choices:
1547 47988778 Iustin Pop
          f.write(" %s - %s\n" % (entry[0], entry[2]))
1548 47988778 Iustin Pop
        f.write("\n")
1549 47988778 Iustin Pop
        continue
1550 a8083063 Iustin Pop
  finally:
1551 a8083063 Iustin Pop
    f.close()
1552 a8083063 Iustin Pop
  return answer
1553 a8083063 Iustin Pop
1554 a8083063 Iustin Pop
1555 e9d741b6 Iustin Pop
class JobSubmittedException(Exception):
1556 e9d741b6 Iustin Pop
  """Job was submitted, client should exit.
1557 e9d741b6 Iustin Pop

1558 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1559 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1560 e9d741b6 Iustin Pop

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

1563 e9d741b6 Iustin Pop
  """
1564 e9d741b6 Iustin Pop
1565 e9d741b6 Iustin Pop
1566 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1567 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1568 a8083063 Iustin Pop

1569 0a1e74d9 Iustin Pop
  @type ops: list
1570 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1571 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1572 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1573 0a1e74d9 Iustin Pop
             if None, a new client will be created
1574 a8083063 Iustin Pop

1575 a8083063 Iustin Pop
  """
1576 e2212007 Iustin Pop
  if cl is None:
1577 b33e986b Iustin Pop
    cl = GetClient()
1578 685ee993 Iustin Pop
1579 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1580 0a1e74d9 Iustin Pop
1581 0a1e74d9 Iustin Pop
  return job_id
1582 0a1e74d9 Iustin Pop
1583 0a1e74d9 Iustin Pop
1584 4e338533 Michael Hanselmann
def GenericPollJob(job_id, cbs, report_cbs):
1585 4e338533 Michael Hanselmann
  """Generic job-polling function.
1586 0a1e74d9 Iustin Pop

1587 4e338533 Michael Hanselmann
  @type job_id: number
1588 4e338533 Michael Hanselmann
  @param job_id: Job ID
1589 4e338533 Michael Hanselmann
  @type cbs: Instance of L{JobPollCbBase}
1590 4e338533 Michael Hanselmann
  @param cbs: Data callbacks
1591 4e338533 Michael Hanselmann
  @type report_cbs: Instance of L{JobPollReportCbBase}
1592 4e338533 Michael Hanselmann
  @param report_cbs: Reporting callbacks
1593 0a1e74d9 Iustin Pop

1594 0a1e74d9 Iustin Pop
  """
1595 6c5a7090 Michael Hanselmann
  prev_job_info = None
1596 6c5a7090 Michael Hanselmann
  prev_logmsg_serial = None
1597 6c5a7090 Michael Hanselmann
1598 f4484122 Michael Hanselmann
  status = None
1599 f4484122 Michael Hanselmann
1600 685ee993 Iustin Pop
  while True:
1601 4e338533 Michael Hanselmann
    result = cbs.WaitForJobChangeOnce(job_id, ["status"], prev_job_info,
1602 4e338533 Michael Hanselmann
                                      prev_logmsg_serial)
1603 6c5a7090 Michael Hanselmann
    if not result:
1604 685ee993 Iustin Pop
      # job not found, go away!
1605 0bbe448c Michael Hanselmann
      raise errors.JobLost("Job with id %s lost" % job_id)
1606 4e338533 Michael Hanselmann
1607 4e338533 Michael Hanselmann
    if result == constants.JOB_NOTCHANGED:
1608 4e338533 Michael Hanselmann
      report_cbs.ReportNotChanged(job_id, status)
1609 f4484122 Michael Hanselmann
1610 f4484122 Michael Hanselmann
      # Wait again
1611 f4484122 Michael Hanselmann
      continue
1612 685ee993 Iustin Pop
1613 6c5a7090 Michael Hanselmann
    # Split result, a tuple of (field values, log entries)
1614 6c5a7090 Michael Hanselmann
    (job_info, log_entries) = result
1615 6c5a7090 Michael Hanselmann
    (status, ) = job_info
1616 6c5a7090 Michael Hanselmann
1617 6c5a7090 Michael Hanselmann
    if log_entries:
1618 6c5a7090 Michael Hanselmann
      for log_entry in log_entries:
1619 4e338533 Michael Hanselmann
        (serial, timestamp, log_type, message) = log_entry
1620 4e338533 Michael Hanselmann
        report_cbs.ReportLogMessage(job_id, serial, timestamp,
1621 4e338533 Michael Hanselmann
                                    log_type, message)
1622 6c5a7090 Michael Hanselmann
        prev_logmsg_serial = max(prev_logmsg_serial, serial)
1623 6c5a7090 Michael Hanselmann
1624 0bbe448c Michael Hanselmann
    # TODO: Handle canceled and archived jobs
1625 fbf0262f Michael Hanselmann
    elif status in (constants.JOB_STATUS_SUCCESS,
1626 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_ERROR,
1627 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELING,
1628 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELED):
1629 685ee993 Iustin Pop
      break
1630 6c5a7090 Michael Hanselmann
1631 6c5a7090 Michael Hanselmann
    prev_job_info = job_info
1632 685ee993 Iustin Pop
1633 4e338533 Michael Hanselmann
  jobs = cbs.QueryJobs([job_id], ["status", "opstatus", "opresult"])
1634 0bbe448c Michael Hanselmann
  if not jobs:
1635 0bbe448c Michael Hanselmann
    raise errors.JobLost("Job with id %s lost" % job_id)
1636 685ee993 Iustin Pop
1637 0e050889 Iustin Pop
  status, opstatus, result = jobs[0]
1638 4e338533 Michael Hanselmann
1639 0bbe448c Michael Hanselmann
  if status == constants.JOB_STATUS_SUCCESS:
1640 53c04d04 Iustin Pop
    return result
1641 4e338533 Michael Hanselmann
1642 4e338533 Michael Hanselmann
  if status in (constants.JOB_STATUS_CANCELING, constants.JOB_STATUS_CANCELED):
1643 fbf0262f Michael Hanselmann
    raise errors.OpExecError("Job was canceled")
1644 4e338533 Michael Hanselmann
1645 4e338533 Michael Hanselmann
  has_ok = False
1646 4e338533 Michael Hanselmann
  for idx, (status, msg) in enumerate(zip(opstatus, result)):
1647 4e338533 Michael Hanselmann
    if status == constants.OP_STATUS_SUCCESS:
1648 4e338533 Michael Hanselmann
      has_ok = True
1649 4e338533 Michael Hanselmann
    elif status == constants.OP_STATUS_ERROR:
1650 4e338533 Michael Hanselmann
      errors.MaybeRaise(msg)
1651 4e338533 Michael Hanselmann
1652 4e338533 Michael Hanselmann
      if has_ok:
1653 4e338533 Michael Hanselmann
        raise errors.OpExecError("partial failure (opcode %d): %s" %
1654 4e338533 Michael Hanselmann
                                 (idx, msg))
1655 4e338533 Michael Hanselmann
1656 4e338533 Michael Hanselmann
      raise errors.OpExecError(str(msg))
1657 4e338533 Michael Hanselmann
1658 4e338533 Michael Hanselmann
  # default failure mode
1659 4e338533 Michael Hanselmann
  raise errors.OpExecError(result)
1660 4e338533 Michael Hanselmann
1661 4e338533 Michael Hanselmann
1662 4e338533 Michael Hanselmann
class JobPollCbBase:
1663 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} callbacks.
1664 4e338533 Michael Hanselmann

1665 4e338533 Michael Hanselmann
  """
1666 4e338533 Michael Hanselmann
  def __init__(self):
1667 4e338533 Michael Hanselmann
    """Initializes this class.
1668 4e338533 Michael Hanselmann

1669 4e338533 Michael Hanselmann
    """
1670 4e338533 Michael Hanselmann
1671 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1672 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1673 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1674 4e338533 Michael Hanselmann

1675 4e338533 Michael Hanselmann
    """
1676 4e338533 Michael Hanselmann
    raise NotImplementedError()
1677 4e338533 Michael Hanselmann
1678 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1679 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1680 4e338533 Michael Hanselmann

1681 4e338533 Michael Hanselmann
    @type job_ids: list of numbers
1682 4e338533 Michael Hanselmann
    @param job_ids: Job IDs
1683 4e338533 Michael Hanselmann
    @type fields: list of strings
1684 4e338533 Michael Hanselmann
    @param fields: Fields
1685 4e338533 Michael Hanselmann

1686 4e338533 Michael Hanselmann
    """
1687 4e338533 Michael Hanselmann
    raise NotImplementedError()
1688 4e338533 Michael Hanselmann
1689 4e338533 Michael Hanselmann
1690 4e338533 Michael Hanselmann
class JobPollReportCbBase:
1691 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} reporting callbacks.
1692 4e338533 Michael Hanselmann

1693 4e338533 Michael Hanselmann
  """
1694 4e338533 Michael Hanselmann
  def __init__(self):
1695 4e338533 Michael Hanselmann
    """Initializes this class.
1696 4e338533 Michael Hanselmann

1697 4e338533 Michael Hanselmann
    """
1698 4e338533 Michael Hanselmann
1699 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1700 4e338533 Michael Hanselmann
    """Handles a log message.
1701 4e338533 Michael Hanselmann

1702 4e338533 Michael Hanselmann
    """
1703 4e338533 Michael Hanselmann
    raise NotImplementedError()
1704 4e338533 Michael Hanselmann
1705 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1706 4e338533 Michael Hanselmann
    """Called for if a job hasn't changed in a while.
1707 4e338533 Michael Hanselmann

1708 4e338533 Michael Hanselmann
    @type job_id: number
1709 4e338533 Michael Hanselmann
    @param job_id: Job ID
1710 4e338533 Michael Hanselmann
    @type status: string or None
1711 4e338533 Michael Hanselmann
    @param status: Job status if available
1712 4e338533 Michael Hanselmann

1713 4e338533 Michael Hanselmann
    """
1714 4e338533 Michael Hanselmann
    raise NotImplementedError()
1715 4e338533 Michael Hanselmann
1716 4e338533 Michael Hanselmann
1717 4e338533 Michael Hanselmann
class _LuxiJobPollCb(JobPollCbBase):
1718 4e338533 Michael Hanselmann
  def __init__(self, cl):
1719 4e338533 Michael Hanselmann
    """Initializes this class.
1720 4e338533 Michael Hanselmann

1721 4e338533 Michael Hanselmann
    """
1722 4e338533 Michael Hanselmann
    JobPollCbBase.__init__(self)
1723 4e338533 Michael Hanselmann
    self.cl = cl
1724 4e338533 Michael Hanselmann
1725 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1726 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1727 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1728 4e338533 Michael Hanselmann

1729 4e338533 Michael Hanselmann
    """
1730 4e338533 Michael Hanselmann
    return self.cl.WaitForJobChangeOnce(job_id, fields,
1731 4e338533 Michael Hanselmann
                                        prev_job_info, prev_log_serial)
1732 4e338533 Michael Hanselmann
1733 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1734 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1735 4e338533 Michael Hanselmann

1736 4e338533 Michael Hanselmann
    """
1737 4e338533 Michael Hanselmann
    return self.cl.QueryJobs(job_ids, fields)
1738 4e338533 Michael Hanselmann
1739 4e338533 Michael Hanselmann
1740 4e338533 Michael Hanselmann
class FeedbackFnJobPollReportCb(JobPollReportCbBase):
1741 4e338533 Michael Hanselmann
  def __init__(self, feedback_fn):
1742 4e338533 Michael Hanselmann
    """Initializes this class.
1743 4e338533 Michael Hanselmann

1744 4e338533 Michael Hanselmann
    """
1745 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1746 4e338533 Michael Hanselmann
1747 4e338533 Michael Hanselmann
    self.feedback_fn = feedback_fn
1748 4e338533 Michael Hanselmann
1749 4e338533 Michael Hanselmann
    assert callable(feedback_fn)
1750 4e338533 Michael Hanselmann
1751 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1752 4e338533 Michael Hanselmann
    """Handles a log message.
1753 4e338533 Michael Hanselmann

1754 4e338533 Michael Hanselmann
    """
1755 4e338533 Michael Hanselmann
    self.feedback_fn((timestamp, log_type, log_msg))
1756 4e338533 Michael Hanselmann
1757 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1758 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1759 4e338533 Michael Hanselmann

1760 4e338533 Michael Hanselmann
    """
1761 4e338533 Michael Hanselmann
    # Ignore
1762 4e338533 Michael Hanselmann
1763 4e338533 Michael Hanselmann
1764 4e338533 Michael Hanselmann
class StdioJobPollReportCb(JobPollReportCbBase):
1765 4e338533 Michael Hanselmann
  def __init__(self):
1766 4e338533 Michael Hanselmann
    """Initializes this class.
1767 4e338533 Michael Hanselmann

1768 4e338533 Michael Hanselmann
    """
1769 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1770 4e338533 Michael Hanselmann
1771 4e338533 Michael Hanselmann
    self.notified_queued = False
1772 4e338533 Michael Hanselmann
    self.notified_waitlock = False
1773 4e338533 Michael Hanselmann
1774 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1775 4e338533 Michael Hanselmann
    """Handles a log message.
1776 4e338533 Michael Hanselmann

1777 4e338533 Michael Hanselmann
    """
1778 4e338533 Michael Hanselmann
    ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)),
1779 8a7f1c61 Michael Hanselmann
             FormatLogMessage(log_type, log_msg))
1780 4e338533 Michael Hanselmann
1781 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1782 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1783 4e338533 Michael Hanselmann

1784 4e338533 Michael Hanselmann
    """
1785 4e338533 Michael Hanselmann
    if status is None:
1786 4e338533 Michael Hanselmann
      return
1787 4e338533 Michael Hanselmann
1788 4e338533 Michael Hanselmann
    if status == constants.JOB_STATUS_QUEUED and not self.notified_queued:
1789 4e338533 Michael Hanselmann
      ToStderr("Job %s is waiting in queue", job_id)
1790 4e338533 Michael Hanselmann
      self.notified_queued = True
1791 4e338533 Michael Hanselmann
1792 47099cd1 Michael Hanselmann
    elif status == constants.JOB_STATUS_WAITING and not self.notified_waitlock:
1793 4e338533 Michael Hanselmann
      ToStderr("Job %s is trying to acquire all necessary locks", job_id)
1794 4e338533 Michael Hanselmann
      self.notified_waitlock = True
1795 4e338533 Michael Hanselmann
1796 4e338533 Michael Hanselmann
1797 8a7f1c61 Michael Hanselmann
def FormatLogMessage(log_type, log_msg):
1798 8a7f1c61 Michael Hanselmann
  """Formats a job message according to its type.
1799 8a7f1c61 Michael Hanselmann

1800 8a7f1c61 Michael Hanselmann
  """
1801 8a7f1c61 Michael Hanselmann
  if log_type != constants.ELOG_MESSAGE:
1802 8a7f1c61 Michael Hanselmann
    log_msg = str(log_msg)
1803 8a7f1c61 Michael Hanselmann
1804 8a7f1c61 Michael Hanselmann
  return utils.SafeEncode(log_msg)
1805 8a7f1c61 Michael Hanselmann
1806 8a7f1c61 Michael Hanselmann
1807 583163a6 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None, reporter=None):
1808 4e338533 Michael Hanselmann
  """Function to poll for the result of a job.
1809 4e338533 Michael Hanselmann

1810 4e338533 Michael Hanselmann
  @type job_id: job identified
1811 4e338533 Michael Hanselmann
  @param job_id: the job to poll for results
1812 4e338533 Michael Hanselmann
  @type cl: luxi.Client
1813 4e338533 Michael Hanselmann
  @param cl: the luxi client to use for communicating with the master;
1814 4e338533 Michael Hanselmann
             if None, a new client will be created
1815 4e338533 Michael Hanselmann

1816 4e338533 Michael Hanselmann
  """
1817 4e338533 Michael Hanselmann
  if cl is None:
1818 4e338533 Michael Hanselmann
    cl = GetClient()
1819 4e338533 Michael Hanselmann
1820 583163a6 Michael Hanselmann
  if reporter is None:
1821 583163a6 Michael Hanselmann
    if feedback_fn:
1822 583163a6 Michael Hanselmann
      reporter = FeedbackFnJobPollReportCb(feedback_fn)
1823 583163a6 Michael Hanselmann
    else:
1824 583163a6 Michael Hanselmann
      reporter = StdioJobPollReportCb()
1825 583163a6 Michael Hanselmann
  elif feedback_fn:
1826 583163a6 Michael Hanselmann
    raise errors.ProgrammerError("Can't specify reporter and feedback function")
1827 4e338533 Michael Hanselmann
1828 4e338533 Michael Hanselmann
  return GenericPollJob(job_id, _LuxiJobPollCb(cl), reporter)
1829 ceab32dd Iustin Pop
1830 ceab32dd Iustin Pop
1831 583163a6 Michael Hanselmann
def SubmitOpCode(op, cl=None, feedback_fn=None, opts=None, reporter=None):
1832 0a1e74d9 Iustin Pop
  """Legacy function to submit an opcode.
1833 0a1e74d9 Iustin Pop

1834 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1835 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1836 0a1e74d9 Iustin Pop
  interaction functions.
1837 0a1e74d9 Iustin Pop

1838 0a1e74d9 Iustin Pop
  """
1839 0a1e74d9 Iustin Pop
  if cl is None:
1840 0a1e74d9 Iustin Pop
    cl = GetClient()
1841 0a1e74d9 Iustin Pop
1842 293ba2d8 Iustin Pop
  SetGenericOpcodeOpts([op], opts)
1843 293ba2d8 Iustin Pop
1844 5d297d8a Michael Hanselmann
  job_id = SendJob([op], cl=cl)
1845 0a1e74d9 Iustin Pop
1846 583163a6 Michael Hanselmann
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn,
1847 583163a6 Michael Hanselmann
                       reporter=reporter)
1848 53c04d04 Iustin Pop
1849 53c04d04 Iustin Pop
  return op_results[0]
1850 0a1e74d9 Iustin Pop
1851 0a1e74d9 Iustin Pop
1852 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1853 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1854 94428652 Iustin Pop

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

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

1863 94428652 Iustin Pop
  """
1864 94428652 Iustin Pop
  if opts and opts.submit_only:
1865 293ba2d8 Iustin Pop
    job = [op]
1866 293ba2d8 Iustin Pop
    SetGenericOpcodeOpts(job, opts)
1867 293ba2d8 Iustin Pop
    job_id = SendJob(job, cl=cl)
1868 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
1869 94428652 Iustin Pop
  else:
1870 293ba2d8 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
1871 293ba2d8 Iustin Pop
1872 293ba2d8 Iustin Pop
1873 293ba2d8 Iustin Pop
def SetGenericOpcodeOpts(opcode_list, options):
1874 293ba2d8 Iustin Pop
  """Processor for generic options.
1875 293ba2d8 Iustin Pop

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

1879 293ba2d8 Iustin Pop
  @param opcode_list: list of opcodes
1880 293ba2d8 Iustin Pop
  @param options: command line options or None
1881 293ba2d8 Iustin Pop
  @return: None (in-place modification)
1882 293ba2d8 Iustin Pop

1883 293ba2d8 Iustin Pop
  """
1884 293ba2d8 Iustin Pop
  if not options:
1885 293ba2d8 Iustin Pop
    return
1886 293ba2d8 Iustin Pop
  for op in opcode_list:
1887 aa06f8c6 Michael Hanselmann
    op.debug_level = options.debug
1888 a0a6ff34 Iustin Pop
    if hasattr(options, "dry_run"):
1889 a0a6ff34 Iustin Pop
      op.dry_run = options.dry_run
1890 aa06f8c6 Michael Hanselmann
    if getattr(options, "priority", None) is not None:
1891 aa06f8c6 Michael Hanselmann
      op.priority = _PRIONAME_TO_VALUE[options.priority]
1892 94428652 Iustin Pop
1893 94428652 Iustin Pop
1894 af30b2fd Michael Hanselmann
def GetClient():
1895 af30b2fd Michael Hanselmann
  # TODO: Cache object?
1896 b33e986b Iustin Pop
  try:
1897 b33e986b Iustin Pop
    client = luxi.Client()
1898 b33e986b Iustin Pop
  except luxi.NoMasterError:
1899 d9a51679 Michael Hanselmann
    ss = ssconf.SimpleStore()
1900 d9a51679 Michael Hanselmann
1901 d9a51679 Michael Hanselmann
    # Try to read ssconf file
1902 d9a51679 Michael Hanselmann
    try:
1903 d9a51679 Michael Hanselmann
      ss.GetMasterNode()
1904 d9a51679 Michael Hanselmann
    except errors.ConfigurationError:
1905 d9a51679 Michael Hanselmann
      raise errors.OpPrereqError("Cluster not initialized or this machine is"
1906 d9a51679 Michael Hanselmann
                                 " not part of a cluster")
1907 d9a51679 Michael Hanselmann
1908 d9a51679 Michael Hanselmann
    master, myself = ssconf.GetMasterAndMyself(ss=ss)
1909 b33e986b Iustin Pop
    if master != myself:
1910 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
1911 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
1912 b33e986b Iustin Pop
                                 master)
1913 d9a51679 Michael Hanselmann
    raise
1914 b33e986b Iustin Pop
  return client
1915 af30b2fd Michael Hanselmann
1916 af30b2fd Michael Hanselmann
1917 73702ee7 Iustin Pop
def FormatError(err):
1918 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
1919 73702ee7 Iustin Pop

1920 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
1921 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
1922 73702ee7 Iustin Pop
  second, a string describing the error message (not
1923 73702ee7 Iustin Pop
  newline-terminated).
1924 73702ee7 Iustin Pop

1925 73702ee7 Iustin Pop
  """
1926 73702ee7 Iustin Pop
  retcode = 1
1927 73702ee7 Iustin Pop
  obuf = StringIO()
1928 e2e521d0 Iustin Pop
  msg = str(err)
1929 73702ee7 Iustin Pop
  if isinstance(err, errors.ConfigurationError):
1930 e2e521d0 Iustin Pop
    txt = "Corrupt configuration file: %s" % msg
1931 46fbdd04 Iustin Pop
    logging.error(txt)
1932 e2e521d0 Iustin Pop
    obuf.write(txt + "\n")
1933 73702ee7 Iustin Pop
    obuf.write("Aborting.")
1934 73702ee7 Iustin Pop
    retcode = 2
1935 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksAbort):
1936 73702ee7 Iustin Pop
    obuf.write("Failure: hooks execution failed:\n")
1937 73702ee7 Iustin Pop
    for node, script, out in err.args[0]:
1938 73702ee7 Iustin Pop
      if out:
1939 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s, output: %s\n" %
1940 73702ee7 Iustin Pop
                   (node, script, out))
1941 73702ee7 Iustin Pop
      else:
1942 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s (no output)\n" %
1943 73702ee7 Iustin Pop
                   (node, script))
1944 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksFailure):
1945 e2e521d0 Iustin Pop
    obuf.write("Failure: hooks general failure: %s" % msg)
1946 73702ee7 Iustin Pop
  elif isinstance(err, errors.ResolverError):
1947 b705c7a6 Manuel Franceschini
    this_host = netutils.Hostname.GetSysName()
1948 73702ee7 Iustin Pop
    if err.args[0] == this_host:
1949 73702ee7 Iustin Pop
      msg = "Failure: can't resolve my own hostname ('%s')"
1950 73702ee7 Iustin Pop
    else:
1951 73702ee7 Iustin Pop
      msg = "Failure: can't resolve hostname '%s'"
1952 73702ee7 Iustin Pop
    obuf.write(msg % err.args[0])
1953 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpPrereqError):
1954 5c983ee5 Iustin Pop
    if len(err.args) == 2:
1955 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
1956 5c983ee5 Iustin Pop
               " operation:\nerror type: %s, error details:\n%s" %
1957 5c983ee5 Iustin Pop
                 (err.args[1], err.args[0]))
1958 5c983ee5 Iustin Pop
    else:
1959 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
1960 5c983ee5 Iustin Pop
                 " operation:\n%s" % msg)
1961 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpExecError):
1962 e2e521d0 Iustin Pop
    obuf.write("Failure: command execution error:\n%s" % msg)
1963 73702ee7 Iustin Pop
  elif isinstance(err, errors.TagError):
1964 e2e521d0 Iustin Pop
    obuf.write("Failure: invalid tag(s) given:\n%s" % msg)
1965 686d7433 Iustin Pop
  elif isinstance(err, errors.JobQueueDrainError):
1966 686d7433 Iustin Pop
    obuf.write("Failure: the job queue is marked for drain and doesn't"
1967 686d7433 Iustin Pop
               " accept new requests\n")
1968 f87b405e Michael Hanselmann
  elif isinstance(err, errors.JobQueueFull):
1969 f87b405e Michael Hanselmann
    obuf.write("Failure: the job queue is full and doesn't accept new"
1970 f87b405e Michael Hanselmann
               " job submissions until old jobs are archived\n")
1971 a5728081 Guido Trotter
  elif isinstance(err, errors.TypeEnforcementError):
1972 a5728081 Guido Trotter
    obuf.write("Parameter Error: %s" % msg)
1973 c1ce76bb Iustin Pop
  elif isinstance(err, errors.ParameterError):
1974 c1ce76bb Iustin Pop
    obuf.write("Failure: unknown/wrong parameter name '%s'" % msg)
1975 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.NoMasterError):
1976 03a8dbdc Iustin Pop
    obuf.write("Cannot communicate with the master daemon.\nIs it running"
1977 082c5adb Michael Hanselmann
               " and listening for connections?")
1978 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.TimeoutError):
1979 cd4c86a8 Michael Hanselmann
    obuf.write("Timeout while talking to the master daemon. Jobs might have"
1980 cd4c86a8 Michael Hanselmann
               " been submitted and will continue to run even if the call"
1981 cd4c86a8 Michael Hanselmann
               " timed out. Useful commands in this situation are \"gnt-job"
1982 cd4c86a8 Michael Hanselmann
               " list\", \"gnt-job cancel\" and \"gnt-job watch\". Error:\n")
1983 cd4c86a8 Michael Hanselmann
    obuf.write(msg)
1984 5a1c22fe Iustin Pop
  elif isinstance(err, luxi.PermissionError):
1985 5a1c22fe Iustin Pop
    obuf.write("It seems you don't have permissions to connect to the"
1986 5a1c22fe Iustin Pop
               " master daemon.\nPlease retry as a different user.")
1987 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.ProtocolError):
1988 03a8dbdc Iustin Pop
    obuf.write("Unhandled protocol error while talking to the master daemon:\n"
1989 03a8dbdc Iustin Pop
               "%s" % msg)
1990 91c622a8 Iustin Pop
  elif isinstance(err, errors.JobLost):
1991 91c622a8 Iustin Pop
    obuf.write("Error checking job status: %s" % msg)
1992 cb1e6c3c Michael Hanselmann
  elif isinstance(err, errors.QueryFilterParseError):
1993 cb1e6c3c Michael Hanselmann
    obuf.write("Error while parsing query filter: %s\n" % err.args[0])
1994 cb1e6c3c Michael Hanselmann
    obuf.write("\n".join(err.GetDetails()))
1995 797506fc Michael Hanselmann
  elif isinstance(err, errors.GenericError):
1996 797506fc Michael Hanselmann
    obuf.write("Unhandled Ganeti error: %s" % msg)
1997 e9d741b6 Iustin Pop
  elif isinstance(err, JobSubmittedException):
1998 e9d741b6 Iustin Pop
    obuf.write("JobID: %s\n" % err.args[0])
1999 e9d741b6 Iustin Pop
    retcode = 0
2000 73702ee7 Iustin Pop
  else:
2001 e2e521d0 Iustin Pop
    obuf.write("Unhandled exception: %s" % msg)
2002 d0c8c01d Iustin Pop
  return retcode, obuf.getvalue().rstrip("\n")
2003 73702ee7 Iustin Pop
2004 73702ee7 Iustin Pop
2005 de47cf8f Guido Trotter
def GenericMain(commands, override=None, aliases=None):
2006 a8083063 Iustin Pop
  """Generic main function for all the gnt-* commands.
2007 a8083063 Iustin Pop

2008 334d1483 Iustin Pop
  Arguments:
2009 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
2010 334d1483 Iustin Pop
                for command line handling.
2011 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
2012 334d1483 Iustin Pop
                override command line options; this can be used to pass
2013 334d1483 Iustin Pop
                options from the scripts to generic functions
2014 de47cf8f Guido Trotter
    - aliases: dictionary with command aliases {'alias': 'target, ...}
2015 a8083063 Iustin Pop

2016 a8083063 Iustin Pop
  """
2017 a8083063 Iustin Pop
  # save the program name and the entire command line for later logging
2018 a8083063 Iustin Pop
  if sys.argv:
2019 a8083063 Iustin Pop
    binary = os.path.basename(sys.argv[0]) or sys.argv[0]
2020 a8083063 Iustin Pop
    if len(sys.argv) >= 2:
2021 a8083063 Iustin Pop
      binary += " " + sys.argv[1]
2022 a8083063 Iustin Pop
      old_cmdline = " ".join(sys.argv[2:])
2023 a8083063 Iustin Pop
    else:
2024 a8083063 Iustin Pop
      old_cmdline = ""
2025 a8083063 Iustin Pop
  else:
2026 a8083063 Iustin Pop
    binary = "<unknown program>"
2027 a8083063 Iustin Pop
    old_cmdline = ""
2028 a8083063 Iustin Pop
2029 de47cf8f Guido Trotter
  if aliases is None:
2030 de47cf8f Guido Trotter
    aliases = {}
2031 de47cf8f Guido Trotter
2032 3126878d Guido Trotter
  try:
2033 3126878d Guido Trotter
    func, options, args = _ParseArgs(sys.argv, commands, aliases)
2034 3126878d Guido Trotter
  except errors.ParameterError, err:
2035 3126878d Guido Trotter
    result, err_msg = FormatError(err)
2036 3126878d Guido Trotter
    ToStderr(err_msg)
2037 3126878d Guido Trotter
    return 1
2038 3126878d Guido Trotter
2039 a8083063 Iustin Pop
  if func is None: # parse error
2040 a8083063 Iustin Pop
    return 1
2041 a8083063 Iustin Pop
2042 334d1483 Iustin Pop
  if override is not None:
2043 334d1483 Iustin Pop
    for key, val in override.iteritems():
2044 334d1483 Iustin Pop
      setattr(options, key, val)
2045 334d1483 Iustin Pop
2046 cfcc79c6 Michael Hanselmann
  utils.SetupLogging(constants.LOG_COMMANDS, binary, debug=options.debug,
2047 cfcc79c6 Michael Hanselmann
                     stderr_logging=True)
2048 a8083063 Iustin Pop
2049 a8083063 Iustin Pop
  if old_cmdline:
2050 46fbdd04 Iustin Pop
    logging.info("run with arguments '%s'", old_cmdline)
2051 a8083063 Iustin Pop
  else:
2052 46fbdd04 Iustin Pop
    logging.info("run with no arguments")
2053 a8083063 Iustin Pop
2054 a8083063 Iustin Pop
  try:
2055 a4af651e Iustin Pop
    result = func(options, args)
2056 d8353c3a Iustin Pop
  except (errors.GenericError, luxi.ProtocolError,
2057 d8353c3a Iustin Pop
          JobSubmittedException), err:
2058 a4af651e Iustin Pop
    result, err_msg = FormatError(err)
2059 5bbd3f7f Michael Hanselmann
    logging.exception("Error during command processing")
2060 46fbdd04 Iustin Pop
    ToStderr(err_msg)
2061 8a53b55f Iustin Pop
  except KeyboardInterrupt:
2062 8a53b55f Iustin Pop
    result = constants.EXIT_FAILURE
2063 8a53b55f Iustin Pop
    ToStderr("Aborted. Note that if the operation created any jobs, they"
2064 8a53b55f Iustin Pop
             " might have been submitted and"
2065 8a53b55f Iustin Pop
             " will continue to run in the background.")
2066 225e2544 Iustin Pop
  except IOError, err:
2067 225e2544 Iustin Pop
    if err.errno == errno.EPIPE:
2068 225e2544 Iustin Pop
      # our terminal went away, we'll exit
2069 225e2544 Iustin Pop
      sys.exit(constants.EXIT_FAILURE)
2070 225e2544 Iustin Pop
    else:
2071 225e2544 Iustin Pop
      raise
2072 a8083063 Iustin Pop
2073 a8083063 Iustin Pop
  return result
2074 137161c9 Michael Hanselmann
2075 137161c9 Michael Hanselmann
2076 845c79d8 Michael Hanselmann
def ParseNicOption(optvalue):
2077 845c79d8 Michael Hanselmann
  """Parses the value of the --net option(s).
2078 845c79d8 Michael Hanselmann

2079 845c79d8 Michael Hanselmann
  """
2080 845c79d8 Michael Hanselmann
  try:
2081 845c79d8 Michael Hanselmann
    nic_max = max(int(nidx[0]) + 1 for nidx in optvalue)
2082 845c79d8 Michael Hanselmann
  except (TypeError, ValueError), err:
2083 845c79d8 Michael Hanselmann
    raise errors.OpPrereqError("Invalid NIC index passed: %s" % str(err))
2084 845c79d8 Michael Hanselmann
2085 845c79d8 Michael Hanselmann
  nics = [{}] * nic_max
2086 845c79d8 Michael Hanselmann
  for nidx, ndict in optvalue:
2087 845c79d8 Michael Hanselmann
    nidx = int(nidx)
2088 845c79d8 Michael Hanselmann
2089 845c79d8 Michael Hanselmann
    if not isinstance(ndict, dict):
2090 845c79d8 Michael Hanselmann
      raise errors.OpPrereqError("Invalid nic/%d value: expected dict,"
2091 845c79d8 Michael Hanselmann
                                 " got %s" % (nidx, ndict))
2092 845c79d8 Michael Hanselmann
2093 845c79d8 Michael Hanselmann
    utils.ForceDictType(ndict, constants.INIC_PARAMS_TYPES)
2094 845c79d8 Michael Hanselmann
2095 845c79d8 Michael Hanselmann
    nics[nidx] = ndict
2096 845c79d8 Michael Hanselmann
2097 845c79d8 Michael Hanselmann
  return nics
2098 845c79d8 Michael Hanselmann
2099 845c79d8 Michael Hanselmann
2100 d77490c5 Iustin Pop
def GenericInstanceCreate(mode, opts, args):
2101 d77490c5 Iustin Pop
  """Add an instance to the cluster via either creation or import.
2102 d77490c5 Iustin Pop

2103 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
2104 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
2105 d77490c5 Iustin Pop
  @type args: list
2106 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
2107 d77490c5 Iustin Pop
  @rtype: int
2108 d77490c5 Iustin Pop
  @return: the desired exit code
2109 d77490c5 Iustin Pop

2110 d77490c5 Iustin Pop
  """
2111 d77490c5 Iustin Pop
  instance = args[0]
2112 d77490c5 Iustin Pop
2113 d77490c5 Iustin Pop
  (pnode, snode) = SplitNodeOption(opts.node)
2114 d77490c5 Iustin Pop
2115 d77490c5 Iustin Pop
  hypervisor = None
2116 d77490c5 Iustin Pop
  hvparams = {}
2117 d77490c5 Iustin Pop
  if opts.hypervisor:
2118 d77490c5 Iustin Pop
    hypervisor, hvparams = opts.hypervisor
2119 d77490c5 Iustin Pop
2120 d77490c5 Iustin Pop
  if opts.nics:
2121 845c79d8 Michael Hanselmann
    nics = ParseNicOption(opts.nics)
2122 d77490c5 Iustin Pop
  elif opts.no_nics:
2123 d77490c5 Iustin Pop
    # no nics
2124 d77490c5 Iustin Pop
    nics = []
2125 0af0f641 Iustin Pop
  elif mode == constants.INSTANCE_CREATE:
2126 d77490c5 Iustin Pop
    # default of one nic, all auto
2127 d77490c5 Iustin Pop
    nics = [{}]
2128 0af0f641 Iustin Pop
  else:
2129 0af0f641 Iustin Pop
    # mode == import
2130 0af0f641 Iustin Pop
    nics = []
2131 d77490c5 Iustin Pop
2132 d77490c5 Iustin Pop
  if opts.disk_template == constants.DT_DISKLESS:
2133 d77490c5 Iustin Pop
    if opts.disks or opts.sd_size is not None:
2134 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Diskless instance but disk"
2135 d77490c5 Iustin Pop
                                 " information passed")
2136 d77490c5 Iustin Pop
    disks = []
2137 d77490c5 Iustin Pop
  else:
2138 9b12ed0f Iustin Pop
    if (not opts.disks and not opts.sd_size
2139 9b12ed0f Iustin Pop
        and mode == constants.INSTANCE_CREATE):
2140 d77490c5 Iustin Pop
      raise errors.OpPrereqError("No disk information specified")
2141 d77490c5 Iustin Pop
    if opts.disks and opts.sd_size is not None:
2142 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Please use either the '--disk' or"
2143 d77490c5 Iustin Pop
                                 " '-s' option")
2144 d77490c5 Iustin Pop
    if opts.sd_size is not None:
2145 ccfa86ba Michael Hanselmann
      opts.disks = [(0, {constants.IDISK_SIZE: opts.sd_size})]
2146 9b12ed0f Iustin Pop
2147 9b12ed0f Iustin Pop
    if opts.disks:
2148 9b12ed0f Iustin Pop
      try:
2149 9b12ed0f Iustin Pop
        disk_max = max(int(didx[0]) + 1 for didx in opts.disks)
2150 9b12ed0f Iustin Pop
      except ValueError, err:
2151 9b12ed0f Iustin Pop
        raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err))
2152 9b12ed0f Iustin Pop
      disks = [{}] * disk_max
2153 9b12ed0f Iustin Pop
    else:
2154 9b12ed0f Iustin Pop
      disks = []
2155 d77490c5 Iustin Pop
    for didx, ddict in opts.disks:
2156 d77490c5 Iustin Pop
      didx = int(didx)
2157 d77490c5 Iustin Pop
      if not isinstance(ddict, dict):
2158 d77490c5 Iustin Pop
        msg = "Invalid disk/%d value: expected dict, got %s" % (didx, ddict)
2159 d77490c5 Iustin Pop
        raise errors.OpPrereqError(msg)
2160 ccfa86ba Michael Hanselmann
      elif constants.IDISK_SIZE in ddict:
2161 ccfa86ba Michael Hanselmann
        if constants.IDISK_ADOPT in ddict:
2162 5029db65 Iustin Pop
          raise errors.OpPrereqError("Only one of 'size' and 'adopt' allowed"
2163 5029db65 Iustin Pop
                                     " (disk %d)" % didx)
2164 5029db65 Iustin Pop
        try:
2165 ccfa86ba Michael Hanselmann
          ddict[constants.IDISK_SIZE] = \
2166 ccfa86ba Michael Hanselmann
            utils.ParseUnit(ddict[constants.IDISK_SIZE])
2167 5029db65 Iustin Pop
        except ValueError, err:
2168 5029db65 Iustin Pop
          raise errors.OpPrereqError("Invalid disk size for disk %d: %s" %
2169 5029db65 Iustin Pop
                                     (didx, err))
2170 ccfa86ba Michael Hanselmann
      elif constants.IDISK_ADOPT in ddict:
2171 5029db65 Iustin Pop
        if mode == constants.INSTANCE_IMPORT:
2172 5029db65 Iustin Pop
          raise errors.OpPrereqError("Disk adoption not allowed for instance"
2173 5029db65 Iustin Pop
                                     " import")
2174 ccfa86ba Michael Hanselmann
        ddict[constants.IDISK_SIZE] = 0
2175 5029db65 Iustin Pop
      else:
2176 5029db65 Iustin Pop
        raise errors.OpPrereqError("Missing size or adoption source for"
2177 5029db65 Iustin Pop
                                   " disk %d" % didx)
2178 d77490c5 Iustin Pop
      disks[didx] = ddict
2179 d77490c5 Iustin Pop
2180 a57981c5 Apollon Oikonomopoulos
  if opts.tags is not None:
2181 0f8810df Michael Hanselmann
    tags = opts.tags.split(",")
2182 a57981c5 Apollon Oikonomopoulos
  else:
2183 a57981c5 Apollon Oikonomopoulos
    tags = []
2184 a57981c5 Apollon Oikonomopoulos
2185 d77490c5 Iustin Pop
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_TYPES)
2186 d77490c5 Iustin Pop
  utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
2187 d77490c5 Iustin Pop
2188 d77490c5 Iustin Pop
  if mode == constants.INSTANCE_CREATE:
2189 d77490c5 Iustin Pop
    start = opts.start
2190 d77490c5 Iustin Pop
    os_type = opts.os
2191 1ee8e01a Guido Trotter
    force_variant = opts.force_variant
2192 d77490c5 Iustin Pop
    src_node = None
2193 d77490c5 Iustin Pop
    src_path = None
2194 25a8792c Iustin Pop
    no_install = opts.no_install
2195 e588764d Iustin Pop
    identify_defaults = False
2196 d77490c5 Iustin Pop
  elif mode == constants.INSTANCE_IMPORT:
2197 d77490c5 Iustin Pop
    start = False
2198 d77490c5 Iustin Pop
    os_type = None
2199 1ee8e01a Guido Trotter
    force_variant = False
2200 d77490c5 Iustin Pop
    src_node = opts.src_node
2201 d77490c5 Iustin Pop
    src_path = opts.src_dir
2202 25a8792c Iustin Pop
    no_install = None
2203 e588764d Iustin Pop
    identify_defaults = opts.identify_defaults
2204 d77490c5 Iustin Pop
  else:
2205 d77490c5 Iustin Pop
    raise errors.ProgrammerError("Invalid creation mode %s" % mode)
2206 d77490c5 Iustin Pop
2207 e1530b10 Iustin Pop
  op = opcodes.OpInstanceCreate(instance_name=instance,
2208 d77490c5 Iustin Pop
                                disks=disks,
2209 d77490c5 Iustin Pop
                                disk_template=opts.disk_template,
2210 d77490c5 Iustin Pop
                                nics=nics,
2211 d77490c5 Iustin Pop
                                pnode=pnode, snode=snode,
2212 d77490c5 Iustin Pop
                                ip_check=opts.ip_check,
2213 460d22be Iustin Pop
                                name_check=opts.name_check,
2214 d77490c5 Iustin Pop
                                wait_for_sync=opts.wait_for_sync,
2215 d77490c5 Iustin Pop
                                file_storage_dir=opts.file_storage_dir,
2216 d77490c5 Iustin Pop
                                file_driver=opts.file_driver,
2217 d77490c5 Iustin Pop
                                iallocator=opts.iallocator,
2218 d77490c5 Iustin Pop
                                hypervisor=hypervisor,
2219 d77490c5 Iustin Pop
                                hvparams=hvparams,
2220 d77490c5 Iustin Pop
                                beparams=opts.beparams,
2221 062a7100 Iustin Pop
                                osparams=opts.osparams,
2222 d77490c5 Iustin Pop
                                mode=mode,
2223 d77490c5 Iustin Pop
                                start=start,
2224 d77490c5 Iustin Pop
                                os_type=os_type,
2225 1ee8e01a Guido Trotter
                                force_variant=force_variant,
2226 d77490c5 Iustin Pop
                                src_node=src_node,
2227 25a8792c Iustin Pop
                                src_path=src_path,
2228 a57981c5 Apollon Oikonomopoulos
                                tags=tags,
2229 e588764d Iustin Pop
                                no_install=no_install,
2230 e588764d Iustin Pop
                                identify_defaults=identify_defaults)
2231 d77490c5 Iustin Pop
2232 d77490c5 Iustin Pop
  SubmitOrSend(op, opts)
2233 d77490c5 Iustin Pop
  return 0
2234 d77490c5 Iustin Pop
2235 d77490c5 Iustin Pop
2236 7e49b6ce Michael Hanselmann
class _RunWhileClusterStoppedHelper:
2237 7e49b6ce Michael Hanselmann
  """Helper class for L{RunWhileClusterStopped} to simplify state management
2238 7e49b6ce Michael Hanselmann

2239 7e49b6ce Michael Hanselmann
  """
2240 7e49b6ce Michael Hanselmann
  def __init__(self, feedback_fn, cluster_name, master_node, online_nodes):
2241 7e49b6ce Michael Hanselmann
    """Initializes this class.
2242 7e49b6ce Michael Hanselmann

2243 7e49b6ce Michael Hanselmann
    @type feedback_fn: callable
2244 7e49b6ce Michael Hanselmann
    @param feedback_fn: Feedback function
2245 7e49b6ce Michael Hanselmann
    @type cluster_name: string
2246 7e49b6ce Michael Hanselmann
    @param cluster_name: Cluster name
2247 7e49b6ce Michael Hanselmann
    @type master_node: string
2248 7e49b6ce Michael Hanselmann
    @param master_node Master node name
2249 7e49b6ce Michael Hanselmann
    @type online_nodes: list
2250 7e49b6ce Michael Hanselmann
    @param online_nodes: List of names of online nodes
2251 7e49b6ce Michael Hanselmann

2252 7e49b6ce Michael Hanselmann
    """
2253 7e49b6ce Michael Hanselmann
    self.feedback_fn = feedback_fn
2254 7e49b6ce Michael Hanselmann
    self.cluster_name = cluster_name
2255 7e49b6ce Michael Hanselmann
    self.master_node = master_node
2256 7e49b6ce Michael Hanselmann
    self.online_nodes = online_nodes
2257 7e49b6ce Michael Hanselmann
2258 7e49b6ce Michael Hanselmann
    self.ssh = ssh.SshRunner(self.cluster_name)
2259 7e49b6ce Michael Hanselmann
2260 7e49b6ce Michael Hanselmann
    self.nonmaster_nodes = [name for name in online_nodes
2261 7e49b6ce Michael Hanselmann
                            if name != master_node]
2262 7e49b6ce Michael Hanselmann
2263 7e49b6ce Michael Hanselmann
    assert self.master_node not in self.nonmaster_nodes
2264 7e49b6ce Michael Hanselmann
2265 7e49b6ce Michael Hanselmann
  def _RunCmd(self, node_name, cmd):
2266 7e49b6ce Michael Hanselmann
    """Runs a command on the local or a remote machine.
2267 7e49b6ce Michael Hanselmann

2268 7e49b6ce Michael Hanselmann
    @type node_name: string
2269 7e49b6ce Michael Hanselmann
    @param node_name: Machine name
2270 7e49b6ce Michael Hanselmann
    @type cmd: list
2271 7e49b6ce Michael Hanselmann
    @param cmd: Command
2272 7e49b6ce Michael Hanselmann

2273 7e49b6ce Michael Hanselmann
    """
2274 7e49b6ce Michael Hanselmann
    if node_name is None or node_name == self.master_node:
2275 7e49b6ce Michael Hanselmann
      # No need to use SSH
2276 7e49b6ce Michael Hanselmann
      result = utils.RunCmd(cmd)
2277 7e49b6ce Michael Hanselmann
    else:
2278 7e49b6ce Michael Hanselmann
      result = self.ssh.Run(node_name, "root", utils.ShellQuoteArgs(cmd))
2279 7e49b6ce Michael Hanselmann
2280 7e49b6ce Michael Hanselmann
    if result.failed:
2281 7e49b6ce Michael Hanselmann
      errmsg = ["Failed to run command %s" % result.cmd]
2282 7e49b6ce Michael Hanselmann
      if node_name:
2283 7e49b6ce Michael Hanselmann
        errmsg.append("on node %s" % node_name)
2284 7e49b6ce Michael Hanselmann
      errmsg.append(": exitcode %s and error %s" %
2285 7e49b6ce Michael Hanselmann
                    (result.exit_code, result.output))
2286 7e49b6ce Michael Hanselmann
      raise errors.OpExecError(" ".join(errmsg))
2287 7e49b6ce Michael Hanselmann
2288 7e49b6ce Michael Hanselmann
  def Call(self, fn, *args):
2289 7e49b6ce Michael Hanselmann
    """Call function while all daemons are stopped.
2290 7e49b6ce Michael Hanselmann

2291 7e49b6ce Michael Hanselmann
    @type fn: callable
2292 7e49b6ce Michael Hanselmann
    @param fn: Function to be called
2293 7e49b6ce Michael Hanselmann

2294 7e49b6ce Michael Hanselmann
    """
2295 7e49b6ce Michael Hanselmann
    # Pause watcher by acquiring an exclusive lock on watcher state file
2296 7e49b6ce Michael Hanselmann
    self.feedback_fn("Blocking watcher")
2297 16e0b9c9 Michael Hanselmann
    watcher_block = utils.FileLock.Open(constants.WATCHER_LOCK_FILE)
2298 7e49b6ce Michael Hanselmann
    try:
2299 7e49b6ce Michael Hanselmann
      # TODO: Currently, this just blocks. There's no timeout.
2300 7e49b6ce Michael Hanselmann
      # TODO: Should it be a shared lock?
2301 7e49b6ce Michael Hanselmann
      watcher_block.Exclusive(blocking=True)
2302 7e49b6ce Michael Hanselmann
2303 7e49b6ce Michael Hanselmann
      # Stop master daemons, so that no new jobs can come in and all running
2304 7e49b6ce Michael Hanselmann
      # ones are finished
2305 7e49b6ce Michael Hanselmann
      self.feedback_fn("Stopping master daemons")
2306 7e49b6ce Michael Hanselmann
      self._RunCmd(None, [constants.DAEMON_UTIL, "stop-master"])
2307 7e49b6ce Michael Hanselmann
      try:
2308 7e49b6ce Michael Hanselmann
        # Stop daemons on all nodes
2309 7e49b6ce Michael Hanselmann
        for node_name in self.online_nodes:
2310 7e49b6ce Michael Hanselmann
          self.feedback_fn("Stopping daemons on %s" % node_name)
2311 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "stop-all"])
2312 7e49b6ce Michael Hanselmann
2313 7e49b6ce Michael Hanselmann
        # All daemons are shut down now
2314 7e49b6ce Michael Hanselmann
        try:
2315 7e49b6ce Michael Hanselmann
          return fn(self, *args)
2316 d512e84b Michael Hanselmann
        except Exception, err:
2317 d512e84b Michael Hanselmann
          _, errmsg = FormatError(err)
2318 7e49b6ce Michael Hanselmann
          logging.exception("Caught exception")
2319 d512e84b Michael Hanselmann
          self.feedback_fn(errmsg)
2320 7e49b6ce Michael Hanselmann
          raise
2321 7e49b6ce Michael Hanselmann
      finally:
2322 7e49b6ce Michael Hanselmann
        # Start cluster again, master node last
2323 7e49b6ce Michael Hanselmann
        for node_name in self.nonmaster_nodes + [self.master_node]:
2324 7e49b6ce Michael Hanselmann
          self.feedback_fn("Starting daemons on %s" % node_name)
2325 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "start-all"])
2326 7e49b6ce Michael Hanselmann
    finally:
2327 7e49b6ce Michael Hanselmann
      # Resume watcher
2328 7e49b6ce Michael Hanselmann
      watcher_block.Close()
2329 7e49b6ce Michael Hanselmann
2330 7e49b6ce Michael Hanselmann
2331 7e49b6ce Michael Hanselmann
def RunWhileClusterStopped(feedback_fn, fn, *args):
2332 7e49b6ce Michael Hanselmann
  """Calls a function while all cluster daemons are stopped.
2333 7e49b6ce Michael Hanselmann

2334 7e49b6ce Michael Hanselmann
  @type feedback_fn: callable
2335 7e49b6ce Michael Hanselmann
  @param feedback_fn: Feedback function
2336 7e49b6ce Michael Hanselmann
  @type fn: callable
2337 7e49b6ce Michael Hanselmann
  @param fn: Function to be called when daemons are stopped
2338 7e49b6ce Michael Hanselmann

2339 7e49b6ce Michael Hanselmann
  """
2340 7e49b6ce Michael Hanselmann
  feedback_fn("Gathering cluster information")
2341 7e49b6ce Michael Hanselmann
2342 7e49b6ce Michael Hanselmann
  # This ensures we're running on the master daemon
2343 7e49b6ce Michael Hanselmann
  cl = GetClient()
2344 7e49b6ce Michael Hanselmann
2345 7e49b6ce Michael Hanselmann
  (cluster_name, master_node) = \
2346 7e49b6ce Michael Hanselmann
    cl.QueryConfigValues(["cluster_name", "master_node"])
2347 7e49b6ce Michael Hanselmann
2348 7e49b6ce Michael Hanselmann
  online_nodes = GetOnlineNodes([], cl=cl)
2349 7e49b6ce Michael Hanselmann
2350 7e49b6ce Michael Hanselmann
  # Don't keep a reference to the client. The master daemon will go away.
2351 7e49b6ce Michael Hanselmann
  del cl
2352 7e49b6ce Michael Hanselmann
2353 7e49b6ce Michael Hanselmann
  assert master_node in online_nodes
2354 7e49b6ce Michael Hanselmann
2355 7e49b6ce Michael Hanselmann
  return _RunWhileClusterStoppedHelper(feedback_fn, cluster_name, master_node,
2356 7e49b6ce Michael Hanselmann
                                       online_nodes).Call(fn, *args)
2357 7e49b6ce Michael Hanselmann
2358 7e49b6ce Michael Hanselmann
2359 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
2360 9fbfbb7b Iustin Pop
                  numfields=None, unitfields=None,
2361 9fbfbb7b Iustin Pop
                  units=None):
2362 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
2363 137161c9 Michael Hanselmann

2364 9fbfbb7b Iustin Pop
  @type headers: dict
2365 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
2366 9fbfbb7b Iustin Pop
      the table
2367 9fbfbb7b Iustin Pop
  @type fields: list
2368 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
2369 9fbfbb7b Iustin Pop
      the data field
2370 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
2371 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
2372 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
2373 9fbfbb7b Iustin Pop
      each field
2374 9fbfbb7b Iustin Pop
  @type data: list
2375 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
2376 9fbfbb7b Iustin Pop
  @type numfields: list
2377 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
2378 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
2379 9fbfbb7b Iustin Pop
  @type unitfields: list
2380 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
2381 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
2382 9fbfbb7b Iustin Pop
  @type units: string or None
2383 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
2384 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
2385 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
2386 137161c9 Michael Hanselmann

2387 137161c9 Michael Hanselmann
  """
2388 9fbfbb7b Iustin Pop
  if units is None:
2389 9fbfbb7b Iustin Pop
    if separator:
2390 9fbfbb7b Iustin Pop
      units = "m"
2391 9fbfbb7b Iustin Pop
    else:
2392 9fbfbb7b Iustin Pop
      units = "h"
2393 9fbfbb7b Iustin Pop
2394 137161c9 Michael Hanselmann
  if numfields is None:
2395 137161c9 Michael Hanselmann
    numfields = []
2396 137161c9 Michael Hanselmann
  if unitfields is None:
2397 137161c9 Michael Hanselmann
    unitfields = []
2398 137161c9 Michael Hanselmann
2399 b459a848 Andrea Spadaccini
  numfields = utils.FieldSet(*numfields)   # pylint: disable=W0142
2400 b459a848 Andrea Spadaccini
  unitfields = utils.FieldSet(*unitfields) # pylint: disable=W0142
2401 00430f8e Iustin Pop
2402 137161c9 Michael Hanselmann
  format_fields = []
2403 137161c9 Michael Hanselmann
  for field in fields:
2404 01ca31ae Iustin Pop
    if headers and field not in headers:
2405 ea5a5b74 Guido Trotter
      # TODO: handle better unknown fields (either revert to old
2406 71c1af58 Iustin Pop
      # style of raising exception, or deal more intelligently with
2407 71c1af58 Iustin Pop
      # variable fields)
2408 71c1af58 Iustin Pop
      headers[field] = field
2409 137161c9 Michael Hanselmann
    if separator is not None:
2410 137161c9 Michael Hanselmann
      format_fields.append("%s")
2411 00430f8e Iustin Pop
    elif numfields.Matches(field):
2412 137161c9 Michael Hanselmann
      format_fields.append("%*s")
2413 137161c9 Michael Hanselmann
    else:
2414 137161c9 Michael Hanselmann
      format_fields.append("%-*s")
2415 137161c9 Michael Hanselmann
2416 137161c9 Michael Hanselmann
  if separator is None:
2417 137161c9 Michael Hanselmann
    mlens = [0 for name in fields]
2418 d0c8c01d Iustin Pop
    format_str = " ".join(format_fields)
2419 137161c9 Michael Hanselmann
  else:
2420 c04bc777 Iustin Pop
    format_str = separator.replace("%", "%%").join(format_fields)
2421 137161c9 Michael Hanselmann
2422 137161c9 Michael Hanselmann
  for row in data:
2423 dcbd6288 Guido Trotter
    if row is None:
2424 dcbd6288 Guido Trotter
      continue
2425 137161c9 Michael Hanselmann
    for idx, val in enumerate(row):
2426 00430f8e Iustin Pop
      if unitfields.Matches(fields[idx]):
2427 137161c9 Michael Hanselmann
        try:
2428 137161c9 Michael Hanselmann
          val = int(val)
2429 691744c4 Iustin Pop
        except (TypeError, ValueError):
2430 137161c9 Michael Hanselmann
          pass
2431 137161c9 Michael Hanselmann
        else:
2432 9fbfbb7b Iustin Pop
          val = row[idx] = utils.FormatUnit(val, units)
2433 01ca31ae Iustin Pop
      val = row[idx] = str(val)
2434 137161c9 Michael Hanselmann
      if separator is None:
2435 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(val))
2436 137161c9 Michael Hanselmann
2437 16be8703 Iustin Pop
  result = []
2438 137161c9 Michael Hanselmann
  if headers:
2439 137161c9 Michael Hanselmann
    args = []
2440 137161c9 Michael Hanselmann
    for idx, name in enumerate(fields):
2441 137161c9 Michael Hanselmann
      hdr = headers[name]
2442 137161c9 Michael Hanselmann
      if separator is None:
2443 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(hdr))
2444 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2445 137161c9 Michael Hanselmann
      args.append(hdr)
2446 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2447 137161c9 Michael Hanselmann
2448 ec39d63c Michael Hanselmann
  if separator is None:
2449 ec39d63c Michael Hanselmann
    assert len(mlens) == len(fields)
2450 ec39d63c Michael Hanselmann
2451 ec39d63c Michael Hanselmann
    if fields and not numfields.Matches(fields[-1]):
2452 ec39d63c Michael Hanselmann
      mlens[-1] = 0
2453 ec39d63c Michael Hanselmann
2454 137161c9 Michael Hanselmann
  for line in data:
2455 137161c9 Michael Hanselmann
    args = []
2456 dcbd6288 Guido Trotter
    if line is None:
2457 d0c8c01d Iustin Pop
      line = ["-" for _ in fields]
2458 f1501b3f Michael Hanselmann
    for idx in range(len(fields)):
2459 137161c9 Michael Hanselmann
      if separator is None:
2460 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2461 137161c9 Michael Hanselmann
      args.append(line[idx])
2462 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2463 16be8703 Iustin Pop
2464 16be8703 Iustin Pop
  return result
2465 3386e7a9 Iustin Pop
2466 3386e7a9 Iustin Pop
2467 ee3aedff Michael Hanselmann
def _FormatBool(value):
2468 ee3aedff Michael Hanselmann
  """Formats a boolean value as a string.
2469 ee3aedff Michael Hanselmann

2470 ee3aedff Michael Hanselmann
  """
2471 ee3aedff Michael Hanselmann
  if value:
2472 ee3aedff Michael Hanselmann
    return "Y"
2473 ee3aedff Michael Hanselmann
  return "N"
2474 ee3aedff Michael Hanselmann
2475 ee3aedff Michael Hanselmann
2476 ee3aedff Michael Hanselmann
#: Default formatting for query results; (callback, align right)
2477 ee3aedff Michael Hanselmann
_DEFAULT_FORMAT_QUERY = {
2478 ee3aedff Michael Hanselmann
  constants.QFT_TEXT: (str, False),
2479 ee3aedff Michael Hanselmann
  constants.QFT_BOOL: (_FormatBool, False),
2480 ee3aedff Michael Hanselmann
  constants.QFT_NUMBER: (str, True),
2481 ee3aedff Michael Hanselmann
  constants.QFT_TIMESTAMP: (utils.FormatTime, False),
2482 ee3aedff Michael Hanselmann
  constants.QFT_OTHER: (str, False),
2483 ee3aedff Michael Hanselmann
  constants.QFT_UNKNOWN: (str, False),
2484 ee3aedff Michael Hanselmann
  }
2485 ee3aedff Michael Hanselmann
2486 ee3aedff Michael Hanselmann
2487 ee3aedff Michael Hanselmann
def _GetColumnFormatter(fdef, override, unit):
2488 ee3aedff Michael Hanselmann
  """Returns formatting function for a field.
2489 ee3aedff Michael Hanselmann

2490 ee3aedff Michael Hanselmann
  @type fdef: L{objects.QueryFieldDefinition}
2491 ee3aedff Michael Hanselmann
  @type override: dict
2492 ee3aedff Michael Hanselmann
  @param override: Dictionary for overriding field formatting functions,
2493 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2494 ee3aedff Michael Hanselmann
  @type unit: string
2495 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT}
2496 ee3aedff Michael Hanselmann
  @rtype: tuple; (callable, bool)
2497 ee3aedff Michael Hanselmann
  @return: Returns the function to format a value (takes one parameter) and a
2498 ee3aedff Michael Hanselmann
    boolean for aligning the value on the right-hand side
2499 ee3aedff Michael Hanselmann

2500 ee3aedff Michael Hanselmann
  """
2501 ee3aedff Michael Hanselmann
  fmt = override.get(fdef.name, None)
2502 ee3aedff Michael Hanselmann
  if fmt is not None:
2503 ee3aedff Michael Hanselmann
    return fmt
2504 ee3aedff Michael Hanselmann
2505 ee3aedff Michael Hanselmann
  assert constants.QFT_UNIT not in _DEFAULT_FORMAT_QUERY
2506 ee3aedff Michael Hanselmann
2507 ee3aedff Michael Hanselmann
  if fdef.kind == constants.QFT_UNIT:
2508 ee3aedff Michael Hanselmann
    # Can't keep this information in the static dictionary
2509 ee3aedff Michael Hanselmann
    return (lambda value: utils.FormatUnit(value, unit), True)
2510 ee3aedff Michael Hanselmann
2511 ee3aedff Michael Hanselmann
  fmt = _DEFAULT_FORMAT_QUERY.get(fdef.kind, None)
2512 ee3aedff Michael Hanselmann
  if fmt is not None:
2513 ee3aedff Michael Hanselmann
    return fmt
2514 ee3aedff Michael Hanselmann
2515 ee3aedff Michael Hanselmann
  raise NotImplementedError("Can't format column type '%s'" % fdef.kind)
2516 ee3aedff Michael Hanselmann
2517 ee3aedff Michael Hanselmann
2518 ee3aedff Michael Hanselmann
class _QueryColumnFormatter:
2519 ee3aedff Michael Hanselmann
  """Callable class for formatting fields of a query.
2520 ee3aedff Michael Hanselmann

2521 ee3aedff Michael Hanselmann
  """
2522 f0b1bafe Iustin Pop
  def __init__(self, fn, status_fn, verbose):
2523 ee3aedff Michael Hanselmann
    """Initializes this class.
2524 ee3aedff Michael Hanselmann

2525 ee3aedff Michael Hanselmann
    @type fn: callable
2526 ee3aedff Michael Hanselmann
    @param fn: Formatting function
2527 ee3aedff Michael Hanselmann
    @type status_fn: callable
2528 ee3aedff Michael Hanselmann
    @param status_fn: Function to report fields' status
2529 f0b1bafe Iustin Pop
    @type verbose: boolean
2530 f0b1bafe Iustin Pop
    @param verbose: whether to use verbose field descriptions or not
2531 ee3aedff Michael Hanselmann

2532 ee3aedff Michael Hanselmann
    """
2533 ee3aedff Michael Hanselmann
    self._fn = fn
2534 ee3aedff Michael Hanselmann
    self._status_fn = status_fn
2535 cbfa4f0f Michael Hanselmann
    self._verbose = verbose
2536 ee3aedff Michael Hanselmann
2537 ee3aedff Michael Hanselmann
  def __call__(self, data):
2538 ee3aedff Michael Hanselmann
    """Returns a field's string representation.
2539 ee3aedff Michael Hanselmann

2540 ee3aedff Michael Hanselmann
    """
2541 ee3aedff Michael Hanselmann
    (status, value) = data
2542 ee3aedff Michael Hanselmann
2543 ee3aedff Michael Hanselmann
    # Report status
2544 ee3aedff Michael Hanselmann
    self._status_fn(status)
2545 ee3aedff Michael Hanselmann
2546 cfb084ae René Nussbaumer
    if status == constants.RS_NORMAL:
2547 ee3aedff Michael Hanselmann
      return self._fn(value)
2548 ee3aedff Michael Hanselmann
2549 ee3aedff Michael Hanselmann
    assert value is None, \
2550 ee3aedff Michael Hanselmann
           "Found value %r for abnormal status %s" % (value, status)
2551 ee3aedff Michael Hanselmann
2552 f2c6673d Michael Hanselmann
    return FormatResultError(status, self._verbose)
2553 ee3aedff Michael Hanselmann
2554 ee3aedff Michael Hanselmann
2555 f2c6673d Michael Hanselmann
def FormatResultError(status, verbose):
2556 ae95e419 René Nussbaumer
  """Formats result status other than L{constants.RS_NORMAL}.
2557 ee3aedff Michael Hanselmann

2558 ae95e419 René Nussbaumer
  @param status: The result status
2559 f2c6673d Michael Hanselmann
  @type verbose: boolean
2560 f2c6673d Michael Hanselmann
  @param verbose: Whether to return the verbose text
2561 ae95e419 René Nussbaumer
  @return: Text of result status
2562 a6070ef7 Michael Hanselmann

2563 ae95e419 René Nussbaumer
  """
2564 ae95e419 René Nussbaumer
  assert status != constants.RS_NORMAL, \
2565 cbfa4f0f Michael Hanselmann
         "FormatResultError called with status equal to constants.RS_NORMAL"
2566 ae95e419 René Nussbaumer
  try:
2567 cbfa4f0f Michael Hanselmann
    (verbose_text, normal_text) = constants.RSS_DESCRIPTION[status]
2568 ae95e419 René Nussbaumer
  except KeyError:
2569 ee3aedff Michael Hanselmann
    raise NotImplementedError("Unknown status %s" % status)
2570 cbfa4f0f Michael Hanselmann
  else:
2571 cbfa4f0f Michael Hanselmann
    if verbose:
2572 cbfa4f0f Michael Hanselmann
      return verbose_text
2573 cbfa4f0f Michael Hanselmann
    return normal_text
2574 ee3aedff Michael Hanselmann
2575 ee3aedff Michael Hanselmann
2576 ee3aedff Michael Hanselmann
def FormatQueryResult(result, unit=None, format_override=None, separator=None,
2577 f0b1bafe Iustin Pop
                      header=False, verbose=False):
2578 ee3aedff Michael Hanselmann
  """Formats data in L{objects.QueryResponse}.
2579 ee3aedff Michael Hanselmann

2580 ee3aedff Michael Hanselmann
  @type result: L{objects.QueryResponse}
2581 ee3aedff Michael Hanselmann
  @param result: result of query operation
2582 ee3aedff Michael Hanselmann
  @type unit: string
2583 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT},
2584 18009c1e Iustin Pop
    see L{utils.text.FormatUnit}
2585 ee3aedff Michael Hanselmann
  @type format_override: dict
2586 ee3aedff Michael Hanselmann
  @param format_override: Dictionary for overriding field formatting functions,
2587 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2588 ee3aedff Michael Hanselmann
  @type separator: string or None
2589 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2590 ee3aedff Michael Hanselmann
  @type header: bool
2591 ee3aedff Michael Hanselmann
  @param header: Whether to output header row
2592 f0b1bafe Iustin Pop
  @type verbose: boolean
2593 f0b1bafe Iustin Pop
  @param verbose: whether to use verbose field descriptions or not
2594 ee3aedff Michael Hanselmann

2595 ee3aedff Michael Hanselmann
  """
2596 ee3aedff Michael Hanselmann
  if unit is None:
2597 ee3aedff Michael Hanselmann
    if separator:
2598 ee3aedff Michael Hanselmann
      unit = "m"
2599 ee3aedff Michael Hanselmann
    else:
2600 ee3aedff Michael Hanselmann
      unit = "h"
2601 ee3aedff Michael Hanselmann
2602 ee3aedff Michael Hanselmann
  if format_override is None:
2603 ee3aedff Michael Hanselmann
    format_override = {}
2604 ee3aedff Michael Hanselmann
2605 cfb084ae René Nussbaumer
  stats = dict.fromkeys(constants.RS_ALL, 0)
2606 ee3aedff Michael Hanselmann
2607 ee3aedff Michael Hanselmann
  def _RecordStatus(status):
2608 ee3aedff Michael Hanselmann
    if status in stats:
2609 ee3aedff Michael Hanselmann
      stats[status] += 1
2610 ee3aedff Michael Hanselmann
2611 ee3aedff Michael Hanselmann
  columns = []
2612 ee3aedff Michael Hanselmann
  for fdef in result.fields:
2613 ee3aedff Michael Hanselmann
    assert fdef.title and fdef.name
2614 ee3aedff Michael Hanselmann
    (fn, align_right) = _GetColumnFormatter(fdef, format_override, unit)
2615 ee3aedff Michael Hanselmann
    columns.append(TableColumn(fdef.title,
2616 f0b1bafe Iustin Pop
                               _QueryColumnFormatter(fn, _RecordStatus,
2617 f0b1bafe Iustin Pop
                                                     verbose),
2618 ee3aedff Michael Hanselmann
                               align_right))
2619 ee3aedff Michael Hanselmann
2620 ee3aedff Michael Hanselmann
  table = FormatTable(result.data, columns, header, separator)
2621 ee3aedff Michael Hanselmann
2622 ee3aedff Michael Hanselmann
  # Collect statistics
2623 cfb084ae René Nussbaumer
  assert len(stats) == len(constants.RS_ALL)
2624 ee3aedff Michael Hanselmann
  assert compat.all(count >= 0 for count in stats.values())
2625 ee3aedff Michael Hanselmann
2626 ee3aedff Michael Hanselmann
  # Determine overall status. If there was no data, unknown fields must be
2627 ee3aedff Michael Hanselmann
  # detected via the field definitions.
2628 cfb084ae René Nussbaumer
  if (stats[constants.RS_UNKNOWN] or
2629 ee3aedff Michael Hanselmann
      (not result.data and _GetUnknownFields(result.fields))):
2630 ee3aedff Michael Hanselmann
    status = QR_UNKNOWN
2631 ee3aedff Michael Hanselmann
  elif compat.any(count > 0 for key, count in stats.items()
2632 cfb084ae René Nussbaumer
                  if key != constants.RS_NORMAL):
2633 ee3aedff Michael Hanselmann
    status = QR_INCOMPLETE
2634 ee3aedff Michael Hanselmann
  else:
2635 ee3aedff Michael Hanselmann
    status = QR_NORMAL
2636 ee3aedff Michael Hanselmann
2637 ee3aedff Michael Hanselmann
  return (status, table)
2638 ee3aedff Michael Hanselmann
2639 ee3aedff Michael Hanselmann
2640 ee3aedff Michael Hanselmann
def _GetUnknownFields(fdefs):
2641 ee3aedff Michael Hanselmann
  """Returns list of unknown fields included in C{fdefs}.
2642 ee3aedff Michael Hanselmann

2643 ee3aedff Michael Hanselmann
  @type fdefs: list of L{objects.QueryFieldDefinition}
2644 ee3aedff Michael Hanselmann

2645 ee3aedff Michael Hanselmann
  """
2646 ee3aedff Michael Hanselmann
  return [fdef for fdef in fdefs
2647 ee3aedff Michael Hanselmann
          if fdef.kind == constants.QFT_UNKNOWN]
2648 ee3aedff Michael Hanselmann
2649 ee3aedff Michael Hanselmann
2650 ee3aedff Michael Hanselmann
def _WarnUnknownFields(fdefs):
2651 ee3aedff Michael Hanselmann
  """Prints a warning to stderr if a query included unknown fields.
2652 ee3aedff Michael Hanselmann

2653 ee3aedff Michael Hanselmann
  @type fdefs: list of L{objects.QueryFieldDefinition}
2654 ee3aedff Michael Hanselmann

2655 ee3aedff Michael Hanselmann
  """
2656 ee3aedff Michael Hanselmann
  unknown = _GetUnknownFields(fdefs)
2657 ee3aedff Michael Hanselmann
  if unknown:
2658 ee3aedff Michael Hanselmann
    ToStderr("Warning: Queried for unknown fields %s",
2659 ee3aedff Michael Hanselmann
             utils.CommaJoin(fdef.name for fdef in unknown))
2660 ee3aedff Michael Hanselmann
    return True
2661 ee3aedff Michael Hanselmann
2662 ee3aedff Michael Hanselmann
  return False
2663 ee3aedff Michael Hanselmann
2664 ee3aedff Michael Hanselmann
2665 ee3aedff Michael Hanselmann
def GenericList(resource, fields, names, unit, separator, header, cl=None,
2666 2928de47 Michael Hanselmann
                format_override=None, verbose=False, force_filter=False):
2667 ee3aedff Michael Hanselmann
  """Generic implementation for listing all items of a resource.
2668 ee3aedff Michael Hanselmann

2669 abd66bf8 Michael Hanselmann
  @param resource: One of L{constants.QR_VIA_LUXI}
2670 ee3aedff Michael Hanselmann
  @type fields: list of strings
2671 ee3aedff Michael Hanselmann
  @param fields: List of fields to query for
2672 ee3aedff Michael Hanselmann
  @type names: list of strings
2673 ee3aedff Michael Hanselmann
  @param names: Names of items to query for
2674 ee3aedff Michael Hanselmann
  @type unit: string or None
2675 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT} or
2676 ee3aedff Michael Hanselmann
    None for automatic choice (human-readable for non-separator usage,
2677 ee3aedff Michael Hanselmann
    otherwise megabytes); this is a one-letter string
2678 ee3aedff Michael Hanselmann
  @type separator: string or None
2679 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2680 ee3aedff Michael Hanselmann
  @type header: bool
2681 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2682 2928de47 Michael Hanselmann
  @type force_filter: bool
2683 2928de47 Michael Hanselmann
  @param force_filter: Whether to always treat names as filter
2684 ee3aedff Michael Hanselmann
  @type format_override: dict
2685 ee3aedff Michael Hanselmann
  @param format_override: Dictionary for overriding field formatting functions,
2686 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2687 f0b1bafe Iustin Pop
  @type verbose: boolean
2688 f0b1bafe Iustin Pop
  @param verbose: whether to use verbose field descriptions or not
2689 ee3aedff Michael Hanselmann

2690 ee3aedff Michael Hanselmann
  """
2691 ee3aedff Michael Hanselmann
  if not names:
2692 ee3aedff Michael Hanselmann
    names = None
2693 ee3aedff Michael Hanselmann
2694 2e5c33db Iustin Pop
  qfilter = qlang.MakeFilter(names, force_filter)
2695 2928de47 Michael Hanselmann
2696 727274dd Iustin Pop
  if cl is None:
2697 727274dd Iustin Pop
    cl = GetClient()
2698 727274dd Iustin Pop
2699 2e5c33db Iustin Pop
  response = cl.Query(resource, fields, qfilter)
2700 ee3aedff Michael Hanselmann
2701 ee3aedff Michael Hanselmann
  found_unknown = _WarnUnknownFields(response.fields)
2702 ee3aedff Michael Hanselmann
2703 ee3aedff Michael Hanselmann
  (status, data) = FormatQueryResult(response, unit=unit, separator=separator,
2704 ee3aedff Michael Hanselmann
                                     header=header,
2705 f0b1bafe Iustin Pop
                                     format_override=format_override,
2706 f0b1bafe Iustin Pop
                                     verbose=verbose)
2707 ee3aedff Michael Hanselmann
2708 ee3aedff Michael Hanselmann
  for line in data:
2709 ee3aedff Michael Hanselmann
    ToStdout(line)
2710 ee3aedff Michael Hanselmann
2711 ee3aedff Michael Hanselmann
  assert ((found_unknown and status == QR_UNKNOWN) or
2712 ee3aedff Michael Hanselmann
          (not found_unknown and status != QR_UNKNOWN))
2713 ee3aedff Michael Hanselmann
2714 ee3aedff Michael Hanselmann
  if status == QR_UNKNOWN:
2715 ee3aedff Michael Hanselmann
    return constants.EXIT_UNKNOWN_FIELD
2716 ee3aedff Michael Hanselmann
2717 ee3aedff Michael Hanselmann
  # TODO: Should the list command fail if not all data could be collected?
2718 ee3aedff Michael Hanselmann
  return constants.EXIT_SUCCESS
2719 ee3aedff Michael Hanselmann
2720 ee3aedff Michael Hanselmann
2721 ee3aedff Michael Hanselmann
def GenericListFields(resource, fields, separator, header, cl=None):
2722 ee3aedff Michael Hanselmann
  """Generic implementation for listing fields for a resource.
2723 ee3aedff Michael Hanselmann

2724 abd66bf8 Michael Hanselmann
  @param resource: One of L{constants.QR_VIA_LUXI}
2725 ee3aedff Michael Hanselmann
  @type fields: list of strings
2726 ee3aedff Michael Hanselmann
  @param fields: List of fields to query for
2727 ee3aedff Michael Hanselmann
  @type separator: string or None
2728 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2729 ee3aedff Michael Hanselmann
  @type header: bool
2730 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2731 ee3aedff Michael Hanselmann

2732 ee3aedff Michael Hanselmann
  """
2733 ee3aedff Michael Hanselmann
  if cl is None:
2734 ee3aedff Michael Hanselmann
    cl = GetClient()
2735 ee3aedff Michael Hanselmann
2736 ee3aedff Michael Hanselmann
  if not fields:
2737 ee3aedff Michael Hanselmann
    fields = None
2738 ee3aedff Michael Hanselmann
2739 ee3aedff Michael Hanselmann
  response = cl.QueryFields(resource, fields)
2740 ee3aedff Michael Hanselmann
2741 ee3aedff Michael Hanselmann
  found_unknown = _WarnUnknownFields(response.fields)
2742 ee3aedff Michael Hanselmann
2743 ee3aedff Michael Hanselmann
  columns = [
2744 ee3aedff Michael Hanselmann
    TableColumn("Name", str, False),
2745 ee3aedff Michael Hanselmann
    TableColumn("Title", str, False),
2746 ea1440c1 Michael Hanselmann
    TableColumn("Description", str, False),
2747 ee3aedff Michael Hanselmann
    ]
2748 ee3aedff Michael Hanselmann
2749 ea1440c1 Michael Hanselmann
  rows = [[fdef.name, fdef.title, fdef.doc] for fdef in response.fields]
2750 ee3aedff Michael Hanselmann
2751 ee3aedff Michael Hanselmann
  for line in FormatTable(rows, columns, header, separator):
2752 ee3aedff Michael Hanselmann
    ToStdout(line)
2753 ee3aedff Michael Hanselmann
2754 ee3aedff Michael Hanselmann
  if found_unknown:
2755 ee3aedff Michael Hanselmann
    return constants.EXIT_UNKNOWN_FIELD
2756 ee3aedff Michael Hanselmann
2757 ee3aedff Michael Hanselmann
  return constants.EXIT_SUCCESS
2758 ee3aedff Michael Hanselmann
2759 ee3aedff Michael Hanselmann
2760 ee3aedff Michael Hanselmann
class TableColumn:
2761 ee3aedff Michael Hanselmann
  """Describes a column for L{FormatTable}.
2762 ee3aedff Michael Hanselmann

2763 ee3aedff Michael Hanselmann
  """
2764 ee3aedff Michael Hanselmann
  def __init__(self, title, fn, align_right):
2765 ee3aedff Michael Hanselmann
    """Initializes this class.
2766 ee3aedff Michael Hanselmann

2767 ee3aedff Michael Hanselmann
    @type title: string
2768 ee3aedff Michael Hanselmann
    @param title: Column title
2769 ee3aedff Michael Hanselmann
    @type fn: callable
2770 ee3aedff Michael Hanselmann
    @param fn: Formatting function
2771 ee3aedff Michael Hanselmann
    @type align_right: bool
2772 ee3aedff Michael Hanselmann
    @param align_right: Whether to align values on the right-hand side
2773 ee3aedff Michael Hanselmann

2774 ee3aedff Michael Hanselmann
    """
2775 ee3aedff Michael Hanselmann
    self.title = title
2776 ee3aedff Michael Hanselmann
    self.format = fn
2777 ee3aedff Michael Hanselmann
    self.align_right = align_right
2778 ee3aedff Michael Hanselmann
2779 ee3aedff Michael Hanselmann
2780 ee3aedff Michael Hanselmann
def _GetColFormatString(width, align_right):
2781 ee3aedff Michael Hanselmann
  """Returns the format string for a field.
2782 ee3aedff Michael Hanselmann

2783 ee3aedff Michael Hanselmann
  """
2784 ee3aedff Michael Hanselmann
  if align_right:
2785 ee3aedff Michael Hanselmann
    sign = ""
2786 ee3aedff Michael Hanselmann
  else:
2787 ee3aedff Michael Hanselmann
    sign = "-"
2788 ee3aedff Michael Hanselmann
2789 ee3aedff Michael Hanselmann
  return "%%%s%ss" % (sign, width)
2790 ee3aedff Michael Hanselmann
2791 ee3aedff Michael Hanselmann
2792 ee3aedff Michael Hanselmann
def FormatTable(rows, columns, header, separator):
2793 ee3aedff Michael Hanselmann
  """Formats data as a table.
2794 ee3aedff Michael Hanselmann

2795 ee3aedff Michael Hanselmann
  @type rows: list of lists
2796 ee3aedff Michael Hanselmann
  @param rows: Row data, one list per row
2797 ee3aedff Michael Hanselmann
  @type columns: list of L{TableColumn}
2798 ee3aedff Michael Hanselmann
  @param columns: Column descriptions
2799 ee3aedff Michael Hanselmann
  @type header: bool
2800 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2801 ee3aedff Michael Hanselmann
  @type separator: string or None
2802 ee3aedff Michael Hanselmann
  @param separator: String used to separate columns
2803 ee3aedff Michael Hanselmann

2804 ee3aedff Michael Hanselmann
  """
2805 ee3aedff Michael Hanselmann
  if header:
2806 ee3aedff Michael Hanselmann
    data = [[col.title for col in columns]]
2807 ee3aedff Michael Hanselmann
    colwidth = [len(col.title) for col in columns]
2808 ee3aedff Michael Hanselmann
  else:
2809 ee3aedff Michael Hanselmann
    data = []
2810 ee3aedff Michael Hanselmann
    colwidth = [0 for _ in columns]
2811 ee3aedff Michael Hanselmann
2812 ee3aedff Michael Hanselmann
  # Format row data
2813 ee3aedff Michael Hanselmann
  for row in rows:
2814 ee3aedff Michael Hanselmann
    assert len(row) == len(columns)
2815 ee3aedff Michael Hanselmann
2816 ee3aedff Michael Hanselmann
    formatted = [col.format(value) for value, col in zip(row, columns)]
2817 ee3aedff Michael Hanselmann
2818 ee3aedff Michael Hanselmann
    if separator is None:
2819 ee3aedff Michael Hanselmann
      # Update column widths
2820 ee3aedff Michael Hanselmann
      for idx, (oldwidth, value) in enumerate(zip(colwidth, formatted)):
2821 ee3aedff Michael Hanselmann
        # Modifying a list's items while iterating is fine
2822 ee3aedff Michael Hanselmann
        colwidth[idx] = max(oldwidth, len(value))
2823 ee3aedff Michael Hanselmann
2824 ee3aedff Michael Hanselmann
    data.append(formatted)
2825 ee3aedff Michael Hanselmann
2826 ee3aedff Michael Hanselmann
  if separator is not None:
2827 ee3aedff Michael Hanselmann
    # Return early if a separator is used
2828 ee3aedff Michael Hanselmann
    return [separator.join(row) for row in data]
2829 ee3aedff Michael Hanselmann
2830 ee3aedff Michael Hanselmann
  if columns and not columns[-1].align_right:
2831 ee3aedff Michael Hanselmann
    # Avoid unnecessary spaces at end of line
2832 ee3aedff Michael Hanselmann
    colwidth[-1] = 0
2833 ee3aedff Michael Hanselmann
2834 ee3aedff Michael Hanselmann
  # Build format string
2835 ee3aedff Michael Hanselmann
  fmt = " ".join([_GetColFormatString(width, col.align_right)
2836 ee3aedff Michael Hanselmann
                  for col, width in zip(columns, colwidth)])
2837 ee3aedff Michael Hanselmann
2838 ee3aedff Michael Hanselmann
  return [fmt % tuple(row) for row in data]
2839 ee3aedff Michael Hanselmann
2840 ee3aedff Michael Hanselmann
2841 3386e7a9 Iustin Pop
def FormatTimestamp(ts):
2842 3386e7a9 Iustin Pop
  """Formats a given timestamp.
2843 3386e7a9 Iustin Pop

2844 3386e7a9 Iustin Pop
  @type ts: timestamp
2845 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
2846 3386e7a9 Iustin Pop

2847 3386e7a9 Iustin Pop
  @rtype: string
2848 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
2849 3386e7a9 Iustin Pop

2850 3386e7a9 Iustin Pop
  """
2851 e687ec01 Michael Hanselmann
  if not isinstance(ts, (tuple, list)) or len(ts) != 2:
2852 d0c8c01d Iustin Pop
    return "?"
2853 3386e7a9 Iustin Pop
  sec, usec = ts
2854 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
2855 2241e2b9 Iustin Pop
2856 2241e2b9 Iustin Pop
2857 2241e2b9 Iustin Pop
def ParseTimespec(value):
2858 2241e2b9 Iustin Pop
  """Parse a time specification.
2859 2241e2b9 Iustin Pop

2860 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
2861 2241e2b9 Iustin Pop

2862 2241e2b9 Iustin Pop
    - s: seconds
2863 2241e2b9 Iustin Pop
    - m: minutes
2864 2241e2b9 Iustin Pop
    - h: hours
2865 2241e2b9 Iustin Pop
    - d: day
2866 2241e2b9 Iustin Pop
    - w: weeks
2867 2241e2b9 Iustin Pop

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

2870 2241e2b9 Iustin Pop
  """
2871 2241e2b9 Iustin Pop
  value = str(value)
2872 2241e2b9 Iustin Pop
  if not value:
2873 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
2874 2241e2b9 Iustin Pop
  suffix_map = {
2875 d0c8c01d Iustin Pop
    "s": 1,
2876 d0c8c01d Iustin Pop
    "m": 60,
2877 d0c8c01d Iustin Pop
    "h": 3600,
2878 d0c8c01d Iustin Pop
    "d": 86400,
2879 d0c8c01d Iustin Pop
    "w": 604800,
2880 2241e2b9 Iustin Pop
    }
2881 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
2882 2241e2b9 Iustin Pop
    try:
2883 2241e2b9 Iustin Pop
      value = int(value)
2884 691744c4 Iustin Pop
    except (TypeError, ValueError):
2885 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2886 2241e2b9 Iustin Pop
  else:
2887 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
2888 2241e2b9 Iustin Pop
    value = value[:-1]
2889 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
2890 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
2891 2241e2b9 Iustin Pop
                                 " suffix passed)")
2892 2241e2b9 Iustin Pop
    try:
2893 2241e2b9 Iustin Pop
      value = int(value) * multiplier
2894 691744c4 Iustin Pop
    except (TypeError, ValueError):
2895 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2896 2241e2b9 Iustin Pop
  return value
2897 46fbdd04 Iustin Pop
2898 46fbdd04 Iustin Pop
2899 e9e26bb3 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False, secondary_ips=False,
2900 05484a24 Michael Hanselmann
                   filter_master=False, nodegroup=None):
2901 4040a784 Iustin Pop
  """Returns the names of online nodes.
2902 4040a784 Iustin Pop

2903 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
2904 4040a784 Iustin Pop
  the online nodes.
2905 4040a784 Iustin Pop

2906 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
2907 4040a784 Iustin Pop
      offline ones)
2908 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
2909 4040a784 Iustin Pop
  @type nowarn: boolean
2910 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
2911 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
2912 4040a784 Iustin Pop
      note is not displayed
2913 e9e26bb3 Iustin Pop
  @type secondary_ips: boolean
2914 e9e26bb3 Iustin Pop
  @param secondary_ips: if True, return the secondary IPs instead of the
2915 e9e26bb3 Iustin Pop
      names, useful for doing network traffic over the replication interface
2916 e9e26bb3 Iustin Pop
      (if any)
2917 e9e26bb3 Iustin Pop
  @type filter_master: boolean
2918 e9e26bb3 Iustin Pop
  @param filter_master: if True, do not return the master node in the list
2919 e9e26bb3 Iustin Pop
      (useful in coordination with secondary_ips where we cannot check our
2920 e9e26bb3 Iustin Pop
      node name against the list)
2921 05484a24 Michael Hanselmann
  @type nodegroup: string
2922 05484a24 Michael Hanselmann
  @param nodegroup: If set, only return nodes in this node group
2923 4040a784 Iustin Pop

2924 4040a784 Iustin Pop
  """
2925 4040a784 Iustin Pop
  if cl is None:
2926 4040a784 Iustin Pop
    cl = GetClient()
2927 4040a784 Iustin Pop
2928 2e5c33db Iustin Pop
  qfilter = []
2929 05484a24 Michael Hanselmann
2930 05484a24 Michael Hanselmann
  if nodes:
2931 2e5c33db Iustin Pop
    qfilter.append(qlang.MakeSimpleFilter("name", nodes))
2932 05484a24 Michael Hanselmann
2933 05484a24 Michael Hanselmann
  if nodegroup is not None:
2934 2e5c33db Iustin Pop
    qfilter.append([qlang.OP_OR, [qlang.OP_EQUAL, "group", nodegroup],
2935 05484a24 Michael Hanselmann
                                 [qlang.OP_EQUAL, "group.uuid", nodegroup]])
2936 e9e26bb3 Iustin Pop
2937 e9e26bb3 Iustin Pop
  if filter_master:
2938 2e5c33db Iustin Pop
    qfilter.append([qlang.OP_NOT, [qlang.OP_TRUE, "master"]])
2939 05484a24 Michael Hanselmann
2940 2e5c33db Iustin Pop
  if qfilter:
2941 2e5c33db Iustin Pop
    if len(qfilter) > 1:
2942 2e5c33db Iustin Pop
      final_filter = [qlang.OP_AND] + qfilter
2943 05484a24 Michael Hanselmann
    else:
2944 2e5c33db Iustin Pop
      assert len(qfilter) == 1
2945 2e5c33db Iustin Pop
      final_filter = qfilter[0]
2946 e9e26bb3 Iustin Pop
  else:
2947 05484a24 Michael Hanselmann
    final_filter = None
2948 05484a24 Michael Hanselmann
2949 05484a24 Michael Hanselmann
  result = cl.Query(constants.QR_NODE, ["name", "offline", "sip"], final_filter)
2950 05484a24 Michael Hanselmann
2951 05484a24 Michael Hanselmann
  def _IsOffline(row):
2952 05484a24 Michael Hanselmann
    (_, (_, offline), _) = row
2953 05484a24 Michael Hanselmann
    return offline
2954 05484a24 Michael Hanselmann
2955 05484a24 Michael Hanselmann
  def _GetName(row):
2956 05484a24 Michael Hanselmann
    ((_, name), _, _) = row
2957 05484a24 Michael Hanselmann
    return name
2958 05484a24 Michael Hanselmann
2959 05484a24 Michael Hanselmann
  def _GetSip(row):
2960 05484a24 Michael Hanselmann
    (_, _, (_, sip)) = row
2961 05484a24 Michael Hanselmann
    return sip
2962 05484a24 Michael Hanselmann
2963 05484a24 Michael Hanselmann
  (offline, online) = compat.partition(result.data, _IsOffline)
2964 e9e26bb3 Iustin Pop
2965 4040a784 Iustin Pop
  if offline and not nowarn:
2966 05484a24 Michael Hanselmann
    ToStderr("Note: skipping offline node(s): %s" %
2967 05484a24 Michael Hanselmann
             utils.CommaJoin(map(_GetName, offline)))
2968 05484a24 Michael Hanselmann
2969 05484a24 Michael Hanselmann
  if secondary_ips:
2970 05484a24 Michael Hanselmann
    fn = _GetSip
2971 05484a24 Michael Hanselmann
  else:
2972 05484a24 Michael Hanselmann
    fn = _GetName
2973 05484a24 Michael Hanselmann
2974 05484a24 Michael Hanselmann
  return map(fn, online)
2975 4040a784 Iustin Pop
2976 4040a784 Iustin Pop
2977 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
2978 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
2979 46fbdd04 Iustin Pop

2980 46fbdd04 Iustin Pop
  @type stream: file object
2981 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
2982 46fbdd04 Iustin Pop
  @type txt: str
2983 46fbdd04 Iustin Pop
  @param txt: the message
2984 46fbdd04 Iustin Pop

2985 46fbdd04 Iustin Pop
  """
2986 225e2544 Iustin Pop
  try:
2987 225e2544 Iustin Pop
    if args:
2988 225e2544 Iustin Pop
      args = tuple(args)
2989 225e2544 Iustin Pop
      stream.write(txt % args)
2990 225e2544 Iustin Pop
    else:
2991 225e2544 Iustin Pop
      stream.write(txt)
2992 d0c8c01d Iustin Pop
    stream.write("\n")
2993 225e2544 Iustin Pop
    stream.flush()
2994 225e2544 Iustin Pop
  except IOError, err:
2995 225e2544 Iustin Pop
    if err.errno == errno.EPIPE:
2996 225e2544 Iustin Pop
      # our terminal went away, we'll exit
2997 225e2544 Iustin Pop
      sys.exit(constants.EXIT_FAILURE)
2998 225e2544 Iustin Pop
    else:
2999 225e2544 Iustin Pop
      raise
3000 46fbdd04 Iustin Pop
3001 46fbdd04 Iustin Pop
3002 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
3003 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
3004 46fbdd04 Iustin Pop

3005 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
3006 46fbdd04 Iustin Pop

3007 46fbdd04 Iustin Pop
  @type txt: str
3008 46fbdd04 Iustin Pop
  @param txt: the message
3009 46fbdd04 Iustin Pop

3010 46fbdd04 Iustin Pop
  """
3011 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
3012 46fbdd04 Iustin Pop
3013 46fbdd04 Iustin Pop
3014 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
3015 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
3016 46fbdd04 Iustin Pop

3017 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
3018 46fbdd04 Iustin Pop

3019 46fbdd04 Iustin Pop
  @type txt: str
3020 46fbdd04 Iustin Pop
  @param txt: the message
3021 46fbdd04 Iustin Pop

3022 46fbdd04 Iustin Pop
  """
3023 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
3024 479636a3 Iustin Pop
3025 479636a3 Iustin Pop
3026 479636a3 Iustin Pop
class JobExecutor(object):
3027 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
3028 479636a3 Iustin Pop

3029 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
3030 479636a3 Iustin Pop
  GetResults() calls.
3031 479636a3 Iustin Pop

3032 479636a3 Iustin Pop
  """
3033 919ca415 Iustin Pop
  def __init__(self, cl=None, verbose=True, opts=None, feedback_fn=None):
3034 479636a3 Iustin Pop
    self.queue = []
3035 479636a3 Iustin Pop
    if cl is None:
3036 479636a3 Iustin Pop
      cl = GetClient()
3037 479636a3 Iustin Pop
    self.cl = cl
3038 479636a3 Iustin Pop
    self.verbose = verbose
3039 23b4b983 Iustin Pop
    self.jobs = []
3040 cff5fa7f Iustin Pop
    self.opts = opts
3041 919ca415 Iustin Pop
    self.feedback_fn = feedback_fn
3042 60452edf Michael Hanselmann
    self._counter = itertools.count()
3043 479636a3 Iustin Pop
3044 8d99a8bf Michael Hanselmann
  @staticmethod
3045 8d99a8bf Michael Hanselmann
  def _IfName(name, fmt):
3046 8d99a8bf Michael Hanselmann
    """Helper function for formatting name.
3047 8d99a8bf Michael Hanselmann

3048 8d99a8bf Michael Hanselmann
    """
3049 8d99a8bf Michael Hanselmann
    if name:
3050 8d99a8bf Michael Hanselmann
      return fmt % name
3051 8d99a8bf Michael Hanselmann
3052 8d99a8bf Michael Hanselmann
    return ""
3053 8d99a8bf Michael Hanselmann
3054 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
3055 23b4b983 Iustin Pop
    """Record a job for later submit.
3056 479636a3 Iustin Pop

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

3060 479636a3 Iustin Pop
    """
3061 cff5fa7f Iustin Pop
    SetGenericOpcodeOpts(ops, self.opts)
3062 60452edf Michael Hanselmann
    self.queue.append((self._counter.next(), name, ops))
3063 23b4b983 Iustin Pop
3064 8d99a8bf Michael Hanselmann
  def AddJobId(self, name, status, job_id):
3065 8d99a8bf Michael Hanselmann
    """Adds a job ID to the internal queue.
3066 8d99a8bf Michael Hanselmann

3067 8d99a8bf Michael Hanselmann
    """
3068 8d99a8bf Michael Hanselmann
    self.jobs.append((self._counter.next(), status, job_id, name))
3069 8d99a8bf Michael Hanselmann
3070 66ecc479 Guido Trotter
  def SubmitPending(self, each=False):
3071 23b4b983 Iustin Pop
    """Submit all pending jobs.
3072 23b4b983 Iustin Pop

3073 23b4b983 Iustin Pop
    """
3074 66ecc479 Guido Trotter
    if each:
3075 66ecc479 Guido Trotter
      results = []
3076 60452edf Michael Hanselmann
      for (_, _, ops) in self.queue:
3077 66ecc479 Guido Trotter
        # SubmitJob will remove the success status, but raise an exception if
3078 66ecc479 Guido Trotter
        # the submission fails, so we'll notice that anyway.
3079 60452edf Michael Hanselmann
        results.append([True, self.cl.SubmitJob(ops)])
3080 66ecc479 Guido Trotter
    else:
3081 60452edf Michael Hanselmann
      results = self.cl.SubmitManyJobs([ops for (_, _, ops) in self.queue])
3082 60452edf Michael Hanselmann
    for ((status, data), (idx, name, _)) in zip(results, self.queue):
3083 5299e61f Iustin Pop
      self.jobs.append((idx, status, data, name))
3084 5299e61f Iustin Pop
3085 5299e61f Iustin Pop
  def _ChooseJob(self):
3086 5299e61f Iustin Pop
    """Choose a non-waiting/queued job to poll next.
3087 5299e61f Iustin Pop

3088 5299e61f Iustin Pop
    """
3089 5299e61f Iustin Pop
    assert self.jobs, "_ChooseJob called with empty job list"
3090 5299e61f Iustin Pop
3091 11705e3d Iustin Pop
    result = self.cl.QueryJobs([i[2] for i in self.jobs[:_CHOOSE_BATCH]],
3092 11705e3d Iustin Pop
                               ["status"])
3093 5299e61f Iustin Pop
    assert result
3094 5299e61f Iustin Pop
3095 5299e61f Iustin Pop
    for job_data, status in zip(self.jobs, result):
3096 91c622a8 Iustin Pop
      if (isinstance(status, list) and status and
3097 91c622a8 Iustin Pop
          status[0] in (constants.JOB_STATUS_QUEUED,
3098 47099cd1 Michael Hanselmann
                        constants.JOB_STATUS_WAITING,
3099 91c622a8 Iustin Pop
                        constants.JOB_STATUS_CANCELING)):
3100 91c622a8 Iustin Pop
        # job is still present and waiting
3101 5299e61f Iustin Pop
        continue
3102 91c622a8 Iustin Pop
      # good candidate found (either running job or lost job)
3103 5299e61f Iustin Pop
      self.jobs.remove(job_data)
3104 5299e61f Iustin Pop
      return job_data
3105 5299e61f Iustin Pop
3106 5299e61f Iustin Pop
    # no job found
3107 5299e61f Iustin Pop
    return self.jobs.pop(0)
3108 479636a3 Iustin Pop
3109 479636a3 Iustin Pop
  def GetResults(self):
3110 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
3111 479636a3 Iustin Pop

3112 479636a3 Iustin Pop
    @rtype: list
3113 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
3114 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
3115 479636a3 Iustin Pop
        there will be the error message
3116 479636a3 Iustin Pop

3117 479636a3 Iustin Pop
    """
3118 23b4b983 Iustin Pop
    if not self.jobs:
3119 23b4b983 Iustin Pop
      self.SubmitPending()
3120 479636a3 Iustin Pop
    results = []
3121 479636a3 Iustin Pop
    if self.verbose:
3122 5299e61f Iustin Pop
      ok_jobs = [row[2] for row in self.jobs if row[1]]
3123 23b4b983 Iustin Pop
      if ok_jobs:
3124 4474f112 Iustin Pop
        ToStdout("Submitted jobs %s", utils.CommaJoin(ok_jobs))
3125 5299e61f Iustin Pop
3126 5299e61f Iustin Pop
    # first, remove any non-submitted jobs
3127 cea881e5 Michael Hanselmann
    self.jobs, failures = compat.partition(self.jobs, lambda x: x[1])
3128 5299e61f Iustin Pop
    for idx, _, jid, name in failures:
3129 4474f112 Iustin Pop
      ToStderr("Failed to submit job%s: %s", self._IfName(name, " for %s"), jid)
3130 c63355f2 Iustin Pop
      results.append((idx, False, jid))
3131 5299e61f Iustin Pop
3132 5299e61f Iustin Pop
    while self.jobs:
3133 5299e61f Iustin Pop
      (idx, _, jid, name) = self._ChooseJob()
3134 4474f112 Iustin Pop
      ToStdout("Waiting for job %s%s ...", jid, self._IfName(name, " for %s"))
3135 479636a3 Iustin Pop
      try:
3136 919ca415 Iustin Pop
        job_result = PollJob(jid, cl=self.cl, feedback_fn=self.feedback_fn)
3137 479636a3 Iustin Pop
        success = True
3138 91c622a8 Iustin Pop
      except errors.JobLost, err:
3139 91c622a8 Iustin Pop
        _, job_result = FormatError(err)
3140 4474f112 Iustin Pop
        ToStderr("Job %s%s has been archived, cannot check its result",
3141 4474f112 Iustin Pop
                 jid, self._IfName(name, " for %s"))
3142 91c622a8 Iustin Pop
        success = False
3143 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
3144 479636a3 Iustin Pop
        _, job_result = FormatError(err)
3145 479636a3 Iustin Pop
        success = False
3146 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
3147 4474f112 Iustin Pop
        ToStderr("Job %s%s has failed: %s",
3148 4474f112 Iustin Pop
                 jid, self._IfName(name, " for %s"), job_result)
3149 479636a3 Iustin Pop
3150 5299e61f Iustin Pop
      results.append((idx, success, job_result))
3151 5299e61f Iustin Pop
3152 5299e61f Iustin Pop
    # sort based on the index, then drop it
3153 5299e61f Iustin Pop
    results.sort()
3154 5299e61f Iustin Pop
    results = [i[1:] for i in results]
3155 5299e61f Iustin Pop
3156 479636a3 Iustin Pop
    return results
3157 479636a3 Iustin Pop
3158 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
3159 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
3160 479636a3 Iustin Pop

3161 479636a3 Iustin Pop
    @type wait: boolean
3162 479636a3 Iustin Pop
    @param wait: whether to wait or not
3163 479636a3 Iustin Pop

3164 479636a3 Iustin Pop
    """
3165 479636a3 Iustin Pop
    if wait:
3166 479636a3 Iustin Pop
      return self.GetResults()
3167 479636a3 Iustin Pop
    else:
3168 23b4b983 Iustin Pop
      if not self.jobs:
3169 23b4b983 Iustin Pop
        self.SubmitPending()
3170 71834b2a Guido Trotter
      for _, status, result, name in self.jobs:
3171 23b4b983 Iustin Pop
        if status:
3172 4474f112 Iustin Pop
          ToStdout("%s: %s", result, name)
3173 23b4b983 Iustin Pop
        else:
3174 4474f112 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)
3175 53a8a54d Iustin Pop
      return [row[1:3] for row in self.jobs]
3176 acd19189 René Nussbaumer
3177 acd19189 René Nussbaumer
3178 acd19189 René Nussbaumer
def FormatParameterDict(buf, param_dict, actual, level=1):
3179 acd19189 René Nussbaumer
  """Formats a parameter dictionary.
3180 acd19189 René Nussbaumer

3181 acd19189 René Nussbaumer
  @type buf: L{StringIO}
3182 acd19189 René Nussbaumer
  @param buf: the buffer into which to write
3183 acd19189 René Nussbaumer
  @type param_dict: dict
3184 acd19189 René Nussbaumer
  @param param_dict: the own parameters
3185 acd19189 René Nussbaumer
  @type actual: dict
3186 acd19189 René Nussbaumer
  @param actual: the current parameter set (including defaults)
3187 acd19189 René Nussbaumer
  @param level: Level of indent
3188 acd19189 René Nussbaumer

3189 acd19189 René Nussbaumer
  """
3190 acd19189 René Nussbaumer
  indent = "  " * level
3191 acd19189 René Nussbaumer
  for key in sorted(actual):
3192 acd19189 René Nussbaumer
    val = param_dict.get(key, "default (%s)" % actual[key])
3193 acd19189 René Nussbaumer
    buf.write("%s- %s: %s\n" % (indent, key, val))
3194 25bd815c René Nussbaumer
3195 25bd815c René Nussbaumer
3196 25bd815c René Nussbaumer
def ConfirmOperation(names, list_type, text, extra=""):
3197 25bd815c René Nussbaumer
  """Ask the user to confirm an operation on a list of list_type.
3198 25bd815c René Nussbaumer

3199 25bd815c René Nussbaumer
  This function is used to request confirmation for doing an operation
3200 25bd815c René Nussbaumer
  on a given list of list_type.
3201 25bd815c René Nussbaumer

3202 25bd815c René Nussbaumer
  @type names: list
3203 25bd815c René Nussbaumer
  @param names: the list of names that we display when
3204 25bd815c René Nussbaumer
      we ask for confirmation
3205 25bd815c René Nussbaumer
  @type list_type: str
3206 25bd815c René Nussbaumer
  @param list_type: Human readable name for elements in the list (e.g. nodes)
3207 25bd815c René Nussbaumer
  @type text: str
3208 25bd815c René Nussbaumer
  @param text: the operation that the user should confirm
3209 25bd815c René Nussbaumer
  @rtype: boolean
3210 25bd815c René Nussbaumer
  @return: True or False depending on user's confirmation.
3211 25bd815c René Nussbaumer

3212 25bd815c René Nussbaumer
  """
3213 25bd815c René Nussbaumer
  count = len(names)
3214 25bd815c René Nussbaumer
  msg = ("The %s will operate on %d %s.\n%s"
3215 25bd815c René Nussbaumer
         "Do you want to continue?" % (text, count, list_type, extra))
3216 25bd815c René Nussbaumer
  affected = (("\nAffected %s:\n" % list_type) +
3217 25bd815c René Nussbaumer
              "\n".join(["  %s" % name for name in names]))
3218 25bd815c René Nussbaumer
3219 25bd815c René Nussbaumer
  choices = [("y", True, "Yes, execute the %s" % text),
3220 25bd815c René Nussbaumer
             ("n", False, "No, abort the %s" % text)]
3221 25bd815c René Nussbaumer
3222 25bd815c René Nussbaumer
  if count > 20:
3223 25bd815c René Nussbaumer
    choices.insert(1, ("v", "v", "View the list of affected %s" % list_type))
3224 25bd815c René Nussbaumer
    question = msg
3225 25bd815c René Nussbaumer
  else:
3226 25bd815c René Nussbaumer
    question = msg + affected
3227 25bd815c René Nussbaumer
3228 25bd815c René Nussbaumer
  choice = AskUser(question, choices)
3229 25bd815c René Nussbaumer
  if choice == "v":
3230 25bd815c René Nussbaumer
    choices.pop(1)
3231 25bd815c René Nussbaumer
    choice = AskUser(msg + affected, choices)
3232 25bd815c René Nussbaumer
  return choice