Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ 7142485a

History | View | Annotate | Download (109.9 kB)

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

300 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor.
301 863d7f46 Michael Hanselmann

302 863d7f46 Michael Hanselmann
  """
303 b459a848 Andrea Spadaccini
  # pylint: disable=W0622
304 863d7f46 Michael Hanselmann
  def __init__(self, min=0, max=None, choices=None):
305 863d7f46 Michael Hanselmann
    _Argument.__init__(self, min=min, max=max)
306 863d7f46 Michael Hanselmann
    self.choices = choices
307 863d7f46 Michael Hanselmann
308 863d7f46 Michael Hanselmann
  def __repr__(self):
309 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s choices=%r>" %
310 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max, self.choices))
311 863d7f46 Michael Hanselmann
312 863d7f46 Michael Hanselmann
313 863d7f46 Michael Hanselmann
class ArgChoice(ArgSuggest):
314 863d7f46 Michael Hanselmann
  """Choice argument.
315 863d7f46 Michael Hanselmann

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

319 863d7f46 Michael Hanselmann
  """
320 863d7f46 Michael Hanselmann
321 863d7f46 Michael Hanselmann
322 863d7f46 Michael Hanselmann
class ArgUnknown(_Argument):
323 863d7f46 Michael Hanselmann
  """Unknown argument to program (e.g. determined at runtime).
324 863d7f46 Michael Hanselmann

325 863d7f46 Michael Hanselmann
  """
326 863d7f46 Michael Hanselmann
327 863d7f46 Michael Hanselmann
328 863d7f46 Michael Hanselmann
class ArgInstance(_Argument):
329 863d7f46 Michael Hanselmann
  """Instances argument.
330 863d7f46 Michael Hanselmann

331 863d7f46 Michael Hanselmann
  """
332 863d7f46 Michael Hanselmann
333 863d7f46 Michael Hanselmann
334 863d7f46 Michael Hanselmann
class ArgNode(_Argument):
335 863d7f46 Michael Hanselmann
  """Node argument.
336 863d7f46 Michael Hanselmann

337 863d7f46 Michael Hanselmann
  """
338 863d7f46 Michael Hanselmann
339 667dbd6b Adeodato Simo
340 667dbd6b Adeodato Simo
class ArgGroup(_Argument):
341 667dbd6b Adeodato Simo
  """Node group argument.
342 667dbd6b Adeodato Simo

343 667dbd6b Adeodato Simo
  """
344 667dbd6b Adeodato Simo
345 667dbd6b Adeodato Simo
346 863d7f46 Michael Hanselmann
class ArgJobId(_Argument):
347 863d7f46 Michael Hanselmann
  """Job ID argument.
348 863d7f46 Michael Hanselmann

349 863d7f46 Michael Hanselmann
  """
350 863d7f46 Michael Hanselmann
351 863d7f46 Michael Hanselmann
352 863d7f46 Michael Hanselmann
class ArgFile(_Argument):
353 863d7f46 Michael Hanselmann
  """File path argument.
354 863d7f46 Michael Hanselmann

355 863d7f46 Michael Hanselmann
  """
356 863d7f46 Michael Hanselmann
357 863d7f46 Michael Hanselmann
358 863d7f46 Michael Hanselmann
class ArgCommand(_Argument):
359 863d7f46 Michael Hanselmann
  """Command argument.
360 863d7f46 Michael Hanselmann

361 863d7f46 Michael Hanselmann
  """
362 863d7f46 Michael Hanselmann
363 863d7f46 Michael Hanselmann
364 83ec7961 Michael Hanselmann
class ArgHost(_Argument):
365 83ec7961 Michael Hanselmann
  """Host argument.
366 83ec7961 Michael Hanselmann

367 83ec7961 Michael Hanselmann
  """
368 83ec7961 Michael Hanselmann
369 83ec7961 Michael Hanselmann
370 f9faf9c3 René Nussbaumer
class ArgOs(_Argument):
371 f9faf9c3 René Nussbaumer
  """OS argument.
372 f9faf9c3 René Nussbaumer

373 f9faf9c3 René Nussbaumer
  """
374 f9faf9c3 René Nussbaumer
375 f9faf9c3 René Nussbaumer
376 4a265c08 Michael Hanselmann
ARGS_NONE = []
377 4a265c08 Michael Hanselmann
ARGS_MANY_INSTANCES = [ArgInstance()]
378 4a265c08 Michael Hanselmann
ARGS_MANY_NODES = [ArgNode()]
379 667dbd6b Adeodato Simo
ARGS_MANY_GROUPS = [ArgGroup()]
380 4a265c08 Michael Hanselmann
ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
381 4a265c08 Michael Hanselmann
ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
382 dadf6b7d Michael Hanselmann
# TODO
383 dadf6b7d Michael Hanselmann
ARGS_ONE_GROUP = [ArgGroup(min=1, max=1)]
384 f9faf9c3 René Nussbaumer
ARGS_ONE_OS = [ArgOs(min=1, max=1)]
385 4a265c08 Michael Hanselmann
386 4a265c08 Michael Hanselmann
387 846baef9 Iustin Pop
def _ExtractTagsObject(opts, args):
388 846baef9 Iustin Pop
  """Extract the tag type object.
389 846baef9 Iustin Pop

390 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
391 846baef9 Iustin Pop

392 846baef9 Iustin Pop
  """
393 846baef9 Iustin Pop
  if not hasattr(opts, "tag_type"):
394 846baef9 Iustin Pop
    raise errors.ProgrammerError("tag_type not passed to _ExtractTagsObject")
395 846baef9 Iustin Pop
  kind = opts.tag_type
396 846baef9 Iustin Pop
  if kind == constants.TAG_CLUSTER:
397 846baef9 Iustin Pop
    retval = kind, kind
398 819cbfe5 Michael Hanselmann
  elif kind in (constants.TAG_NODEGROUP,
399 819cbfe5 Michael Hanselmann
                constants.TAG_NODE,
400 819cbfe5 Michael Hanselmann
                constants.TAG_INSTANCE):
401 846baef9 Iustin Pop
    if not args:
402 0c434948 Iustin Pop
      raise errors.OpPrereqError("no arguments passed to the command")
403 846baef9 Iustin Pop
    name = args.pop(0)
404 846baef9 Iustin Pop
    retval = kind, name
405 846baef9 Iustin Pop
  else:
406 846baef9 Iustin Pop
    raise errors.ProgrammerError("Unhandled tag type '%s'" % kind)
407 846baef9 Iustin Pop
  return retval
408 846baef9 Iustin Pop
409 846baef9 Iustin Pop
410 810c50b7 Iustin Pop
def _ExtendTags(opts, args):
411 810c50b7 Iustin Pop
  """Extend the args if a source file has been given.
412 810c50b7 Iustin Pop

413 810c50b7 Iustin Pop
  This function will extend the tags with the contents of the file
414 810c50b7 Iustin Pop
  passed in the 'tags_source' attribute of the opts parameter. A file
415 810c50b7 Iustin Pop
  named '-' will be replaced by stdin.
416 810c50b7 Iustin Pop

417 810c50b7 Iustin Pop
  """
418 810c50b7 Iustin Pop
  fname = opts.tags_source
419 810c50b7 Iustin Pop
  if fname is None:
420 810c50b7 Iustin Pop
    return
421 810c50b7 Iustin Pop
  if fname == "-":
422 810c50b7 Iustin Pop
    new_fh = sys.stdin
423 810c50b7 Iustin Pop
  else:
424 810c50b7 Iustin Pop
    new_fh = open(fname, "r")
425 810c50b7 Iustin Pop
  new_data = []
426 810c50b7 Iustin Pop
  try:
427 810c50b7 Iustin Pop
    # we don't use the nice 'new_data = [line.strip() for line in fh]'
428 810c50b7 Iustin Pop
    # because of python bug 1633941
429 810c50b7 Iustin Pop
    while True:
430 810c50b7 Iustin Pop
      line = new_fh.readline()
431 810c50b7 Iustin Pop
      if not line:
432 810c50b7 Iustin Pop
        break
433 810c50b7 Iustin Pop
      new_data.append(line.strip())
434 810c50b7 Iustin Pop
  finally:
435 810c50b7 Iustin Pop
    new_fh.close()
436 810c50b7 Iustin Pop
  args.extend(new_data)
437 810c50b7 Iustin Pop
438 810c50b7 Iustin Pop
439 846baef9 Iustin Pop
def ListTags(opts, args):
440 846baef9 Iustin Pop
  """List the 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 7699c3af Iustin Pop
  cl = GetClient()
450 7699c3af Iustin Pop
  result = cl.QueryTags(kind, name)
451 846baef9 Iustin Pop
  result = list(result)
452 846baef9 Iustin Pop
  result.sort()
453 846baef9 Iustin Pop
  for tag in result:
454 03298ebe Michael Hanselmann
    ToStdout(tag)
455 846baef9 Iustin Pop
456 846baef9 Iustin Pop
457 846baef9 Iustin Pop
def AddTags(opts, args):
458 846baef9 Iustin Pop
  """Add tags on a given object.
459 846baef9 Iustin Pop

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

465 846baef9 Iustin Pop
  """
466 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
467 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
468 846baef9 Iustin Pop
  if not args:
469 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be added")
470 d1602edc Iustin Pop
  op = opcodes.OpTagsSet(kind=kind, name=name, tags=args)
471 af1a81d1 Michael Hanselmann
  SubmitOpCode(op, opts=opts)
472 846baef9 Iustin Pop
473 846baef9 Iustin Pop
474 846baef9 Iustin Pop
def RemoveTags(opts, args):
475 846baef9 Iustin Pop
  """Remove tags from a given object.
476 846baef9 Iustin Pop

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

482 846baef9 Iustin Pop
  """
483 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
484 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
485 846baef9 Iustin Pop
  if not args:
486 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be removed")
487 3f0ab95f Iustin Pop
  op = opcodes.OpTagsDel(kind=kind, name=name, tags=args)
488 af1a81d1 Michael Hanselmann
  SubmitOpCode(op, opts=opts)
489 846baef9 Iustin Pop
490 a8083063 Iustin Pop
491 b459a848 Andrea Spadaccini
def check_unit(option, opt, value): # pylint: disable=W0613
492 65fe4693 Iustin Pop
  """OptParsers custom converter for units.
493 65fe4693 Iustin Pop

494 65fe4693 Iustin Pop
  """
495 a8083063 Iustin Pop
  try:
496 a8083063 Iustin Pop
    return utils.ParseUnit(value)
497 a8083063 Iustin Pop
  except errors.UnitParseError, err:
498 3ecf6786 Iustin Pop
    raise OptionValueError("option %s: %s" % (opt, err))
499 a8083063 Iustin Pop
500 a8083063 Iustin Pop
501 a8469393 Iustin Pop
def _SplitKeyVal(opt, data):
502 a8469393 Iustin Pop
  """Convert a KeyVal string into a dict.
503 a8469393 Iustin Pop

504 a8469393 Iustin Pop
  This function will convert a key=val[,...] string into a dict. Empty
505 a8469393 Iustin Pop
  values will be converted specially: keys which have the prefix 'no_'
506 a8469393 Iustin Pop
  will have the value=False and the prefix stripped, the others will
507 a8469393 Iustin Pop
  have value=True.
508 a8469393 Iustin Pop

509 a8469393 Iustin Pop
  @type opt: string
510 a8469393 Iustin Pop
  @param opt: a string holding the option name for which we process the
511 a8469393 Iustin Pop
      data, used in building error messages
512 a8469393 Iustin Pop
  @type data: string
513 a8469393 Iustin Pop
  @param data: a string of the format key=val,key=val,...
514 a8469393 Iustin Pop
  @rtype: dict
515 a8469393 Iustin Pop
  @return: {key=val, key=val}
516 a8469393 Iustin Pop
  @raises errors.ParameterError: if there are duplicate keys
517 a8469393 Iustin Pop

518 a8469393 Iustin Pop
  """
519 a8469393 Iustin Pop
  kv_dict = {}
520 4f31882e Guido Trotter
  if data:
521 1b3a7656 Iustin Pop
    for elem in utils.UnescapeAndSplit(data, sep=","):
522 4f31882e Guido Trotter
      if "=" in elem:
523 4f31882e Guido Trotter
        key, val = elem.split("=", 1)
524 a8469393 Iustin Pop
      else:
525 4f31882e Guido Trotter
        if elem.startswith(NO_PREFIX):
526 4f31882e Guido Trotter
          key, val = elem[len(NO_PREFIX):], False
527 4f31882e Guido Trotter
        elif elem.startswith(UN_PREFIX):
528 4f31882e Guido Trotter
          key, val = elem[len(UN_PREFIX):], None
529 4f31882e Guido Trotter
        else:
530 4f31882e Guido Trotter
          key, val = elem, True
531 4f31882e Guido Trotter
      if key in kv_dict:
532 4f31882e Guido Trotter
        raise errors.ParameterError("Duplicate key '%s' in option %s" %
533 4f31882e Guido Trotter
                                    (key, opt))
534 4f31882e Guido Trotter
      kv_dict[key] = val
535 a8469393 Iustin Pop
  return kv_dict
536 a8469393 Iustin Pop
537 a8469393 Iustin Pop
538 b459a848 Andrea Spadaccini
def check_ident_key_val(option, opt, value):  # pylint: disable=W0613
539 552c8dff Michael Hanselmann
  """Custom parser for ident:key=val,key=val options.
540 552c8dff Michael Hanselmann

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

544 a8469393 Iustin Pop
  """
545 a8469393 Iustin Pop
  if ":" not in value:
546 d0c8c01d Iustin Pop
    ident, rest = value, ""
547 a8469393 Iustin Pop
  else:
548 a8469393 Iustin Pop
    ident, rest = value.split(":", 1)
549 8b46606c Guido Trotter
550 8b46606c Guido Trotter
  if ident.startswith(NO_PREFIX):
551 8b46606c Guido Trotter
    if rest:
552 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
553 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
554 8b46606c Guido Trotter
    retval = (ident[len(NO_PREFIX):], False)
555 956631b6 Michael Hanselmann
  elif (ident.startswith(UN_PREFIX) and
556 956631b6 Michael Hanselmann
        (len(ident) <= len(UN_PREFIX) or
557 956631b6 Michael Hanselmann
         not ident[len(UN_PREFIX)][0].isdigit())):
558 8b46606c Guido Trotter
    if rest:
559 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
560 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
561 8b46606c Guido Trotter
    retval = (ident[len(UN_PREFIX):], None)
562 8b46606c Guido Trotter
  else:
563 a8469393 Iustin Pop
    kv_dict = _SplitKeyVal(opt, rest)
564 a8469393 Iustin Pop
    retval = (ident, kv_dict)
565 a8469393 Iustin Pop
  return retval
566 a8469393 Iustin Pop
567 a8469393 Iustin Pop
568 b459a848 Andrea Spadaccini
def check_key_val(option, opt, value):  # pylint: disable=W0613
569 552c8dff Michael Hanselmann
  """Custom parser class for key=val,key=val options.
570 552c8dff Michael Hanselmann

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

573 a8469393 Iustin Pop
  """
574 a8469393 Iustin Pop
  return _SplitKeyVal(opt, value)
575 a8469393 Iustin Pop
576 a8469393 Iustin Pop
577 b459a848 Andrea Spadaccini
def check_bool(option, opt, value): # pylint: disable=W0613
578 e7b61bb0 Iustin Pop
  """Custom parser for yes/no options.
579 e7b61bb0 Iustin Pop

580 e7b61bb0 Iustin Pop
  This will store the parsed value as either True or False.
581 e7b61bb0 Iustin Pop

582 e7b61bb0 Iustin Pop
  """
583 e7b61bb0 Iustin Pop
  value = value.lower()
584 e7b61bb0 Iustin Pop
  if value == constants.VALUE_FALSE or value == "no":
585 e7b61bb0 Iustin Pop
    return False
586 e7b61bb0 Iustin Pop
  elif value == constants.VALUE_TRUE or value == "yes":
587 e7b61bb0 Iustin Pop
    return True
588 e7b61bb0 Iustin Pop
  else:
589 e7b61bb0 Iustin Pop
    raise errors.ParameterError("Invalid boolean value '%s'" % value)
590 e7b61bb0 Iustin Pop
591 e7b61bb0 Iustin Pop
592 499eb088 Iustin Pop
def check_list(option, opt, value): # pylint: disable=W0613
593 499eb088 Iustin Pop
  """Custom parser for comma-separated lists.
594 499eb088 Iustin Pop

595 499eb088 Iustin Pop
  """
596 499eb088 Iustin Pop
  # we have to make this explicit check since "".split(",") is [""],
597 499eb088 Iustin Pop
  # not an empty list :(
598 499eb088 Iustin Pop
  if not value:
599 499eb088 Iustin Pop
    return []
600 499eb088 Iustin Pop
  else:
601 499eb088 Iustin Pop
    return utils.UnescapeAndSplit(value)
602 499eb088 Iustin Pop
603 499eb088 Iustin Pop
604 63d44c55 Michael Hanselmann
# completion_suggestion is normally a list. Using numeric values not evaluating
605 63d44c55 Michael Hanselmann
# to False for dynamic completion.
606 63d44c55 Michael Hanselmann
(OPT_COMPL_MANY_NODES,
607 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_NODE,
608 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_INSTANCE,
609 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_OS,
610 2d3ed64b Michael Hanselmann
 OPT_COMPL_ONE_IALLOCATOR,
611 36e247e1 Guido Trotter
 OPT_COMPL_INST_ADD_NODES,
612 36e247e1 Guido Trotter
 OPT_COMPL_ONE_NODEGROUP) = range(100, 107)
613 63d44c55 Michael Hanselmann
614 63d44c55 Michael Hanselmann
OPT_COMPL_ALL = frozenset([
615 63d44c55 Michael Hanselmann
  OPT_COMPL_MANY_NODES,
616 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_NODE,
617 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_INSTANCE,
618 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_OS,
619 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_IALLOCATOR,
620 2d3ed64b Michael Hanselmann
  OPT_COMPL_INST_ADD_NODES,
621 36e247e1 Guido Trotter
  OPT_COMPL_ONE_NODEGROUP,
622 63d44c55 Michael Hanselmann
  ])
623 63d44c55 Michael Hanselmann
624 63d44c55 Michael Hanselmann
625 552c8dff Michael Hanselmann
class CliOption(Option):
626 552c8dff Michael Hanselmann
  """Custom option class for optparse.
627 a8469393 Iustin Pop

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

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

1429 c41eea6e Iustin Pop
  @param argv: the command line
1430 c41eea6e Iustin Pop
  @param commands: dictionary with special contents, see the design
1431 c41eea6e Iustin Pop
      doc for cmdline handling
1432 c41eea6e Iustin Pop
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
1433 ef9fa5b9 René Nussbaumer
  @param env_override: list of env variables allowed for default args
1434 098c0958 Michael Hanselmann

1435 a8083063 Iustin Pop
  """
1436 ef9fa5b9 René Nussbaumer
  assert not (env_override - set(commands))
1437 ef9fa5b9 René Nussbaumer
1438 a8083063 Iustin Pop
  if len(argv) == 0:
1439 a8083063 Iustin Pop
    binary = "<command>"
1440 a8083063 Iustin Pop
  else:
1441 a8083063 Iustin Pop
    binary = argv[0].split("/")[-1]
1442 a8083063 Iustin Pop
1443 a8083063 Iustin Pop
  if len(argv) > 1 and argv[1] == "--version":
1444 84a12e40 Iustin Pop
    ToStdout("%s (ganeti %s) %s", binary, constants.VCS_VERSION,
1445 84a12e40 Iustin Pop
             constants.RELEASE_VERSION)
1446 a8083063 Iustin Pop
    # Quit right away. That way we don't have to care about this special
1447 a8083063 Iustin Pop
    # argument. optparse.py does it the same.
1448 a8083063 Iustin Pop
    sys.exit(0)
1449 a8083063 Iustin Pop
1450 de47cf8f Guido Trotter
  if len(argv) < 2 or not (argv[1] in commands or
1451 70a35b6f Guido Trotter
                           argv[1] in aliases):
1452 a8083063 Iustin Pop
    # let's do a nice thing
1453 a8083063 Iustin Pop
    sortedcmds = commands.keys()
1454 a8083063 Iustin Pop
    sortedcmds.sort()
1455 03298ebe Michael Hanselmann
1456 03298ebe Michael Hanselmann
    ToStdout("Usage: %s {command} [options...] [argument...]", binary)
1457 03298ebe Michael Hanselmann
    ToStdout("%s <command> --help to see details, or man %s", binary, binary)
1458 03298ebe Michael Hanselmann
    ToStdout("")
1459 03298ebe Michael Hanselmann
1460 a8083063 Iustin Pop
    # compute the max line length for cmd + usage
1461 4e713df6 Iustin Pop
    mlen = max([len(" %s" % cmd) for cmd in commands])
1462 a8083063 Iustin Pop
    mlen = min(60, mlen) # should not get here...
1463 03298ebe Michael Hanselmann
1464 a8083063 Iustin Pop
    # and format a nice command list
1465 03298ebe Michael Hanselmann
    ToStdout("Commands:")
1466 a8083063 Iustin Pop
    for cmd in sortedcmds:
1467 4e713df6 Iustin Pop
      cmdstr = " %s" % (cmd,)
1468 9a033156 Iustin Pop
      help_text = commands[cmd][4]
1469 03298ebe Michael Hanselmann
      help_lines = textwrap.wrap(help_text, 79 - 3 - mlen)
1470 03298ebe Michael Hanselmann
      ToStdout("%-*s - %s", mlen, cmdstr, help_lines.pop(0))
1471 a8083063 Iustin Pop
      for line in help_lines:
1472 03298ebe Michael Hanselmann
        ToStdout("%-*s   %s", mlen, "", line)
1473 03298ebe Michael Hanselmann
1474 03298ebe Michael Hanselmann
    ToStdout("")
1475 03298ebe Michael Hanselmann
1476 a8083063 Iustin Pop
    return None, None, None
1477 de47cf8f Guido Trotter
1478 de47cf8f Guido Trotter
  # get command, unalias it, and look it up in commands
1479 a8083063 Iustin Pop
  cmd = argv.pop(1)
1480 de47cf8f Guido Trotter
  if cmd in aliases:
1481 de47cf8f Guido Trotter
    if cmd in commands:
1482 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' overrides an existing"
1483 de47cf8f Guido Trotter
                                   " command" % cmd)
1484 de47cf8f Guido Trotter
1485 de47cf8f Guido Trotter
    if aliases[cmd] not in commands:
1486 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' maps to non-existing"
1487 de47cf8f Guido Trotter
                                   " command '%s'" % (cmd, aliases[cmd]))
1488 de47cf8f Guido Trotter
1489 de47cf8f Guido Trotter
    cmd = aliases[cmd]
1490 de47cf8f Guido Trotter
1491 ef9fa5b9 René Nussbaumer
  if cmd in env_override:
1492 ef9fa5b9 René Nussbaumer
    args_env_name = ("%s_%s" % (binary.replace("-", "_"), cmd)).upper()
1493 ef9fa5b9 René Nussbaumer
    env_args = os.environ.get(args_env_name)
1494 ef9fa5b9 René Nussbaumer
    if env_args:
1495 ef9fa5b9 René Nussbaumer
      argv = utils.InsertAtPos(argv, 1, shlex.split(env_args))
1496 ef9fa5b9 René Nussbaumer
1497 a8005e17 Michael Hanselmann
  func, args_def, parser_opts, usage, description = commands[cmd]
1498 bf5338b3 Michael Hanselmann
  parser = OptionParser(option_list=parser_opts + COMMON_OPTS,
1499 bf5338b3 Michael Hanselmann
                        description=description,
1500 bf5338b3 Michael Hanselmann
                        formatter=TitledHelpFormatter(),
1501 bf5338b3 Michael Hanselmann
                        usage="%%prog %s %s" % (cmd, usage))
1502 a8083063 Iustin Pop
  parser.disable_interspersed_args()
1503 ef9fa5b9 René Nussbaumer
  options, args = parser.parse_args(args=argv[1:])
1504 a8005e17 Michael Hanselmann
1505 a8005e17 Michael Hanselmann
  if not _CheckArguments(cmd, args_def, args):
1506 a8083063 Iustin Pop
    return None, None, None
1507 a8083063 Iustin Pop
1508 a8083063 Iustin Pop
  return func, options, args
1509 a8083063 Iustin Pop
1510 a8083063 Iustin Pop
1511 a8005e17 Michael Hanselmann
def _CheckArguments(cmd, args_def, args):
1512 a8005e17 Michael Hanselmann
  """Verifies the arguments using the argument definition.
1513 a8005e17 Michael Hanselmann

1514 a8005e17 Michael Hanselmann
  Algorithm:
1515 a8005e17 Michael Hanselmann

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

1518 a8005e17 Michael Hanselmann
    1. For each argument in definition
1519 a8005e17 Michael Hanselmann

1520 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
1521 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
1522 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
1523 a8005e17 Michael Hanselmann

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

1526 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
1527 a8005e17 Michael Hanselmann

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

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

1532 a8005e17 Michael Hanselmann
  """
1533 a8005e17 Michael Hanselmann
  if args and not args_def:
1534 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects no arguments", cmd)
1535 a8005e17 Michael Hanselmann
    return False
1536 a8005e17 Michael Hanselmann
1537 a8005e17 Michael Hanselmann
  min_count = None
1538 a8005e17 Michael Hanselmann
  max_count = None
1539 a8005e17 Michael Hanselmann
  check_max = None
1540 a8005e17 Michael Hanselmann
1541 a8005e17 Michael Hanselmann
  last_idx = len(args_def) - 1
1542 a8005e17 Michael Hanselmann
1543 a8005e17 Michael Hanselmann
  for idx, arg in enumerate(args_def):
1544 a8005e17 Michael Hanselmann
    if min_count is None:
1545 a8005e17 Michael Hanselmann
      min_count = arg.min
1546 a8005e17 Michael Hanselmann
    elif arg.min is not None:
1547 a8005e17 Michael Hanselmann
      min_count += arg.min
1548 a8005e17 Michael Hanselmann
1549 a8005e17 Michael Hanselmann
    if max_count is None:
1550 a8005e17 Michael Hanselmann
      max_count = arg.max
1551 a8005e17 Michael Hanselmann
    elif arg.max is not None:
1552 a8005e17 Michael Hanselmann
      max_count += arg.max
1553 a8005e17 Michael Hanselmann
1554 a8005e17 Michael Hanselmann
    if idx == last_idx:
1555 a8005e17 Michael Hanselmann
      check_max = (arg.max is not None)
1556 a8005e17 Michael Hanselmann
1557 a8005e17 Michael Hanselmann
    elif arg.max is None:
1558 a8005e17 Michael Hanselmann
      raise errors.ProgrammerError("Only the last argument can have max=None")
1559 a8005e17 Michael Hanselmann
1560 a8005e17 Michael Hanselmann
  if check_max:
1561 a8005e17 Michael Hanselmann
    # Command with exact number of arguments
1562 a8005e17 Michael Hanselmann
    if (min_count is not None and max_count is not None and
1563 a8005e17 Michael Hanselmann
        min_count == max_count and len(args) != min_count):
1564 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects %d argument(s)", cmd, min_count)
1565 a8005e17 Michael Hanselmann
      return False
1566 a8005e17 Michael Hanselmann
1567 a8005e17 Michael Hanselmann
    # Command with limited number of arguments
1568 a8005e17 Michael Hanselmann
    if max_count is not None and len(args) > max_count:
1569 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects only %d argument(s)",
1570 a8005e17 Michael Hanselmann
               cmd, max_count)
1571 a8005e17 Michael Hanselmann
      return False
1572 a8005e17 Michael Hanselmann
1573 a8005e17 Michael Hanselmann
  # Command with some required arguments
1574 a8005e17 Michael Hanselmann
  if min_count is not None and len(args) < min_count:
1575 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects at least %d argument(s)",
1576 a8005e17 Michael Hanselmann
             cmd, min_count)
1577 a8005e17 Michael Hanselmann
    return False
1578 a8005e17 Michael Hanselmann
1579 a8005e17 Michael Hanselmann
  return True
1580 a8005e17 Michael Hanselmann
1581 a8005e17 Michael Hanselmann
1582 60d49723 Michael Hanselmann
def SplitNodeOption(value):
1583 60d49723 Michael Hanselmann
  """Splits the value of a --node option.
1584 60d49723 Michael Hanselmann

1585 60d49723 Michael Hanselmann
  """
1586 d0c8c01d Iustin Pop
  if value and ":" in value:
1587 d0c8c01d Iustin Pop
    return value.split(":", 1)
1588 60d49723 Michael Hanselmann
  else:
1589 60d49723 Michael Hanselmann
    return (value, None)
1590 60d49723 Michael Hanselmann
1591 60d49723 Michael Hanselmann
1592 07150497 Guido Trotter
def CalculateOSNames(os_name, os_variants):
1593 07150497 Guido Trotter
  """Calculates all the names an OS can be called, according to its variants.
1594 07150497 Guido Trotter

1595 07150497 Guido Trotter
  @type os_name: string
1596 07150497 Guido Trotter
  @param os_name: base name of the os
1597 07150497 Guido Trotter
  @type os_variants: list or None
1598 07150497 Guido Trotter
  @param os_variants: list of supported variants
1599 07150497 Guido Trotter
  @rtype: list
1600 07150497 Guido Trotter
  @return: list of valid names
1601 07150497 Guido Trotter

1602 07150497 Guido Trotter
  """
1603 07150497 Guido Trotter
  if os_variants:
1604 d0c8c01d Iustin Pop
    return ["%s+%s" % (os_name, v) for v in os_variants]
1605 07150497 Guido Trotter
  else:
1606 07150497 Guido Trotter
    return [os_name]
1607 07150497 Guido Trotter
1608 07150497 Guido Trotter
1609 a4ebd726 Michael Hanselmann
def ParseFields(selected, default):
1610 a4ebd726 Michael Hanselmann
  """Parses the values of "--field"-like options.
1611 a4ebd726 Michael Hanselmann

1612 a4ebd726 Michael Hanselmann
  @type selected: string or None
1613 a4ebd726 Michael Hanselmann
  @param selected: User-selected options
1614 a4ebd726 Michael Hanselmann
  @type default: list
1615 a4ebd726 Michael Hanselmann
  @param default: Default fields
1616 a4ebd726 Michael Hanselmann

1617 a4ebd726 Michael Hanselmann
  """
1618 a4ebd726 Michael Hanselmann
  if selected is None:
1619 a4ebd726 Michael Hanselmann
    return default
1620 a4ebd726 Michael Hanselmann
1621 a4ebd726 Michael Hanselmann
  if selected.startswith("+"):
1622 a4ebd726 Michael Hanselmann
    return default + selected[1:].split(",")
1623 a4ebd726 Michael Hanselmann
1624 a4ebd726 Michael Hanselmann
  return selected.split(",")
1625 a4ebd726 Michael Hanselmann
1626 a4ebd726 Michael Hanselmann
1627 e0e916fe Iustin Pop
UsesRPC = rpc.RunWithRPC
1628 4331f6cd Michael Hanselmann
1629 4331f6cd Michael Hanselmann
1630 47988778 Iustin Pop
def AskUser(text, choices=None):
1631 47988778 Iustin Pop
  """Ask the user a question.
1632 a8083063 Iustin Pop

1633 c41eea6e Iustin Pop
  @param text: the question to ask
1634 a8083063 Iustin Pop

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

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

1644 a8083063 Iustin Pop
  """
1645 47988778 Iustin Pop
  if choices is None:
1646 d0c8c01d Iustin Pop
    choices = [("y", True, "Perform the operation"),
1647 d0c8c01d Iustin Pop
               ("n", False, "Do not perform the operation")]
1648 47988778 Iustin Pop
  if not choices or not isinstance(choices, list):
1649 5bbd3f7f Michael Hanselmann
    raise errors.ProgrammerError("Invalid choices argument to AskUser")
1650 47988778 Iustin Pop
  for entry in choices:
1651 d0c8c01d Iustin Pop
    if not isinstance(entry, tuple) or len(entry) < 3 or entry[0] == "?":
1652 5bbd3f7f Michael Hanselmann
      raise errors.ProgrammerError("Invalid choices element to AskUser")
1653 47988778 Iustin Pop
1654 47988778 Iustin Pop
  answer = choices[-1][1]
1655 47988778 Iustin Pop
  new_text = []
1656 47988778 Iustin Pop
  for line in text.splitlines():
1657 47988778 Iustin Pop
    new_text.append(textwrap.fill(line, 70, replace_whitespace=False))
1658 47988778 Iustin Pop
  text = "\n".join(new_text)
1659 a8083063 Iustin Pop
  try:
1660 3023170f Iustin Pop
    f = file("/dev/tty", "a+")
1661 a8083063 Iustin Pop
  except IOError:
1662 47988778 Iustin Pop
    return answer
1663 a8083063 Iustin Pop
  try:
1664 47988778 Iustin Pop
    chars = [entry[0] for entry in choices]
1665 47988778 Iustin Pop
    chars[-1] = "[%s]" % chars[-1]
1666 d0c8c01d Iustin Pop
    chars.append("?")
1667 47988778 Iustin Pop
    maps = dict([(entry[0], entry[1]) for entry in choices])
1668 47988778 Iustin Pop
    while True:
1669 47988778 Iustin Pop
      f.write(text)
1670 d0c8c01d Iustin Pop
      f.write("\n")
1671 47988778 Iustin Pop
      f.write("/".join(chars))
1672 47988778 Iustin Pop
      f.write(": ")
1673 47988778 Iustin Pop
      line = f.readline(2).strip().lower()
1674 47988778 Iustin Pop
      if line in maps:
1675 47988778 Iustin Pop
        answer = maps[line]
1676 47988778 Iustin Pop
        break
1677 d0c8c01d Iustin Pop
      elif line == "?":
1678 47988778 Iustin Pop
        for entry in choices:
1679 47988778 Iustin Pop
          f.write(" %s - %s\n" % (entry[0], entry[2]))
1680 47988778 Iustin Pop
        f.write("\n")
1681 47988778 Iustin Pop
        continue
1682 a8083063 Iustin Pop
  finally:
1683 a8083063 Iustin Pop
    f.close()
1684 a8083063 Iustin Pop
  return answer
1685 a8083063 Iustin Pop
1686 a8083063 Iustin Pop
1687 e9d741b6 Iustin Pop
class JobSubmittedException(Exception):
1688 e9d741b6 Iustin Pop
  """Job was submitted, client should exit.
1689 e9d741b6 Iustin Pop

1690 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1691 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1692 e9d741b6 Iustin Pop

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

1695 e9d741b6 Iustin Pop
  """
1696 e9d741b6 Iustin Pop
1697 e9d741b6 Iustin Pop
1698 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1699 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1700 a8083063 Iustin Pop

1701 0a1e74d9 Iustin Pop
  @type ops: list
1702 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1703 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1704 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1705 0a1e74d9 Iustin Pop
             if None, a new client will be created
1706 a8083063 Iustin Pop

1707 a8083063 Iustin Pop
  """
1708 e2212007 Iustin Pop
  if cl is None:
1709 b33e986b Iustin Pop
    cl = GetClient()
1710 685ee993 Iustin Pop
1711 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1712 0a1e74d9 Iustin Pop
1713 0a1e74d9 Iustin Pop
  return job_id
1714 0a1e74d9 Iustin Pop
1715 0a1e74d9 Iustin Pop
1716 4e338533 Michael Hanselmann
def GenericPollJob(job_id, cbs, report_cbs):
1717 4e338533 Michael Hanselmann
  """Generic job-polling function.
1718 0a1e74d9 Iustin Pop

1719 4e338533 Michael Hanselmann
  @type job_id: number
1720 4e338533 Michael Hanselmann
  @param job_id: Job ID
1721 4e338533 Michael Hanselmann
  @type cbs: Instance of L{JobPollCbBase}
1722 4e338533 Michael Hanselmann
  @param cbs: Data callbacks
1723 4e338533 Michael Hanselmann
  @type report_cbs: Instance of L{JobPollReportCbBase}
1724 4e338533 Michael Hanselmann
  @param report_cbs: Reporting callbacks
1725 0a1e74d9 Iustin Pop

1726 0a1e74d9 Iustin Pop
  """
1727 6c5a7090 Michael Hanselmann
  prev_job_info = None
1728 6c5a7090 Michael Hanselmann
  prev_logmsg_serial = None
1729 6c5a7090 Michael Hanselmann
1730 f4484122 Michael Hanselmann
  status = None
1731 f4484122 Michael Hanselmann
1732 685ee993 Iustin Pop
  while True:
1733 4e338533 Michael Hanselmann
    result = cbs.WaitForJobChangeOnce(job_id, ["status"], prev_job_info,
1734 4e338533 Michael Hanselmann
                                      prev_logmsg_serial)
1735 6c5a7090 Michael Hanselmann
    if not result:
1736 685ee993 Iustin Pop
      # job not found, go away!
1737 0bbe448c Michael Hanselmann
      raise errors.JobLost("Job with id %s lost" % job_id)
1738 4e338533 Michael Hanselmann
1739 4e338533 Michael Hanselmann
    if result == constants.JOB_NOTCHANGED:
1740 4e338533 Michael Hanselmann
      report_cbs.ReportNotChanged(job_id, status)
1741 f4484122 Michael Hanselmann
1742 f4484122 Michael Hanselmann
      # Wait again
1743 f4484122 Michael Hanselmann
      continue
1744 685ee993 Iustin Pop
1745 6c5a7090 Michael Hanselmann
    # Split result, a tuple of (field values, log entries)
1746 6c5a7090 Michael Hanselmann
    (job_info, log_entries) = result
1747 6c5a7090 Michael Hanselmann
    (status, ) = job_info
1748 6c5a7090 Michael Hanselmann
1749 6c5a7090 Michael Hanselmann
    if log_entries:
1750 6c5a7090 Michael Hanselmann
      for log_entry in log_entries:
1751 4e338533 Michael Hanselmann
        (serial, timestamp, log_type, message) = log_entry
1752 4e338533 Michael Hanselmann
        report_cbs.ReportLogMessage(job_id, serial, timestamp,
1753 4e338533 Michael Hanselmann
                                    log_type, message)
1754 6c5a7090 Michael Hanselmann
        prev_logmsg_serial = max(prev_logmsg_serial, serial)
1755 6c5a7090 Michael Hanselmann
1756 0bbe448c Michael Hanselmann
    # TODO: Handle canceled and archived jobs
1757 fbf0262f Michael Hanselmann
    elif status in (constants.JOB_STATUS_SUCCESS,
1758 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_ERROR,
1759 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELING,
1760 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELED):
1761 685ee993 Iustin Pop
      break
1762 6c5a7090 Michael Hanselmann
1763 6c5a7090 Michael Hanselmann
    prev_job_info = job_info
1764 685ee993 Iustin Pop
1765 4e338533 Michael Hanselmann
  jobs = cbs.QueryJobs([job_id], ["status", "opstatus", "opresult"])
1766 0bbe448c Michael Hanselmann
  if not jobs:
1767 0bbe448c Michael Hanselmann
    raise errors.JobLost("Job with id %s lost" % job_id)
1768 685ee993 Iustin Pop
1769 0e050889 Iustin Pop
  status, opstatus, result = jobs[0]
1770 4e338533 Michael Hanselmann
1771 0bbe448c Michael Hanselmann
  if status == constants.JOB_STATUS_SUCCESS:
1772 53c04d04 Iustin Pop
    return result
1773 4e338533 Michael Hanselmann
1774 4e338533 Michael Hanselmann
  if status in (constants.JOB_STATUS_CANCELING, constants.JOB_STATUS_CANCELED):
1775 fbf0262f Michael Hanselmann
    raise errors.OpExecError("Job was canceled")
1776 4e338533 Michael Hanselmann
1777 4e338533 Michael Hanselmann
  has_ok = False
1778 4e338533 Michael Hanselmann
  for idx, (status, msg) in enumerate(zip(opstatus, result)):
1779 4e338533 Michael Hanselmann
    if status == constants.OP_STATUS_SUCCESS:
1780 4e338533 Michael Hanselmann
      has_ok = True
1781 4e338533 Michael Hanselmann
    elif status == constants.OP_STATUS_ERROR:
1782 4e338533 Michael Hanselmann
      errors.MaybeRaise(msg)
1783 4e338533 Michael Hanselmann
1784 4e338533 Michael Hanselmann
      if has_ok:
1785 4e338533 Michael Hanselmann
        raise errors.OpExecError("partial failure (opcode %d): %s" %
1786 4e338533 Michael Hanselmann
                                 (idx, msg))
1787 4e338533 Michael Hanselmann
1788 4e338533 Michael Hanselmann
      raise errors.OpExecError(str(msg))
1789 4e338533 Michael Hanselmann
1790 4e338533 Michael Hanselmann
  # default failure mode
1791 4e338533 Michael Hanselmann
  raise errors.OpExecError(result)
1792 4e338533 Michael Hanselmann
1793 4e338533 Michael Hanselmann
1794 4e338533 Michael Hanselmann
class JobPollCbBase:
1795 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} callbacks.
1796 4e338533 Michael Hanselmann

1797 4e338533 Michael Hanselmann
  """
1798 4e338533 Michael Hanselmann
  def __init__(self):
1799 4e338533 Michael Hanselmann
    """Initializes this class.
1800 4e338533 Michael Hanselmann

1801 4e338533 Michael Hanselmann
    """
1802 4e338533 Michael Hanselmann
1803 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1804 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1805 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1806 4e338533 Michael Hanselmann

1807 4e338533 Michael Hanselmann
    """
1808 4e338533 Michael Hanselmann
    raise NotImplementedError()
1809 4e338533 Michael Hanselmann
1810 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1811 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1812 4e338533 Michael Hanselmann

1813 4e338533 Michael Hanselmann
    @type job_ids: list of numbers
1814 4e338533 Michael Hanselmann
    @param job_ids: Job IDs
1815 4e338533 Michael Hanselmann
    @type fields: list of strings
1816 4e338533 Michael Hanselmann
    @param fields: Fields
1817 4e338533 Michael Hanselmann

1818 4e338533 Michael Hanselmann
    """
1819 4e338533 Michael Hanselmann
    raise NotImplementedError()
1820 4e338533 Michael Hanselmann
1821 4e338533 Michael Hanselmann
1822 4e338533 Michael Hanselmann
class JobPollReportCbBase:
1823 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} reporting callbacks.
1824 4e338533 Michael Hanselmann

1825 4e338533 Michael Hanselmann
  """
1826 4e338533 Michael Hanselmann
  def __init__(self):
1827 4e338533 Michael Hanselmann
    """Initializes this class.
1828 4e338533 Michael Hanselmann

1829 4e338533 Michael Hanselmann
    """
1830 4e338533 Michael Hanselmann
1831 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1832 4e338533 Michael Hanselmann
    """Handles a log message.
1833 4e338533 Michael Hanselmann

1834 4e338533 Michael Hanselmann
    """
1835 4e338533 Michael Hanselmann
    raise NotImplementedError()
1836 4e338533 Michael Hanselmann
1837 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1838 4e338533 Michael Hanselmann
    """Called for if a job hasn't changed in a while.
1839 4e338533 Michael Hanselmann

1840 4e338533 Michael Hanselmann
    @type job_id: number
1841 4e338533 Michael Hanselmann
    @param job_id: Job ID
1842 4e338533 Michael Hanselmann
    @type status: string or None
1843 4e338533 Michael Hanselmann
    @param status: Job status if available
1844 4e338533 Michael Hanselmann

1845 4e338533 Michael Hanselmann
    """
1846 4e338533 Michael Hanselmann
    raise NotImplementedError()
1847 4e338533 Michael Hanselmann
1848 4e338533 Michael Hanselmann
1849 4e338533 Michael Hanselmann
class _LuxiJobPollCb(JobPollCbBase):
1850 4e338533 Michael Hanselmann
  def __init__(self, cl):
1851 4e338533 Michael Hanselmann
    """Initializes this class.
1852 4e338533 Michael Hanselmann

1853 4e338533 Michael Hanselmann
    """
1854 4e338533 Michael Hanselmann
    JobPollCbBase.__init__(self)
1855 4e338533 Michael Hanselmann
    self.cl = cl
1856 4e338533 Michael Hanselmann
1857 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1858 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1859 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1860 4e338533 Michael Hanselmann

1861 4e338533 Michael Hanselmann
    """
1862 4e338533 Michael Hanselmann
    return self.cl.WaitForJobChangeOnce(job_id, fields,
1863 4e338533 Michael Hanselmann
                                        prev_job_info, prev_log_serial)
1864 4e338533 Michael Hanselmann
1865 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1866 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1867 4e338533 Michael Hanselmann

1868 4e338533 Michael Hanselmann
    """
1869 4e338533 Michael Hanselmann
    return self.cl.QueryJobs(job_ids, fields)
1870 4e338533 Michael Hanselmann
1871 4e338533 Michael Hanselmann
1872 4e338533 Michael Hanselmann
class FeedbackFnJobPollReportCb(JobPollReportCbBase):
1873 4e338533 Michael Hanselmann
  def __init__(self, feedback_fn):
1874 4e338533 Michael Hanselmann
    """Initializes this class.
1875 4e338533 Michael Hanselmann

1876 4e338533 Michael Hanselmann
    """
1877 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1878 4e338533 Michael Hanselmann
1879 4e338533 Michael Hanselmann
    self.feedback_fn = feedback_fn
1880 4e338533 Michael Hanselmann
1881 4e338533 Michael Hanselmann
    assert callable(feedback_fn)
1882 4e338533 Michael Hanselmann
1883 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1884 4e338533 Michael Hanselmann
    """Handles a log message.
1885 4e338533 Michael Hanselmann

1886 4e338533 Michael Hanselmann
    """
1887 4e338533 Michael Hanselmann
    self.feedback_fn((timestamp, log_type, log_msg))
1888 4e338533 Michael Hanselmann
1889 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1890 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1891 4e338533 Michael Hanselmann

1892 4e338533 Michael Hanselmann
    """
1893 4e338533 Michael Hanselmann
    # Ignore
1894 4e338533 Michael Hanselmann
1895 4e338533 Michael Hanselmann
1896 4e338533 Michael Hanselmann
class StdioJobPollReportCb(JobPollReportCbBase):
1897 4e338533 Michael Hanselmann
  def __init__(self):
1898 4e338533 Michael Hanselmann
    """Initializes this class.
1899 4e338533 Michael Hanselmann

1900 4e338533 Michael Hanselmann
    """
1901 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1902 4e338533 Michael Hanselmann
1903 4e338533 Michael Hanselmann
    self.notified_queued = False
1904 4e338533 Michael Hanselmann
    self.notified_waitlock = False
1905 4e338533 Michael Hanselmann
1906 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1907 4e338533 Michael Hanselmann
    """Handles a log message.
1908 4e338533 Michael Hanselmann

1909 4e338533 Michael Hanselmann
    """
1910 4e338533 Michael Hanselmann
    ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)),
1911 8a7f1c61 Michael Hanselmann
             FormatLogMessage(log_type, log_msg))
1912 4e338533 Michael Hanselmann
1913 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1914 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1915 4e338533 Michael Hanselmann

1916 4e338533 Michael Hanselmann
    """
1917 4e338533 Michael Hanselmann
    if status is None:
1918 4e338533 Michael Hanselmann
      return
1919 4e338533 Michael Hanselmann
1920 4e338533 Michael Hanselmann
    if status == constants.JOB_STATUS_QUEUED and not self.notified_queued:
1921 4e338533 Michael Hanselmann
      ToStderr("Job %s is waiting in queue", job_id)
1922 4e338533 Michael Hanselmann
      self.notified_queued = True
1923 4e338533 Michael Hanselmann
1924 47099cd1 Michael Hanselmann
    elif status == constants.JOB_STATUS_WAITING and not self.notified_waitlock:
1925 4e338533 Michael Hanselmann
      ToStderr("Job %s is trying to acquire all necessary locks", job_id)
1926 4e338533 Michael Hanselmann
      self.notified_waitlock = True
1927 4e338533 Michael Hanselmann
1928 4e338533 Michael Hanselmann
1929 8a7f1c61 Michael Hanselmann
def FormatLogMessage(log_type, log_msg):
1930 8a7f1c61 Michael Hanselmann
  """Formats a job message according to its type.
1931 8a7f1c61 Michael Hanselmann

1932 8a7f1c61 Michael Hanselmann
  """
1933 8a7f1c61 Michael Hanselmann
  if log_type != constants.ELOG_MESSAGE:
1934 8a7f1c61 Michael Hanselmann
    log_msg = str(log_msg)
1935 8a7f1c61 Michael Hanselmann
1936 8a7f1c61 Michael Hanselmann
  return utils.SafeEncode(log_msg)
1937 8a7f1c61 Michael Hanselmann
1938 8a7f1c61 Michael Hanselmann
1939 583163a6 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None, reporter=None):
1940 4e338533 Michael Hanselmann
  """Function to poll for the result of a job.
1941 4e338533 Michael Hanselmann

1942 4e338533 Michael Hanselmann
  @type job_id: job identified
1943 4e338533 Michael Hanselmann
  @param job_id: the job to poll for results
1944 4e338533 Michael Hanselmann
  @type cl: luxi.Client
1945 4e338533 Michael Hanselmann
  @param cl: the luxi client to use for communicating with the master;
1946 4e338533 Michael Hanselmann
             if None, a new client will be created
1947 4e338533 Michael Hanselmann

1948 4e338533 Michael Hanselmann
  """
1949 4e338533 Michael Hanselmann
  if cl is None:
1950 4e338533 Michael Hanselmann
    cl = GetClient()
1951 4e338533 Michael Hanselmann
1952 583163a6 Michael Hanselmann
  if reporter is None:
1953 583163a6 Michael Hanselmann
    if feedback_fn:
1954 583163a6 Michael Hanselmann
      reporter = FeedbackFnJobPollReportCb(feedback_fn)
1955 583163a6 Michael Hanselmann
    else:
1956 583163a6 Michael Hanselmann
      reporter = StdioJobPollReportCb()
1957 583163a6 Michael Hanselmann
  elif feedback_fn:
1958 583163a6 Michael Hanselmann
    raise errors.ProgrammerError("Can't specify reporter and feedback function")
1959 4e338533 Michael Hanselmann
1960 4e338533 Michael Hanselmann
  return GenericPollJob(job_id, _LuxiJobPollCb(cl), reporter)
1961 ceab32dd Iustin Pop
1962 ceab32dd Iustin Pop
1963 583163a6 Michael Hanselmann
def SubmitOpCode(op, cl=None, feedback_fn=None, opts=None, reporter=None):
1964 0a1e74d9 Iustin Pop
  """Legacy function to submit an opcode.
1965 0a1e74d9 Iustin Pop

1966 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1967 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1968 0a1e74d9 Iustin Pop
  interaction functions.
1969 0a1e74d9 Iustin Pop

1970 0a1e74d9 Iustin Pop
  """
1971 0a1e74d9 Iustin Pop
  if cl is None:
1972 0a1e74d9 Iustin Pop
    cl = GetClient()
1973 0a1e74d9 Iustin Pop
1974 293ba2d8 Iustin Pop
  SetGenericOpcodeOpts([op], opts)
1975 293ba2d8 Iustin Pop
1976 5d297d8a Michael Hanselmann
  job_id = SendJob([op], cl=cl)
1977 0a1e74d9 Iustin Pop
1978 583163a6 Michael Hanselmann
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn,
1979 583163a6 Michael Hanselmann
                       reporter=reporter)
1980 53c04d04 Iustin Pop
1981 53c04d04 Iustin Pop
  return op_results[0]
1982 0a1e74d9 Iustin Pop
1983 0a1e74d9 Iustin Pop
1984 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1985 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1986 94428652 Iustin Pop

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

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

1995 94428652 Iustin Pop
  """
1996 94428652 Iustin Pop
  if opts and opts.submit_only:
1997 293ba2d8 Iustin Pop
    job = [op]
1998 293ba2d8 Iustin Pop
    SetGenericOpcodeOpts(job, opts)
1999 293ba2d8 Iustin Pop
    job_id = SendJob(job, cl=cl)
2000 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
2001 94428652 Iustin Pop
  else:
2002 293ba2d8 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
2003 293ba2d8 Iustin Pop
2004 293ba2d8 Iustin Pop
2005 293ba2d8 Iustin Pop
def SetGenericOpcodeOpts(opcode_list, options):
2006 293ba2d8 Iustin Pop
  """Processor for generic options.
2007 293ba2d8 Iustin Pop

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

2011 293ba2d8 Iustin Pop
  @param opcode_list: list of opcodes
2012 293ba2d8 Iustin Pop
  @param options: command line options or None
2013 293ba2d8 Iustin Pop
  @return: None (in-place modification)
2014 293ba2d8 Iustin Pop

2015 293ba2d8 Iustin Pop
  """
2016 293ba2d8 Iustin Pop
  if not options:
2017 293ba2d8 Iustin Pop
    return
2018 293ba2d8 Iustin Pop
  for op in opcode_list:
2019 aa06f8c6 Michael Hanselmann
    op.debug_level = options.debug
2020 a0a6ff34 Iustin Pop
    if hasattr(options, "dry_run"):
2021 a0a6ff34 Iustin Pop
      op.dry_run = options.dry_run
2022 aa06f8c6 Michael Hanselmann
    if getattr(options, "priority", None) is not None:
2023 aa06f8c6 Michael Hanselmann
      op.priority = _PRIONAME_TO_VALUE[options.priority]
2024 94428652 Iustin Pop
2025 94428652 Iustin Pop
2026 af30b2fd Michael Hanselmann
def GetClient():
2027 af30b2fd Michael Hanselmann
  # TODO: Cache object?
2028 b33e986b Iustin Pop
  try:
2029 b33e986b Iustin Pop
    client = luxi.Client()
2030 b33e986b Iustin Pop
  except luxi.NoMasterError:
2031 d9a51679 Michael Hanselmann
    ss = ssconf.SimpleStore()
2032 d9a51679 Michael Hanselmann
2033 d9a51679 Michael Hanselmann
    # Try to read ssconf file
2034 d9a51679 Michael Hanselmann
    try:
2035 d9a51679 Michael Hanselmann
      ss.GetMasterNode()
2036 d9a51679 Michael Hanselmann
    except errors.ConfigurationError:
2037 d9a51679 Michael Hanselmann
      raise errors.OpPrereqError("Cluster not initialized or this machine is"
2038 d9a51679 Michael Hanselmann
                                 " not part of a cluster")
2039 d9a51679 Michael Hanselmann
2040 d9a51679 Michael Hanselmann
    master, myself = ssconf.GetMasterAndMyself(ss=ss)
2041 b33e986b Iustin Pop
    if master != myself:
2042 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
2043 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
2044 b33e986b Iustin Pop
                                 master)
2045 d9a51679 Michael Hanselmann
    raise
2046 b33e986b Iustin Pop
  return client
2047 af30b2fd Michael Hanselmann
2048 af30b2fd Michael Hanselmann
2049 73702ee7 Iustin Pop
def FormatError(err):
2050 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
2051 73702ee7 Iustin Pop

2052 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
2053 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
2054 73702ee7 Iustin Pop
  second, a string describing the error message (not
2055 73702ee7 Iustin Pop
  newline-terminated).
2056 73702ee7 Iustin Pop

2057 73702ee7 Iustin Pop
  """
2058 73702ee7 Iustin Pop
  retcode = 1
2059 73702ee7 Iustin Pop
  obuf = StringIO()
2060 e2e521d0 Iustin Pop
  msg = str(err)
2061 73702ee7 Iustin Pop
  if isinstance(err, errors.ConfigurationError):
2062 e2e521d0 Iustin Pop
    txt = "Corrupt configuration file: %s" % msg
2063 46fbdd04 Iustin Pop
    logging.error(txt)
2064 e2e521d0 Iustin Pop
    obuf.write(txt + "\n")
2065 73702ee7 Iustin Pop
    obuf.write("Aborting.")
2066 73702ee7 Iustin Pop
    retcode = 2
2067 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksAbort):
2068 73702ee7 Iustin Pop
    obuf.write("Failure: hooks execution failed:\n")
2069 73702ee7 Iustin Pop
    for node, script, out in err.args[0]:
2070 73702ee7 Iustin Pop
      if out:
2071 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s, output: %s\n" %
2072 73702ee7 Iustin Pop
                   (node, script, out))
2073 73702ee7 Iustin Pop
      else:
2074 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s (no output)\n" %
2075 73702ee7 Iustin Pop
                   (node, script))
2076 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksFailure):
2077 e2e521d0 Iustin Pop
    obuf.write("Failure: hooks general failure: %s" % msg)
2078 73702ee7 Iustin Pop
  elif isinstance(err, errors.ResolverError):
2079 b705c7a6 Manuel Franceschini
    this_host = netutils.Hostname.GetSysName()
2080 73702ee7 Iustin Pop
    if err.args[0] == this_host:
2081 73702ee7 Iustin Pop
      msg = "Failure: can't resolve my own hostname ('%s')"
2082 73702ee7 Iustin Pop
    else:
2083 73702ee7 Iustin Pop
      msg = "Failure: can't resolve hostname '%s'"
2084 73702ee7 Iustin Pop
    obuf.write(msg % err.args[0])
2085 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpPrereqError):
2086 5c983ee5 Iustin Pop
    if len(err.args) == 2:
2087 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
2088 5c983ee5 Iustin Pop
               " operation:\nerror type: %s, error details:\n%s" %
2089 5c983ee5 Iustin Pop
                 (err.args[1], err.args[0]))
2090 5c983ee5 Iustin Pop
    else:
2091 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
2092 5c983ee5 Iustin Pop
                 " operation:\n%s" % msg)
2093 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpExecError):
2094 e2e521d0 Iustin Pop
    obuf.write("Failure: command execution error:\n%s" % msg)
2095 73702ee7 Iustin Pop
  elif isinstance(err, errors.TagError):
2096 e2e521d0 Iustin Pop
    obuf.write("Failure: invalid tag(s) given:\n%s" % msg)
2097 686d7433 Iustin Pop
  elif isinstance(err, errors.JobQueueDrainError):
2098 686d7433 Iustin Pop
    obuf.write("Failure: the job queue is marked for drain and doesn't"
2099 686d7433 Iustin Pop
               " accept new requests\n")
2100 f87b405e Michael Hanselmann
  elif isinstance(err, errors.JobQueueFull):
2101 f87b405e Michael Hanselmann
    obuf.write("Failure: the job queue is full and doesn't accept new"
2102 f87b405e Michael Hanselmann
               " job submissions until old jobs are archived\n")
2103 a5728081 Guido Trotter
  elif isinstance(err, errors.TypeEnforcementError):
2104 a5728081 Guido Trotter
    obuf.write("Parameter Error: %s" % msg)
2105 c1ce76bb Iustin Pop
  elif isinstance(err, errors.ParameterError):
2106 c1ce76bb Iustin Pop
    obuf.write("Failure: unknown/wrong parameter name '%s'" % msg)
2107 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.NoMasterError):
2108 03a8dbdc Iustin Pop
    obuf.write("Cannot communicate with the master daemon.\nIs it running"
2109 082c5adb Michael Hanselmann
               " and listening for connections?")
2110 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.TimeoutError):
2111 cd4c86a8 Michael Hanselmann
    obuf.write("Timeout while talking to the master daemon. Jobs might have"
2112 cd4c86a8 Michael Hanselmann
               " been submitted and will continue to run even if the call"
2113 cd4c86a8 Michael Hanselmann
               " timed out. Useful commands in this situation are \"gnt-job"
2114 cd4c86a8 Michael Hanselmann
               " list\", \"gnt-job cancel\" and \"gnt-job watch\". Error:\n")
2115 cd4c86a8 Michael Hanselmann
    obuf.write(msg)
2116 5a1c22fe Iustin Pop
  elif isinstance(err, luxi.PermissionError):
2117 5a1c22fe Iustin Pop
    obuf.write("It seems you don't have permissions to connect to the"
2118 5a1c22fe Iustin Pop
               " master daemon.\nPlease retry as a different user.")
2119 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.ProtocolError):
2120 03a8dbdc Iustin Pop
    obuf.write("Unhandled protocol error while talking to the master daemon:\n"
2121 03a8dbdc Iustin Pop
               "%s" % msg)
2122 91c622a8 Iustin Pop
  elif isinstance(err, errors.JobLost):
2123 91c622a8 Iustin Pop
    obuf.write("Error checking job status: %s" % msg)
2124 cb1e6c3c Michael Hanselmann
  elif isinstance(err, errors.QueryFilterParseError):
2125 cb1e6c3c Michael Hanselmann
    obuf.write("Error while parsing query filter: %s\n" % err.args[0])
2126 cb1e6c3c Michael Hanselmann
    obuf.write("\n".join(err.GetDetails()))
2127 797506fc Michael Hanselmann
  elif isinstance(err, errors.GenericError):
2128 797506fc Michael Hanselmann
    obuf.write("Unhandled Ganeti error: %s" % msg)
2129 e9d741b6 Iustin Pop
  elif isinstance(err, JobSubmittedException):
2130 e9d741b6 Iustin Pop
    obuf.write("JobID: %s\n" % err.args[0])
2131 e9d741b6 Iustin Pop
    retcode = 0
2132 73702ee7 Iustin Pop
  else:
2133 e2e521d0 Iustin Pop
    obuf.write("Unhandled exception: %s" % msg)
2134 d0c8c01d Iustin Pop
  return retcode, obuf.getvalue().rstrip("\n")
2135 73702ee7 Iustin Pop
2136 73702ee7 Iustin Pop
2137 ef9fa5b9 René Nussbaumer
def GenericMain(commands, override=None, aliases=None,
2138 ef9fa5b9 René Nussbaumer
                env_override=frozenset()):
2139 a8083063 Iustin Pop
  """Generic main function for all the gnt-* commands.
2140 a8083063 Iustin Pop

2141 ef9fa5b9 René Nussbaumer
  @param commands: a dictionary with a special structure, see the design doc
2142 ef9fa5b9 René Nussbaumer
                   for command line handling.
2143 ef9fa5b9 René Nussbaumer
  @param override: if not None, we expect a dictionary with keys that will
2144 ef9fa5b9 René Nussbaumer
                   override command line options; this can be used to pass
2145 ef9fa5b9 René Nussbaumer
                   options from the scripts to generic functions
2146 ef9fa5b9 René Nussbaumer
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
2147 ef9fa5b9 René Nussbaumer
  @param env_override: list of environment names which are allowed to submit
2148 ef9fa5b9 René Nussbaumer
                       default args for commands
2149 a8083063 Iustin Pop

2150 a8083063 Iustin Pop
  """
2151 a8083063 Iustin Pop
  # save the program name and the entire command line for later logging
2152 a8083063 Iustin Pop
  if sys.argv:
2153 c1f19851 Michael Hanselmann
    binary = os.path.basename(sys.argv[0])
2154 c1f19851 Michael Hanselmann
    if not binary:
2155 c1f19851 Michael Hanselmann
      binary = sys.argv[0]
2156 c1f19851 Michael Hanselmann
2157 a8083063 Iustin Pop
    if len(sys.argv) >= 2:
2158 c1f19851 Michael Hanselmann
      logname = utils.ShellQuoteArgs([binary, sys.argv[1]])
2159 a8083063 Iustin Pop
    else:
2160 c1f19851 Michael Hanselmann
      logname = binary
2161 c1f19851 Michael Hanselmann
2162 c1f19851 Michael Hanselmann
    cmdline = utils.ShellQuoteArgs([binary] + sys.argv[1:])
2163 a8083063 Iustin Pop
  else:
2164 a8083063 Iustin Pop
    binary = "<unknown program>"
2165 c1f19851 Michael Hanselmann
    cmdline = "<unknown>"
2166 a8083063 Iustin Pop
2167 de47cf8f Guido Trotter
  if aliases is None:
2168 de47cf8f Guido Trotter
    aliases = {}
2169 de47cf8f Guido Trotter
2170 3126878d Guido Trotter
  try:
2171 ef9fa5b9 René Nussbaumer
    func, options, args = _ParseArgs(sys.argv, commands, aliases, env_override)
2172 3126878d Guido Trotter
  except errors.ParameterError, err:
2173 3126878d Guido Trotter
    result, err_msg = FormatError(err)
2174 3126878d Guido Trotter
    ToStderr(err_msg)
2175 3126878d Guido Trotter
    return 1
2176 3126878d Guido Trotter
2177 a8083063 Iustin Pop
  if func is None: # parse error
2178 a8083063 Iustin Pop
    return 1
2179 a8083063 Iustin Pop
2180 334d1483 Iustin Pop
  if override is not None:
2181 334d1483 Iustin Pop
    for key, val in override.iteritems():
2182 334d1483 Iustin Pop
      setattr(options, key, val)
2183 334d1483 Iustin Pop
2184 c1f19851 Michael Hanselmann
  utils.SetupLogging(constants.LOG_COMMANDS, logname, debug=options.debug,
2185 cfcc79c6 Michael Hanselmann
                     stderr_logging=True)
2186 a8083063 Iustin Pop
2187 c1f19851 Michael Hanselmann
  logging.info("Command line: %s", cmdline)
2188 a8083063 Iustin Pop
2189 a8083063 Iustin Pop
  try:
2190 a4af651e Iustin Pop
    result = func(options, args)
2191 d8353c3a Iustin Pop
  except (errors.GenericError, luxi.ProtocolError,
2192 d8353c3a Iustin Pop
          JobSubmittedException), err:
2193 a4af651e Iustin Pop
    result, err_msg = FormatError(err)
2194 5bbd3f7f Michael Hanselmann
    logging.exception("Error during command processing")
2195 46fbdd04 Iustin Pop
    ToStderr(err_msg)
2196 8a53b55f Iustin Pop
  except KeyboardInterrupt:
2197 8a53b55f Iustin Pop
    result = constants.EXIT_FAILURE
2198 8a53b55f Iustin Pop
    ToStderr("Aborted. Note that if the operation created any jobs, they"
2199 8a53b55f Iustin Pop
             " might have been submitted and"
2200 8a53b55f Iustin Pop
             " will continue to run in the background.")
2201 225e2544 Iustin Pop
  except IOError, err:
2202 225e2544 Iustin Pop
    if err.errno == errno.EPIPE:
2203 225e2544 Iustin Pop
      # our terminal went away, we'll exit
2204 225e2544 Iustin Pop
      sys.exit(constants.EXIT_FAILURE)
2205 225e2544 Iustin Pop
    else:
2206 225e2544 Iustin Pop
      raise
2207 a8083063 Iustin Pop
2208 a8083063 Iustin Pop
  return result
2209 137161c9 Michael Hanselmann
2210 137161c9 Michael Hanselmann
2211 845c79d8 Michael Hanselmann
def ParseNicOption(optvalue):
2212 845c79d8 Michael Hanselmann
  """Parses the value of the --net option(s).
2213 845c79d8 Michael Hanselmann

2214 845c79d8 Michael Hanselmann
  """
2215 845c79d8 Michael Hanselmann
  try:
2216 845c79d8 Michael Hanselmann
    nic_max = max(int(nidx[0]) + 1 for nidx in optvalue)
2217 845c79d8 Michael Hanselmann
  except (TypeError, ValueError), err:
2218 845c79d8 Michael Hanselmann
    raise errors.OpPrereqError("Invalid NIC index passed: %s" % str(err))
2219 845c79d8 Michael Hanselmann
2220 845c79d8 Michael Hanselmann
  nics = [{}] * nic_max
2221 845c79d8 Michael Hanselmann
  for nidx, ndict in optvalue:
2222 845c79d8 Michael Hanselmann
    nidx = int(nidx)
2223 845c79d8 Michael Hanselmann
2224 845c79d8 Michael Hanselmann
    if not isinstance(ndict, dict):
2225 845c79d8 Michael Hanselmann
      raise errors.OpPrereqError("Invalid nic/%d value: expected dict,"
2226 845c79d8 Michael Hanselmann
                                 " got %s" % (nidx, ndict))
2227 845c79d8 Michael Hanselmann
2228 845c79d8 Michael Hanselmann
    utils.ForceDictType(ndict, constants.INIC_PARAMS_TYPES)
2229 845c79d8 Michael Hanselmann
2230 845c79d8 Michael Hanselmann
    nics[nidx] = ndict
2231 845c79d8 Michael Hanselmann
2232 845c79d8 Michael Hanselmann
  return nics
2233 845c79d8 Michael Hanselmann
2234 845c79d8 Michael Hanselmann
2235 d77490c5 Iustin Pop
def GenericInstanceCreate(mode, opts, args):
2236 d77490c5 Iustin Pop
  """Add an instance to the cluster via either creation or import.
2237 d77490c5 Iustin Pop

2238 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
2239 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
2240 d77490c5 Iustin Pop
  @type args: list
2241 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
2242 d77490c5 Iustin Pop
  @rtype: int
2243 d77490c5 Iustin Pop
  @return: the desired exit code
2244 d77490c5 Iustin Pop

2245 d77490c5 Iustin Pop
  """
2246 d77490c5 Iustin Pop
  instance = args[0]
2247 d77490c5 Iustin Pop
2248 d77490c5 Iustin Pop
  (pnode, snode) = SplitNodeOption(opts.node)
2249 d77490c5 Iustin Pop
2250 d77490c5 Iustin Pop
  hypervisor = None
2251 d77490c5 Iustin Pop
  hvparams = {}
2252 d77490c5 Iustin Pop
  if opts.hypervisor:
2253 d77490c5 Iustin Pop
    hypervisor, hvparams = opts.hypervisor
2254 d77490c5 Iustin Pop
2255 d77490c5 Iustin Pop
  if opts.nics:
2256 845c79d8 Michael Hanselmann
    nics = ParseNicOption(opts.nics)
2257 d77490c5 Iustin Pop
  elif opts.no_nics:
2258 d77490c5 Iustin Pop
    # no nics
2259 d77490c5 Iustin Pop
    nics = []
2260 0af0f641 Iustin Pop
  elif mode == constants.INSTANCE_CREATE:
2261 d77490c5 Iustin Pop
    # default of one nic, all auto
2262 d77490c5 Iustin Pop
    nics = [{}]
2263 0af0f641 Iustin Pop
  else:
2264 0af0f641 Iustin Pop
    # mode == import
2265 0af0f641 Iustin Pop
    nics = []
2266 d77490c5 Iustin Pop
2267 d77490c5 Iustin Pop
  if opts.disk_template == constants.DT_DISKLESS:
2268 d77490c5 Iustin Pop
    if opts.disks or opts.sd_size is not None:
2269 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Diskless instance but disk"
2270 d77490c5 Iustin Pop
                                 " information passed")
2271 d77490c5 Iustin Pop
    disks = []
2272 d77490c5 Iustin Pop
  else:
2273 9b12ed0f Iustin Pop
    if (not opts.disks and not opts.sd_size
2274 9b12ed0f Iustin Pop
        and mode == constants.INSTANCE_CREATE):
2275 d77490c5 Iustin Pop
      raise errors.OpPrereqError("No disk information specified")
2276 d77490c5 Iustin Pop
    if opts.disks and opts.sd_size is not None:
2277 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Please use either the '--disk' or"
2278 d77490c5 Iustin Pop
                                 " '-s' option")
2279 d77490c5 Iustin Pop
    if opts.sd_size is not None:
2280 ccfa86ba Michael Hanselmann
      opts.disks = [(0, {constants.IDISK_SIZE: opts.sd_size})]
2281 9b12ed0f Iustin Pop
2282 9b12ed0f Iustin Pop
    if opts.disks:
2283 9b12ed0f Iustin Pop
      try:
2284 9b12ed0f Iustin Pop
        disk_max = max(int(didx[0]) + 1 for didx in opts.disks)
2285 9b12ed0f Iustin Pop
      except ValueError, err:
2286 9b12ed0f Iustin Pop
        raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err))
2287 9b12ed0f Iustin Pop
      disks = [{}] * disk_max
2288 9b12ed0f Iustin Pop
    else:
2289 9b12ed0f Iustin Pop
      disks = []
2290 d77490c5 Iustin Pop
    for didx, ddict in opts.disks:
2291 d77490c5 Iustin Pop
      didx = int(didx)
2292 d77490c5 Iustin Pop
      if not isinstance(ddict, dict):
2293 d77490c5 Iustin Pop
        msg = "Invalid disk/%d value: expected dict, got %s" % (didx, ddict)
2294 d77490c5 Iustin Pop
        raise errors.OpPrereqError(msg)
2295 ccfa86ba Michael Hanselmann
      elif constants.IDISK_SIZE in ddict:
2296 ccfa86ba Michael Hanselmann
        if constants.IDISK_ADOPT in ddict:
2297 5029db65 Iustin Pop
          raise errors.OpPrereqError("Only one of 'size' and 'adopt' allowed"
2298 5029db65 Iustin Pop
                                     " (disk %d)" % didx)
2299 5029db65 Iustin Pop
        try:
2300 ccfa86ba Michael Hanselmann
          ddict[constants.IDISK_SIZE] = \
2301 ccfa86ba Michael Hanselmann
            utils.ParseUnit(ddict[constants.IDISK_SIZE])
2302 5029db65 Iustin Pop
        except ValueError, err:
2303 5029db65 Iustin Pop
          raise errors.OpPrereqError("Invalid disk size for disk %d: %s" %
2304 5029db65 Iustin Pop
                                     (didx, err))
2305 ccfa86ba Michael Hanselmann
      elif constants.IDISK_ADOPT in ddict:
2306 5029db65 Iustin Pop
        if mode == constants.INSTANCE_IMPORT:
2307 5029db65 Iustin Pop
          raise errors.OpPrereqError("Disk adoption not allowed for instance"
2308 5029db65 Iustin Pop
                                     " import")
2309 ccfa86ba Michael Hanselmann
        ddict[constants.IDISK_SIZE] = 0
2310 5029db65 Iustin Pop
      else:
2311 5029db65 Iustin Pop
        raise errors.OpPrereqError("Missing size or adoption source for"
2312 5029db65 Iustin Pop
                                   " disk %d" % didx)
2313 d77490c5 Iustin Pop
      disks[didx] = ddict
2314 d77490c5 Iustin Pop
2315 a57981c5 Apollon Oikonomopoulos
  if opts.tags is not None:
2316 0f8810df Michael Hanselmann
    tags = opts.tags.split(",")
2317 a57981c5 Apollon Oikonomopoulos
  else:
2318 a57981c5 Apollon Oikonomopoulos
    tags = []
2319 a57981c5 Apollon Oikonomopoulos
2320 b2e233a5 Guido Trotter
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_COMPAT)
2321 d77490c5 Iustin Pop
  utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
2322 d77490c5 Iustin Pop
2323 d77490c5 Iustin Pop
  if mode == constants.INSTANCE_CREATE:
2324 d77490c5 Iustin Pop
    start = opts.start
2325 d77490c5 Iustin Pop
    os_type = opts.os
2326 1ee8e01a Guido Trotter
    force_variant = opts.force_variant
2327 d77490c5 Iustin Pop
    src_node = None
2328 d77490c5 Iustin Pop
    src_path = None
2329 25a8792c Iustin Pop
    no_install = opts.no_install
2330 e588764d Iustin Pop
    identify_defaults = False
2331 d77490c5 Iustin Pop
  elif mode == constants.INSTANCE_IMPORT:
2332 d77490c5 Iustin Pop
    start = False
2333 d77490c5 Iustin Pop
    os_type = None
2334 1ee8e01a Guido Trotter
    force_variant = False
2335 d77490c5 Iustin Pop
    src_node = opts.src_node
2336 d77490c5 Iustin Pop
    src_path = opts.src_dir
2337 25a8792c Iustin Pop
    no_install = None
2338 e588764d Iustin Pop
    identify_defaults = opts.identify_defaults
2339 d77490c5 Iustin Pop
  else:
2340 d77490c5 Iustin Pop
    raise errors.ProgrammerError("Invalid creation mode %s" % mode)
2341 d77490c5 Iustin Pop
2342 e1530b10 Iustin Pop
  op = opcodes.OpInstanceCreate(instance_name=instance,
2343 d77490c5 Iustin Pop
                                disks=disks,
2344 d77490c5 Iustin Pop
                                disk_template=opts.disk_template,
2345 d77490c5 Iustin Pop
                                nics=nics,
2346 d77490c5 Iustin Pop
                                pnode=pnode, snode=snode,
2347 d77490c5 Iustin Pop
                                ip_check=opts.ip_check,
2348 460d22be Iustin Pop
                                name_check=opts.name_check,
2349 d77490c5 Iustin Pop
                                wait_for_sync=opts.wait_for_sync,
2350 d77490c5 Iustin Pop
                                file_storage_dir=opts.file_storage_dir,
2351 d77490c5 Iustin Pop
                                file_driver=opts.file_driver,
2352 d77490c5 Iustin Pop
                                iallocator=opts.iallocator,
2353 d77490c5 Iustin Pop
                                hypervisor=hypervisor,
2354 d77490c5 Iustin Pop
                                hvparams=hvparams,
2355 d77490c5 Iustin Pop
                                beparams=opts.beparams,
2356 062a7100 Iustin Pop
                                osparams=opts.osparams,
2357 d77490c5 Iustin Pop
                                mode=mode,
2358 d77490c5 Iustin Pop
                                start=start,
2359 d77490c5 Iustin Pop
                                os_type=os_type,
2360 1ee8e01a Guido Trotter
                                force_variant=force_variant,
2361 d77490c5 Iustin Pop
                                src_node=src_node,
2362 25a8792c Iustin Pop
                                src_path=src_path,
2363 a57981c5 Apollon Oikonomopoulos
                                tags=tags,
2364 e588764d Iustin Pop
                                no_install=no_install,
2365 10889e0c René Nussbaumer
                                identify_defaults=identify_defaults,
2366 10889e0c René Nussbaumer
                                ignore_ipolicy=opts.ignore_ipolicy)
2367 d77490c5 Iustin Pop
2368 d77490c5 Iustin Pop
  SubmitOrSend(op, opts)
2369 d77490c5 Iustin Pop
  return 0
2370 d77490c5 Iustin Pop
2371 d77490c5 Iustin Pop
2372 7e49b6ce Michael Hanselmann
class _RunWhileClusterStoppedHelper:
2373 7e49b6ce Michael Hanselmann
  """Helper class for L{RunWhileClusterStopped} to simplify state management
2374 7e49b6ce Michael Hanselmann

2375 7e49b6ce Michael Hanselmann
  """
2376 7e49b6ce Michael Hanselmann
  def __init__(self, feedback_fn, cluster_name, master_node, online_nodes):
2377 7e49b6ce Michael Hanselmann
    """Initializes this class.
2378 7e49b6ce Michael Hanselmann

2379 7e49b6ce Michael Hanselmann
    @type feedback_fn: callable
2380 7e49b6ce Michael Hanselmann
    @param feedback_fn: Feedback function
2381 7e49b6ce Michael Hanselmann
    @type cluster_name: string
2382 7e49b6ce Michael Hanselmann
    @param cluster_name: Cluster name
2383 7e49b6ce Michael Hanselmann
    @type master_node: string
2384 7e49b6ce Michael Hanselmann
    @param master_node Master node name
2385 7e49b6ce Michael Hanselmann
    @type online_nodes: list
2386 7e49b6ce Michael Hanselmann
    @param online_nodes: List of names of online nodes
2387 7e49b6ce Michael Hanselmann

2388 7e49b6ce Michael Hanselmann
    """
2389 7e49b6ce Michael Hanselmann
    self.feedback_fn = feedback_fn
2390 7e49b6ce Michael Hanselmann
    self.cluster_name = cluster_name
2391 7e49b6ce Michael Hanselmann
    self.master_node = master_node
2392 7e49b6ce Michael Hanselmann
    self.online_nodes = online_nodes
2393 7e49b6ce Michael Hanselmann
2394 7e49b6ce Michael Hanselmann
    self.ssh = ssh.SshRunner(self.cluster_name)
2395 7e49b6ce Michael Hanselmann
2396 7e49b6ce Michael Hanselmann
    self.nonmaster_nodes = [name for name in online_nodes
2397 7e49b6ce Michael Hanselmann
                            if name != master_node]
2398 7e49b6ce Michael Hanselmann
2399 7e49b6ce Michael Hanselmann
    assert self.master_node not in self.nonmaster_nodes
2400 7e49b6ce Michael Hanselmann
2401 7e49b6ce Michael Hanselmann
  def _RunCmd(self, node_name, cmd):
2402 7e49b6ce Michael Hanselmann
    """Runs a command on the local or a remote machine.
2403 7e49b6ce Michael Hanselmann

2404 7e49b6ce Michael Hanselmann
    @type node_name: string
2405 7e49b6ce Michael Hanselmann
    @param node_name: Machine name
2406 7e49b6ce Michael Hanselmann
    @type cmd: list
2407 7e49b6ce Michael Hanselmann
    @param cmd: Command
2408 7e49b6ce Michael Hanselmann

2409 7e49b6ce Michael Hanselmann
    """
2410 7e49b6ce Michael Hanselmann
    if node_name is None or node_name == self.master_node:
2411 7e49b6ce Michael Hanselmann
      # No need to use SSH
2412 7e49b6ce Michael Hanselmann
      result = utils.RunCmd(cmd)
2413 7e49b6ce Michael Hanselmann
    else:
2414 7e49b6ce Michael Hanselmann
      result = self.ssh.Run(node_name, "root", utils.ShellQuoteArgs(cmd))
2415 7e49b6ce Michael Hanselmann
2416 7e49b6ce Michael Hanselmann
    if result.failed:
2417 7e49b6ce Michael Hanselmann
      errmsg = ["Failed to run command %s" % result.cmd]
2418 7e49b6ce Michael Hanselmann
      if node_name:
2419 7e49b6ce Michael Hanselmann
        errmsg.append("on node %s" % node_name)
2420 7e49b6ce Michael Hanselmann
      errmsg.append(": exitcode %s and error %s" %
2421 7e49b6ce Michael Hanselmann
                    (result.exit_code, result.output))
2422 7e49b6ce Michael Hanselmann
      raise errors.OpExecError(" ".join(errmsg))
2423 7e49b6ce Michael Hanselmann
2424 7e49b6ce Michael Hanselmann
  def Call(self, fn, *args):
2425 7e49b6ce Michael Hanselmann
    """Call function while all daemons are stopped.
2426 7e49b6ce Michael Hanselmann

2427 7e49b6ce Michael Hanselmann
    @type fn: callable
2428 7e49b6ce Michael Hanselmann
    @param fn: Function to be called
2429 7e49b6ce Michael Hanselmann

2430 7e49b6ce Michael Hanselmann
    """
2431 7e49b6ce Michael Hanselmann
    # Pause watcher by acquiring an exclusive lock on watcher state file
2432 7e49b6ce Michael Hanselmann
    self.feedback_fn("Blocking watcher")
2433 16e0b9c9 Michael Hanselmann
    watcher_block = utils.FileLock.Open(constants.WATCHER_LOCK_FILE)
2434 7e49b6ce Michael Hanselmann
    try:
2435 7e49b6ce Michael Hanselmann
      # TODO: Currently, this just blocks. There's no timeout.
2436 7e49b6ce Michael Hanselmann
      # TODO: Should it be a shared lock?
2437 7e49b6ce Michael Hanselmann
      watcher_block.Exclusive(blocking=True)
2438 7e49b6ce Michael Hanselmann
2439 7e49b6ce Michael Hanselmann
      # Stop master daemons, so that no new jobs can come in and all running
2440 7e49b6ce Michael Hanselmann
      # ones are finished
2441 7e49b6ce Michael Hanselmann
      self.feedback_fn("Stopping master daemons")
2442 7e49b6ce Michael Hanselmann
      self._RunCmd(None, [constants.DAEMON_UTIL, "stop-master"])
2443 7e49b6ce Michael Hanselmann
      try:
2444 7e49b6ce Michael Hanselmann
        # Stop daemons on all nodes
2445 7e49b6ce Michael Hanselmann
        for node_name in self.online_nodes:
2446 7e49b6ce Michael Hanselmann
          self.feedback_fn("Stopping daemons on %s" % node_name)
2447 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "stop-all"])
2448 7e49b6ce Michael Hanselmann
2449 7e49b6ce Michael Hanselmann
        # All daemons are shut down now
2450 7e49b6ce Michael Hanselmann
        try:
2451 7e49b6ce Michael Hanselmann
          return fn(self, *args)
2452 d512e84b Michael Hanselmann
        except Exception, err:
2453 d512e84b Michael Hanselmann
          _, errmsg = FormatError(err)
2454 7e49b6ce Michael Hanselmann
          logging.exception("Caught exception")
2455 d512e84b Michael Hanselmann
          self.feedback_fn(errmsg)
2456 7e49b6ce Michael Hanselmann
          raise
2457 7e49b6ce Michael Hanselmann
      finally:
2458 7e49b6ce Michael Hanselmann
        # Start cluster again, master node last
2459 7e49b6ce Michael Hanselmann
        for node_name in self.nonmaster_nodes + [self.master_node]:
2460 7e49b6ce Michael Hanselmann
          self.feedback_fn("Starting daemons on %s" % node_name)
2461 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "start-all"])
2462 7e49b6ce Michael Hanselmann
    finally:
2463 7e49b6ce Michael Hanselmann
      # Resume watcher
2464 7e49b6ce Michael Hanselmann
      watcher_block.Close()
2465 7e49b6ce Michael Hanselmann
2466 7e49b6ce Michael Hanselmann
2467 7e49b6ce Michael Hanselmann
def RunWhileClusterStopped(feedback_fn, fn, *args):
2468 7e49b6ce Michael Hanselmann
  """Calls a function while all cluster daemons are stopped.
2469 7e49b6ce Michael Hanselmann

2470 7e49b6ce Michael Hanselmann
  @type feedback_fn: callable
2471 7e49b6ce Michael Hanselmann
  @param feedback_fn: Feedback function
2472 7e49b6ce Michael Hanselmann
  @type fn: callable
2473 7e49b6ce Michael Hanselmann
  @param fn: Function to be called when daemons are stopped
2474 7e49b6ce Michael Hanselmann

2475 7e49b6ce Michael Hanselmann
  """
2476 7e49b6ce Michael Hanselmann
  feedback_fn("Gathering cluster information")
2477 7e49b6ce Michael Hanselmann
2478 7e49b6ce Michael Hanselmann
  # This ensures we're running on the master daemon
2479 7e49b6ce Michael Hanselmann
  cl = GetClient()
2480 7e49b6ce Michael Hanselmann
2481 7e49b6ce Michael Hanselmann
  (cluster_name, master_node) = \
2482 7e49b6ce Michael Hanselmann
    cl.QueryConfigValues(["cluster_name", "master_node"])
2483 7e49b6ce Michael Hanselmann
2484 7e49b6ce Michael Hanselmann
  online_nodes = GetOnlineNodes([], cl=cl)
2485 7e49b6ce Michael Hanselmann
2486 7e49b6ce Michael Hanselmann
  # Don't keep a reference to the client. The master daemon will go away.
2487 7e49b6ce Michael Hanselmann
  del cl
2488 7e49b6ce Michael Hanselmann
2489 7e49b6ce Michael Hanselmann
  assert master_node in online_nodes
2490 7e49b6ce Michael Hanselmann
2491 7e49b6ce Michael Hanselmann
  return _RunWhileClusterStoppedHelper(feedback_fn, cluster_name, master_node,
2492 7e49b6ce Michael Hanselmann
                                       online_nodes).Call(fn, *args)
2493 7e49b6ce Michael Hanselmann
2494 7e49b6ce Michael Hanselmann
2495 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
2496 9fbfbb7b Iustin Pop
                  numfields=None, unitfields=None,
2497 9fbfbb7b Iustin Pop
                  units=None):
2498 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
2499 137161c9 Michael Hanselmann

2500 9fbfbb7b Iustin Pop
  @type headers: dict
2501 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
2502 9fbfbb7b Iustin Pop
      the table
2503 9fbfbb7b Iustin Pop
  @type fields: list
2504 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
2505 9fbfbb7b Iustin Pop
      the data field
2506 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
2507 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
2508 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
2509 9fbfbb7b Iustin Pop
      each field
2510 9fbfbb7b Iustin Pop
  @type data: list
2511 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
2512 9fbfbb7b Iustin Pop
  @type numfields: list
2513 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
2514 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
2515 9fbfbb7b Iustin Pop
  @type unitfields: list
2516 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
2517 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
2518 9fbfbb7b Iustin Pop
  @type units: string or None
2519 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
2520 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
2521 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
2522 137161c9 Michael Hanselmann

2523 137161c9 Michael Hanselmann
  """
2524 9fbfbb7b Iustin Pop
  if units is None:
2525 9fbfbb7b Iustin Pop
    if separator:
2526 9fbfbb7b Iustin Pop
      units = "m"
2527 9fbfbb7b Iustin Pop
    else:
2528 9fbfbb7b Iustin Pop
      units = "h"
2529 9fbfbb7b Iustin Pop
2530 137161c9 Michael Hanselmann
  if numfields is None:
2531 137161c9 Michael Hanselmann
    numfields = []
2532 137161c9 Michael Hanselmann
  if unitfields is None:
2533 137161c9 Michael Hanselmann
    unitfields = []
2534 137161c9 Michael Hanselmann
2535 b459a848 Andrea Spadaccini
  numfields = utils.FieldSet(*numfields)   # pylint: disable=W0142
2536 b459a848 Andrea Spadaccini
  unitfields = utils.FieldSet(*unitfields) # pylint: disable=W0142
2537 00430f8e Iustin Pop
2538 137161c9 Michael Hanselmann
  format_fields = []
2539 137161c9 Michael Hanselmann
  for field in fields:
2540 01ca31ae Iustin Pop
    if headers and field not in headers:
2541 ea5a5b74 Guido Trotter
      # TODO: handle better unknown fields (either revert to old
2542 71c1af58 Iustin Pop
      # style of raising exception, or deal more intelligently with
2543 71c1af58 Iustin Pop
      # variable fields)
2544 71c1af58 Iustin Pop
      headers[field] = field
2545 137161c9 Michael Hanselmann
    if separator is not None:
2546 137161c9 Michael Hanselmann
      format_fields.append("%s")
2547 00430f8e Iustin Pop
    elif numfields.Matches(field):
2548 137161c9 Michael Hanselmann
      format_fields.append("%*s")
2549 137161c9 Michael Hanselmann
    else:
2550 137161c9 Michael Hanselmann
      format_fields.append("%-*s")
2551 137161c9 Michael Hanselmann
2552 137161c9 Michael Hanselmann
  if separator is None:
2553 137161c9 Michael Hanselmann
    mlens = [0 for name in fields]
2554 d0c8c01d Iustin Pop
    format_str = " ".join(format_fields)
2555 137161c9 Michael Hanselmann
  else:
2556 c04bc777 Iustin Pop
    format_str = separator.replace("%", "%%").join(format_fields)
2557 137161c9 Michael Hanselmann
2558 137161c9 Michael Hanselmann
  for row in data:
2559 dcbd6288 Guido Trotter
    if row is None:
2560 dcbd6288 Guido Trotter
      continue
2561 137161c9 Michael Hanselmann
    for idx, val in enumerate(row):
2562 00430f8e Iustin Pop
      if unitfields.Matches(fields[idx]):
2563 137161c9 Michael Hanselmann
        try:
2564 137161c9 Michael Hanselmann
          val = int(val)
2565 691744c4 Iustin Pop
        except (TypeError, ValueError):
2566 137161c9 Michael Hanselmann
          pass
2567 137161c9 Michael Hanselmann
        else:
2568 9fbfbb7b Iustin Pop
          val = row[idx] = utils.FormatUnit(val, units)
2569 01ca31ae Iustin Pop
      val = row[idx] = str(val)
2570 137161c9 Michael Hanselmann
      if separator is None:
2571 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(val))
2572 137161c9 Michael Hanselmann
2573 16be8703 Iustin Pop
  result = []
2574 137161c9 Michael Hanselmann
  if headers:
2575 137161c9 Michael Hanselmann
    args = []
2576 137161c9 Michael Hanselmann
    for idx, name in enumerate(fields):
2577 137161c9 Michael Hanselmann
      hdr = headers[name]
2578 137161c9 Michael Hanselmann
      if separator is None:
2579 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(hdr))
2580 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2581 137161c9 Michael Hanselmann
      args.append(hdr)
2582 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2583 137161c9 Michael Hanselmann
2584 ec39d63c Michael Hanselmann
  if separator is None:
2585 ec39d63c Michael Hanselmann
    assert len(mlens) == len(fields)
2586 ec39d63c Michael Hanselmann
2587 ec39d63c Michael Hanselmann
    if fields and not numfields.Matches(fields[-1]):
2588 ec39d63c Michael Hanselmann
      mlens[-1] = 0
2589 ec39d63c Michael Hanselmann
2590 137161c9 Michael Hanselmann
  for line in data:
2591 137161c9 Michael Hanselmann
    args = []
2592 dcbd6288 Guido Trotter
    if line is None:
2593 d0c8c01d Iustin Pop
      line = ["-" for _ in fields]
2594 f1501b3f Michael Hanselmann
    for idx in range(len(fields)):
2595 137161c9 Michael Hanselmann
      if separator is None:
2596 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2597 137161c9 Michael Hanselmann
      args.append(line[idx])
2598 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2599 16be8703 Iustin Pop
2600 16be8703 Iustin Pop
  return result
2601 3386e7a9 Iustin Pop
2602 3386e7a9 Iustin Pop
2603 ee3aedff Michael Hanselmann
def _FormatBool(value):
2604 ee3aedff Michael Hanselmann
  """Formats a boolean value as a string.
2605 ee3aedff Michael Hanselmann

2606 ee3aedff Michael Hanselmann
  """
2607 ee3aedff Michael Hanselmann
  if value:
2608 ee3aedff Michael Hanselmann
    return "Y"
2609 ee3aedff Michael Hanselmann
  return "N"
2610 ee3aedff Michael Hanselmann
2611 ee3aedff Michael Hanselmann
2612 ee3aedff Michael Hanselmann
#: Default formatting for query results; (callback, align right)
2613 ee3aedff Michael Hanselmann
_DEFAULT_FORMAT_QUERY = {
2614 ee3aedff Michael Hanselmann
  constants.QFT_TEXT: (str, False),
2615 ee3aedff Michael Hanselmann
  constants.QFT_BOOL: (_FormatBool, False),
2616 ee3aedff Michael Hanselmann
  constants.QFT_NUMBER: (str, True),
2617 ee3aedff Michael Hanselmann
  constants.QFT_TIMESTAMP: (utils.FormatTime, False),
2618 ee3aedff Michael Hanselmann
  constants.QFT_OTHER: (str, False),
2619 ee3aedff Michael Hanselmann
  constants.QFT_UNKNOWN: (str, False),
2620 ee3aedff Michael Hanselmann
  }
2621 ee3aedff Michael Hanselmann
2622 ee3aedff Michael Hanselmann
2623 ee3aedff Michael Hanselmann
def _GetColumnFormatter(fdef, override, unit):
2624 ee3aedff Michael Hanselmann
  """Returns formatting function for a field.
2625 ee3aedff Michael Hanselmann

2626 ee3aedff Michael Hanselmann
  @type fdef: L{objects.QueryFieldDefinition}
2627 ee3aedff Michael Hanselmann
  @type override: dict
2628 ee3aedff Michael Hanselmann
  @param override: Dictionary for overriding field formatting functions,
2629 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2630 ee3aedff Michael Hanselmann
  @type unit: string
2631 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT}
2632 ee3aedff Michael Hanselmann
  @rtype: tuple; (callable, bool)
2633 ee3aedff Michael Hanselmann
  @return: Returns the function to format a value (takes one parameter) and a
2634 ee3aedff Michael Hanselmann
    boolean for aligning the value on the right-hand side
2635 ee3aedff Michael Hanselmann

2636 ee3aedff Michael Hanselmann
  """
2637 ee3aedff Michael Hanselmann
  fmt = override.get(fdef.name, None)
2638 ee3aedff Michael Hanselmann
  if fmt is not None:
2639 ee3aedff Michael Hanselmann
    return fmt
2640 ee3aedff Michael Hanselmann
2641 ee3aedff Michael Hanselmann
  assert constants.QFT_UNIT not in _DEFAULT_FORMAT_QUERY
2642 ee3aedff Michael Hanselmann
2643 ee3aedff Michael Hanselmann
  if fdef.kind == constants.QFT_UNIT:
2644 ee3aedff Michael Hanselmann
    # Can't keep this information in the static dictionary
2645 ee3aedff Michael Hanselmann
    return (lambda value: utils.FormatUnit(value, unit), True)
2646 ee3aedff Michael Hanselmann
2647 ee3aedff Michael Hanselmann
  fmt = _DEFAULT_FORMAT_QUERY.get(fdef.kind, None)
2648 ee3aedff Michael Hanselmann
  if fmt is not None:
2649 ee3aedff Michael Hanselmann
    return fmt
2650 ee3aedff Michael Hanselmann
2651 ee3aedff Michael Hanselmann
  raise NotImplementedError("Can't format column type '%s'" % fdef.kind)
2652 ee3aedff Michael Hanselmann
2653 ee3aedff Michael Hanselmann
2654 ee3aedff Michael Hanselmann
class _QueryColumnFormatter:
2655 ee3aedff Michael Hanselmann
  """Callable class for formatting fields of a query.
2656 ee3aedff Michael Hanselmann

2657 ee3aedff Michael Hanselmann
  """
2658 f0b1bafe Iustin Pop
  def __init__(self, fn, status_fn, verbose):
2659 ee3aedff Michael Hanselmann
    """Initializes this class.
2660 ee3aedff Michael Hanselmann

2661 ee3aedff Michael Hanselmann
    @type fn: callable
2662 ee3aedff Michael Hanselmann
    @param fn: Formatting function
2663 ee3aedff Michael Hanselmann
    @type status_fn: callable
2664 ee3aedff Michael Hanselmann
    @param status_fn: Function to report fields' status
2665 f0b1bafe Iustin Pop
    @type verbose: boolean
2666 f0b1bafe Iustin Pop
    @param verbose: whether to use verbose field descriptions or not
2667 ee3aedff Michael Hanselmann

2668 ee3aedff Michael Hanselmann
    """
2669 ee3aedff Michael Hanselmann
    self._fn = fn
2670 ee3aedff Michael Hanselmann
    self._status_fn = status_fn
2671 cbfa4f0f Michael Hanselmann
    self._verbose = verbose
2672 ee3aedff Michael Hanselmann
2673 ee3aedff Michael Hanselmann
  def __call__(self, data):
2674 ee3aedff Michael Hanselmann
    """Returns a field's string representation.
2675 ee3aedff Michael Hanselmann

2676 ee3aedff Michael Hanselmann
    """
2677 ee3aedff Michael Hanselmann
    (status, value) = data
2678 ee3aedff Michael Hanselmann
2679 ee3aedff Michael Hanselmann
    # Report status
2680 ee3aedff Michael Hanselmann
    self._status_fn(status)
2681 ee3aedff Michael Hanselmann
2682 cfb084ae René Nussbaumer
    if status == constants.RS_NORMAL:
2683 ee3aedff Michael Hanselmann
      return self._fn(value)
2684 ee3aedff Michael Hanselmann
2685 ee3aedff Michael Hanselmann
    assert value is None, \
2686 ee3aedff Michael Hanselmann
           "Found value %r for abnormal status %s" % (value, status)
2687 ee3aedff Michael Hanselmann
2688 f2c6673d Michael Hanselmann
    return FormatResultError(status, self._verbose)
2689 ee3aedff Michael Hanselmann
2690 ee3aedff Michael Hanselmann
2691 f2c6673d Michael Hanselmann
def FormatResultError(status, verbose):
2692 ae95e419 René Nussbaumer
  """Formats result status other than L{constants.RS_NORMAL}.
2693 ee3aedff Michael Hanselmann

2694 ae95e419 René Nussbaumer
  @param status: The result status
2695 f2c6673d Michael Hanselmann
  @type verbose: boolean
2696 f2c6673d Michael Hanselmann
  @param verbose: Whether to return the verbose text
2697 ae95e419 René Nussbaumer
  @return: Text of result status
2698 a6070ef7 Michael Hanselmann

2699 ae95e419 René Nussbaumer
  """
2700 ae95e419 René Nussbaumer
  assert status != constants.RS_NORMAL, \
2701 cbfa4f0f Michael Hanselmann
         "FormatResultError called with status equal to constants.RS_NORMAL"
2702 ae95e419 René Nussbaumer
  try:
2703 cbfa4f0f Michael Hanselmann
    (verbose_text, normal_text) = constants.RSS_DESCRIPTION[status]
2704 ae95e419 René Nussbaumer
  except KeyError:
2705 ee3aedff Michael Hanselmann
    raise NotImplementedError("Unknown status %s" % status)
2706 cbfa4f0f Michael Hanselmann
  else:
2707 cbfa4f0f Michael Hanselmann
    if verbose:
2708 cbfa4f0f Michael Hanselmann
      return verbose_text
2709 cbfa4f0f Michael Hanselmann
    return normal_text
2710 ee3aedff Michael Hanselmann
2711 ee3aedff Michael Hanselmann
2712 ee3aedff Michael Hanselmann
def FormatQueryResult(result, unit=None, format_override=None, separator=None,
2713 f0b1bafe Iustin Pop
                      header=False, verbose=False):
2714 ee3aedff Michael Hanselmann
  """Formats data in L{objects.QueryResponse}.
2715 ee3aedff Michael Hanselmann

2716 ee3aedff Michael Hanselmann
  @type result: L{objects.QueryResponse}
2717 ee3aedff Michael Hanselmann
  @param result: result of query operation
2718 ee3aedff Michael Hanselmann
  @type unit: string
2719 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT},
2720 18009c1e Iustin Pop
    see L{utils.text.FormatUnit}
2721 ee3aedff Michael Hanselmann
  @type format_override: dict
2722 ee3aedff Michael Hanselmann
  @param format_override: Dictionary for overriding field formatting functions,
2723 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2724 ee3aedff Michael Hanselmann
  @type separator: string or None
2725 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2726 ee3aedff Michael Hanselmann
  @type header: bool
2727 ee3aedff Michael Hanselmann
  @param header: Whether to output header row
2728 f0b1bafe Iustin Pop
  @type verbose: boolean
2729 f0b1bafe Iustin Pop
  @param verbose: whether to use verbose field descriptions or not
2730 ee3aedff Michael Hanselmann

2731 ee3aedff Michael Hanselmann
  """
2732 ee3aedff Michael Hanselmann
  if unit is None:
2733 ee3aedff Michael Hanselmann
    if separator:
2734 ee3aedff Michael Hanselmann
      unit = "m"
2735 ee3aedff Michael Hanselmann
    else:
2736 ee3aedff Michael Hanselmann
      unit = "h"
2737 ee3aedff Michael Hanselmann
2738 ee3aedff Michael Hanselmann
  if format_override is None:
2739 ee3aedff Michael Hanselmann
    format_override = {}
2740 ee3aedff Michael Hanselmann
2741 cfb084ae René Nussbaumer
  stats = dict.fromkeys(constants.RS_ALL, 0)
2742 ee3aedff Michael Hanselmann
2743 ee3aedff Michael Hanselmann
  def _RecordStatus(status):
2744 ee3aedff Michael Hanselmann
    if status in stats:
2745 ee3aedff Michael Hanselmann
      stats[status] += 1
2746 ee3aedff Michael Hanselmann
2747 ee3aedff Michael Hanselmann
  columns = []
2748 ee3aedff Michael Hanselmann
  for fdef in result.fields:
2749 ee3aedff Michael Hanselmann
    assert fdef.title and fdef.name
2750 ee3aedff Michael Hanselmann
    (fn, align_right) = _GetColumnFormatter(fdef, format_override, unit)
2751 ee3aedff Michael Hanselmann
    columns.append(TableColumn(fdef.title,
2752 f0b1bafe Iustin Pop
                               _QueryColumnFormatter(fn, _RecordStatus,
2753 f0b1bafe Iustin Pop
                                                     verbose),
2754 ee3aedff Michael Hanselmann
                               align_right))
2755 ee3aedff Michael Hanselmann
2756 ee3aedff Michael Hanselmann
  table = FormatTable(result.data, columns, header, separator)
2757 ee3aedff Michael Hanselmann
2758 ee3aedff Michael Hanselmann
  # Collect statistics
2759 cfb084ae René Nussbaumer
  assert len(stats) == len(constants.RS_ALL)
2760 ee3aedff Michael Hanselmann
  assert compat.all(count >= 0 for count in stats.values())
2761 ee3aedff Michael Hanselmann
2762 ee3aedff Michael Hanselmann
  # Determine overall status. If there was no data, unknown fields must be
2763 ee3aedff Michael Hanselmann
  # detected via the field definitions.
2764 cfb084ae René Nussbaumer
  if (stats[constants.RS_UNKNOWN] or
2765 ee3aedff Michael Hanselmann
      (not result.data and _GetUnknownFields(result.fields))):
2766 ee3aedff Michael Hanselmann
    status = QR_UNKNOWN
2767 ee3aedff Michael Hanselmann
  elif compat.any(count > 0 for key, count in stats.items()
2768 cfb084ae René Nussbaumer
                  if key != constants.RS_NORMAL):
2769 ee3aedff Michael Hanselmann
    status = QR_INCOMPLETE
2770 ee3aedff Michael Hanselmann
  else:
2771 ee3aedff Michael Hanselmann
    status = QR_NORMAL
2772 ee3aedff Michael Hanselmann
2773 ee3aedff Michael Hanselmann
  return (status, table)
2774 ee3aedff Michael Hanselmann
2775 ee3aedff Michael Hanselmann
2776 ee3aedff Michael Hanselmann
def _GetUnknownFields(fdefs):
2777 ee3aedff Michael Hanselmann
  """Returns list of unknown fields included in C{fdefs}.
2778 ee3aedff Michael Hanselmann

2779 ee3aedff Michael Hanselmann
  @type fdefs: list of L{objects.QueryFieldDefinition}
2780 ee3aedff Michael Hanselmann

2781 ee3aedff Michael Hanselmann
  """
2782 ee3aedff Michael Hanselmann
  return [fdef for fdef in fdefs
2783 ee3aedff Michael Hanselmann
          if fdef.kind == constants.QFT_UNKNOWN]
2784 ee3aedff Michael Hanselmann
2785 ee3aedff Michael Hanselmann
2786 ee3aedff Michael Hanselmann
def _WarnUnknownFields(fdefs):
2787 ee3aedff Michael Hanselmann
  """Prints a warning to stderr if a query included unknown fields.
2788 ee3aedff Michael Hanselmann

2789 ee3aedff Michael Hanselmann
  @type fdefs: list of L{objects.QueryFieldDefinition}
2790 ee3aedff Michael Hanselmann

2791 ee3aedff Michael Hanselmann
  """
2792 ee3aedff Michael Hanselmann
  unknown = _GetUnknownFields(fdefs)
2793 ee3aedff Michael Hanselmann
  if unknown:
2794 ee3aedff Michael Hanselmann
    ToStderr("Warning: Queried for unknown fields %s",
2795 ee3aedff Michael Hanselmann
             utils.CommaJoin(fdef.name for fdef in unknown))
2796 ee3aedff Michael Hanselmann
    return True
2797 ee3aedff Michael Hanselmann
2798 ee3aedff Michael Hanselmann
  return False
2799 ee3aedff Michael Hanselmann
2800 ee3aedff Michael Hanselmann
2801 ee3aedff Michael Hanselmann
def GenericList(resource, fields, names, unit, separator, header, cl=None,
2802 2928de47 Michael Hanselmann
                format_override=None, verbose=False, force_filter=False):
2803 ee3aedff Michael Hanselmann
  """Generic implementation for listing all items of a resource.
2804 ee3aedff Michael Hanselmann

2805 abd66bf8 Michael Hanselmann
  @param resource: One of L{constants.QR_VIA_LUXI}
2806 ee3aedff Michael Hanselmann
  @type fields: list of strings
2807 ee3aedff Michael Hanselmann
  @param fields: List of fields to query for
2808 ee3aedff Michael Hanselmann
  @type names: list of strings
2809 ee3aedff Michael Hanselmann
  @param names: Names of items to query for
2810 ee3aedff Michael Hanselmann
  @type unit: string or None
2811 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT} or
2812 ee3aedff Michael Hanselmann
    None for automatic choice (human-readable for non-separator usage,
2813 ee3aedff Michael Hanselmann
    otherwise megabytes); this is a one-letter string
2814 ee3aedff Michael Hanselmann
  @type separator: string or None
2815 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2816 ee3aedff Michael Hanselmann
  @type header: bool
2817 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2818 2928de47 Michael Hanselmann
  @type force_filter: bool
2819 2928de47 Michael Hanselmann
  @param force_filter: Whether to always treat names as filter
2820 ee3aedff Michael Hanselmann
  @type format_override: dict
2821 ee3aedff Michael Hanselmann
  @param format_override: Dictionary for overriding field formatting functions,
2822 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2823 f0b1bafe Iustin Pop
  @type verbose: boolean
2824 f0b1bafe Iustin Pop
  @param verbose: whether to use verbose field descriptions or not
2825 ee3aedff Michael Hanselmann

2826 ee3aedff Michael Hanselmann
  """
2827 ee3aedff Michael Hanselmann
  if not names:
2828 ee3aedff Michael Hanselmann
    names = None
2829 ee3aedff Michael Hanselmann
2830 2e5c33db Iustin Pop
  qfilter = qlang.MakeFilter(names, force_filter)
2831 2928de47 Michael Hanselmann
2832 727274dd Iustin Pop
  if cl is None:
2833 727274dd Iustin Pop
    cl = GetClient()
2834 727274dd Iustin Pop
2835 2e5c33db Iustin Pop
  response = cl.Query(resource, fields, qfilter)
2836 ee3aedff Michael Hanselmann
2837 ee3aedff Michael Hanselmann
  found_unknown = _WarnUnknownFields(response.fields)
2838 ee3aedff Michael Hanselmann
2839 ee3aedff Michael Hanselmann
  (status, data) = FormatQueryResult(response, unit=unit, separator=separator,
2840 ee3aedff Michael Hanselmann
                                     header=header,
2841 f0b1bafe Iustin Pop
                                     format_override=format_override,
2842 f0b1bafe Iustin Pop
                                     verbose=verbose)
2843 ee3aedff Michael Hanselmann
2844 ee3aedff Michael Hanselmann
  for line in data:
2845 ee3aedff Michael Hanselmann
    ToStdout(line)
2846 ee3aedff Michael Hanselmann
2847 ee3aedff Michael Hanselmann
  assert ((found_unknown and status == QR_UNKNOWN) or
2848 ee3aedff Michael Hanselmann
          (not found_unknown and status != QR_UNKNOWN))
2849 ee3aedff Michael Hanselmann
2850 ee3aedff Michael Hanselmann
  if status == QR_UNKNOWN:
2851 ee3aedff Michael Hanselmann
    return constants.EXIT_UNKNOWN_FIELD
2852 ee3aedff Michael Hanselmann
2853 ee3aedff Michael Hanselmann
  # TODO: Should the list command fail if not all data could be collected?
2854 ee3aedff Michael Hanselmann
  return constants.EXIT_SUCCESS
2855 ee3aedff Michael Hanselmann
2856 ee3aedff Michael Hanselmann
2857 ee3aedff Michael Hanselmann
def GenericListFields(resource, fields, separator, header, cl=None):
2858 ee3aedff Michael Hanselmann
  """Generic implementation for listing fields for a resource.
2859 ee3aedff Michael Hanselmann

2860 abd66bf8 Michael Hanselmann
  @param resource: One of L{constants.QR_VIA_LUXI}
2861 ee3aedff Michael Hanselmann
  @type fields: list of strings
2862 ee3aedff Michael Hanselmann
  @param fields: List of fields to query for
2863 ee3aedff Michael Hanselmann
  @type separator: string or None
2864 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2865 ee3aedff Michael Hanselmann
  @type header: bool
2866 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2867 ee3aedff Michael Hanselmann

2868 ee3aedff Michael Hanselmann
  """
2869 ee3aedff Michael Hanselmann
  if cl is None:
2870 ee3aedff Michael Hanselmann
    cl = GetClient()
2871 ee3aedff Michael Hanselmann
2872 ee3aedff Michael Hanselmann
  if not fields:
2873 ee3aedff Michael Hanselmann
    fields = None
2874 ee3aedff Michael Hanselmann
2875 ee3aedff Michael Hanselmann
  response = cl.QueryFields(resource, fields)
2876 ee3aedff Michael Hanselmann
2877 ee3aedff Michael Hanselmann
  found_unknown = _WarnUnknownFields(response.fields)
2878 ee3aedff Michael Hanselmann
2879 ee3aedff Michael Hanselmann
  columns = [
2880 ee3aedff Michael Hanselmann
    TableColumn("Name", str, False),
2881 ee3aedff Michael Hanselmann
    TableColumn("Title", str, False),
2882 ea1440c1 Michael Hanselmann
    TableColumn("Description", str, False),
2883 ee3aedff Michael Hanselmann
    ]
2884 ee3aedff Michael Hanselmann
2885 ea1440c1 Michael Hanselmann
  rows = [[fdef.name, fdef.title, fdef.doc] for fdef in response.fields]
2886 ee3aedff Michael Hanselmann
2887 ee3aedff Michael Hanselmann
  for line in FormatTable(rows, columns, header, separator):
2888 ee3aedff Michael Hanselmann
    ToStdout(line)
2889 ee3aedff Michael Hanselmann
2890 ee3aedff Michael Hanselmann
  if found_unknown:
2891 ee3aedff Michael Hanselmann
    return constants.EXIT_UNKNOWN_FIELD
2892 ee3aedff Michael Hanselmann
2893 ee3aedff Michael Hanselmann
  return constants.EXIT_SUCCESS
2894 ee3aedff Michael Hanselmann
2895 ee3aedff Michael Hanselmann
2896 ee3aedff Michael Hanselmann
class TableColumn:
2897 ee3aedff Michael Hanselmann
  """Describes a column for L{FormatTable}.
2898 ee3aedff Michael Hanselmann

2899 ee3aedff Michael Hanselmann
  """
2900 ee3aedff Michael Hanselmann
  def __init__(self, title, fn, align_right):
2901 ee3aedff Michael Hanselmann
    """Initializes this class.
2902 ee3aedff Michael Hanselmann

2903 ee3aedff Michael Hanselmann
    @type title: string
2904 ee3aedff Michael Hanselmann
    @param title: Column title
2905 ee3aedff Michael Hanselmann
    @type fn: callable
2906 ee3aedff Michael Hanselmann
    @param fn: Formatting function
2907 ee3aedff Michael Hanselmann
    @type align_right: bool
2908 ee3aedff Michael Hanselmann
    @param align_right: Whether to align values on the right-hand side
2909 ee3aedff Michael Hanselmann

2910 ee3aedff Michael Hanselmann
    """
2911 ee3aedff Michael Hanselmann
    self.title = title
2912 ee3aedff Michael Hanselmann
    self.format = fn
2913 ee3aedff Michael Hanselmann
    self.align_right = align_right
2914 ee3aedff Michael Hanselmann
2915 ee3aedff Michael Hanselmann
2916 ee3aedff Michael Hanselmann
def _GetColFormatString(width, align_right):
2917 ee3aedff Michael Hanselmann
  """Returns the format string for a field.
2918 ee3aedff Michael Hanselmann

2919 ee3aedff Michael Hanselmann
  """
2920 ee3aedff Michael Hanselmann
  if align_right:
2921 ee3aedff Michael Hanselmann
    sign = ""
2922 ee3aedff Michael Hanselmann
  else:
2923 ee3aedff Michael Hanselmann
    sign = "-"
2924 ee3aedff Michael Hanselmann
2925 ee3aedff Michael Hanselmann
  return "%%%s%ss" % (sign, width)
2926 ee3aedff Michael Hanselmann
2927 ee3aedff Michael Hanselmann
2928 ee3aedff Michael Hanselmann
def FormatTable(rows, columns, header, separator):
2929 ee3aedff Michael Hanselmann
  """Formats data as a table.
2930 ee3aedff Michael Hanselmann

2931 ee3aedff Michael Hanselmann
  @type rows: list of lists
2932 ee3aedff Michael Hanselmann
  @param rows: Row data, one list per row
2933 ee3aedff Michael Hanselmann
  @type columns: list of L{TableColumn}
2934 ee3aedff Michael Hanselmann
  @param columns: Column descriptions
2935 ee3aedff Michael Hanselmann
  @type header: bool
2936 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2937 ee3aedff Michael Hanselmann
  @type separator: string or None
2938 ee3aedff Michael Hanselmann
  @param separator: String used to separate columns
2939 ee3aedff Michael Hanselmann

2940 ee3aedff Michael Hanselmann
  """
2941 ee3aedff Michael Hanselmann
  if header:
2942 ee3aedff Michael Hanselmann
    data = [[col.title for col in columns]]
2943 ee3aedff Michael Hanselmann
    colwidth = [len(col.title) for col in columns]
2944 ee3aedff Michael Hanselmann
  else:
2945 ee3aedff Michael Hanselmann
    data = []
2946 ee3aedff Michael Hanselmann
    colwidth = [0 for _ in columns]
2947 ee3aedff Michael Hanselmann
2948 ee3aedff Michael Hanselmann
  # Format row data
2949 ee3aedff Michael Hanselmann
  for row in rows:
2950 ee3aedff Michael Hanselmann
    assert len(row) == len(columns)
2951 ee3aedff Michael Hanselmann
2952 ee3aedff Michael Hanselmann
    formatted = [col.format(value) for value, col in zip(row, columns)]
2953 ee3aedff Michael Hanselmann
2954 ee3aedff Michael Hanselmann
    if separator is None:
2955 ee3aedff Michael Hanselmann
      # Update column widths
2956 ee3aedff Michael Hanselmann
      for idx, (oldwidth, value) in enumerate(zip(colwidth, formatted)):
2957 ee3aedff Michael Hanselmann
        # Modifying a list's items while iterating is fine
2958 ee3aedff Michael Hanselmann
        colwidth[idx] = max(oldwidth, len(value))
2959 ee3aedff Michael Hanselmann
2960 ee3aedff Michael Hanselmann
    data.append(formatted)
2961 ee3aedff Michael Hanselmann
2962 ee3aedff Michael Hanselmann
  if separator is not None:
2963 ee3aedff Michael Hanselmann
    # Return early if a separator is used
2964 ee3aedff Michael Hanselmann
    return [separator.join(row) for row in data]
2965 ee3aedff Michael Hanselmann
2966 ee3aedff Michael Hanselmann
  if columns and not columns[-1].align_right:
2967 ee3aedff Michael Hanselmann
    # Avoid unnecessary spaces at end of line
2968 ee3aedff Michael Hanselmann
    colwidth[-1] = 0
2969 ee3aedff Michael Hanselmann
2970 ee3aedff Michael Hanselmann
  # Build format string
2971 ee3aedff Michael Hanselmann
  fmt = " ".join([_GetColFormatString(width, col.align_right)
2972 ee3aedff Michael Hanselmann
                  for col, width in zip(columns, colwidth)])
2973 ee3aedff Michael Hanselmann
2974 ee3aedff Michael Hanselmann
  return [fmt % tuple(row) for row in data]
2975 ee3aedff Michael Hanselmann
2976 ee3aedff Michael Hanselmann
2977 3386e7a9 Iustin Pop
def FormatTimestamp(ts):
2978 3386e7a9 Iustin Pop
  """Formats a given timestamp.
2979 3386e7a9 Iustin Pop

2980 3386e7a9 Iustin Pop
  @type ts: timestamp
2981 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
2982 3386e7a9 Iustin Pop

2983 3386e7a9 Iustin Pop
  @rtype: string
2984 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
2985 3386e7a9 Iustin Pop

2986 3386e7a9 Iustin Pop
  """
2987 e687ec01 Michael Hanselmann
  if not isinstance(ts, (tuple, list)) or len(ts) != 2:
2988 d0c8c01d Iustin Pop
    return "?"
2989 3386e7a9 Iustin Pop
  sec, usec = ts
2990 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
2991 2241e2b9 Iustin Pop
2992 2241e2b9 Iustin Pop
2993 2241e2b9 Iustin Pop
def ParseTimespec(value):
2994 2241e2b9 Iustin Pop
  """Parse a time specification.
2995 2241e2b9 Iustin Pop

2996 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
2997 2241e2b9 Iustin Pop

2998 2241e2b9 Iustin Pop
    - s: seconds
2999 2241e2b9 Iustin Pop
    - m: minutes
3000 2241e2b9 Iustin Pop
    - h: hours
3001 2241e2b9 Iustin Pop
    - d: day
3002 2241e2b9 Iustin Pop
    - w: weeks
3003 2241e2b9 Iustin Pop

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

3006 2241e2b9 Iustin Pop
  """
3007 2241e2b9 Iustin Pop
  value = str(value)
3008 2241e2b9 Iustin Pop
  if not value:
3009 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
3010 2241e2b9 Iustin Pop
  suffix_map = {
3011 d0c8c01d Iustin Pop
    "s": 1,
3012 d0c8c01d Iustin Pop
    "m": 60,
3013 d0c8c01d Iustin Pop
    "h": 3600,
3014 d0c8c01d Iustin Pop
    "d": 86400,
3015 d0c8c01d Iustin Pop
    "w": 604800,
3016 2241e2b9 Iustin Pop
    }
3017 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
3018 2241e2b9 Iustin Pop
    try:
3019 2241e2b9 Iustin Pop
      value = int(value)
3020 691744c4 Iustin Pop
    except (TypeError, ValueError):
3021 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
3022 2241e2b9 Iustin Pop
  else:
3023 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
3024 2241e2b9 Iustin Pop
    value = value[:-1]
3025 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
3026 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
3027 2241e2b9 Iustin Pop
                                 " suffix passed)")
3028 2241e2b9 Iustin Pop
    try:
3029 2241e2b9 Iustin Pop
      value = int(value) * multiplier
3030 691744c4 Iustin Pop
    except (TypeError, ValueError):
3031 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
3032 2241e2b9 Iustin Pop
  return value
3033 46fbdd04 Iustin Pop
3034 46fbdd04 Iustin Pop
3035 e9e26bb3 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False, secondary_ips=False,
3036 05484a24 Michael Hanselmann
                   filter_master=False, nodegroup=None):
3037 4040a784 Iustin Pop
  """Returns the names of online nodes.
3038 4040a784 Iustin Pop

3039 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
3040 4040a784 Iustin Pop
  the online nodes.
3041 4040a784 Iustin Pop

3042 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
3043 4040a784 Iustin Pop
      offline ones)
3044 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
3045 4040a784 Iustin Pop
  @type nowarn: boolean
3046 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
3047 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
3048 4040a784 Iustin Pop
      note is not displayed
3049 e9e26bb3 Iustin Pop
  @type secondary_ips: boolean
3050 e9e26bb3 Iustin Pop
  @param secondary_ips: if True, return the secondary IPs instead of the
3051 e9e26bb3 Iustin Pop
      names, useful for doing network traffic over the replication interface
3052 e9e26bb3 Iustin Pop
      (if any)
3053 e9e26bb3 Iustin Pop
  @type filter_master: boolean
3054 e9e26bb3 Iustin Pop
  @param filter_master: if True, do not return the master node in the list
3055 e9e26bb3 Iustin Pop
      (useful in coordination with secondary_ips where we cannot check our
3056 e9e26bb3 Iustin Pop
      node name against the list)
3057 05484a24 Michael Hanselmann
  @type nodegroup: string
3058 05484a24 Michael Hanselmann
  @param nodegroup: If set, only return nodes in this node group
3059 4040a784 Iustin Pop

3060 4040a784 Iustin Pop
  """
3061 4040a784 Iustin Pop
  if cl is None:
3062 4040a784 Iustin Pop
    cl = GetClient()
3063 4040a784 Iustin Pop
3064 2e5c33db Iustin Pop
  qfilter = []
3065 05484a24 Michael Hanselmann
3066 05484a24 Michael Hanselmann
  if nodes:
3067 2e5c33db Iustin Pop
    qfilter.append(qlang.MakeSimpleFilter("name", nodes))
3068 05484a24 Michael Hanselmann
3069 05484a24 Michael Hanselmann
  if nodegroup is not None:
3070 2e5c33db Iustin Pop
    qfilter.append([qlang.OP_OR, [qlang.OP_EQUAL, "group", nodegroup],
3071 05484a24 Michael Hanselmann
                                 [qlang.OP_EQUAL, "group.uuid", nodegroup]])
3072 e9e26bb3 Iustin Pop
3073 e9e26bb3 Iustin Pop
  if filter_master:
3074 2e5c33db Iustin Pop
    qfilter.append([qlang.OP_NOT, [qlang.OP_TRUE, "master"]])
3075 05484a24 Michael Hanselmann
3076 2e5c33db Iustin Pop
  if qfilter:
3077 2e5c33db Iustin Pop
    if len(qfilter) > 1:
3078 2e5c33db Iustin Pop
      final_filter = [qlang.OP_AND] + qfilter
3079 05484a24 Michael Hanselmann
    else:
3080 2e5c33db Iustin Pop
      assert len(qfilter) == 1
3081 2e5c33db Iustin Pop
      final_filter = qfilter[0]
3082 e9e26bb3 Iustin Pop
  else:
3083 05484a24 Michael Hanselmann
    final_filter = None
3084 05484a24 Michael Hanselmann
3085 05484a24 Michael Hanselmann
  result = cl.Query(constants.QR_NODE, ["name", "offline", "sip"], final_filter)
3086 05484a24 Michael Hanselmann
3087 05484a24 Michael Hanselmann
  def _IsOffline(row):
3088 05484a24 Michael Hanselmann
    (_, (_, offline), _) = row
3089 05484a24 Michael Hanselmann
    return offline
3090 05484a24 Michael Hanselmann
3091 05484a24 Michael Hanselmann
  def _GetName(row):
3092 05484a24 Michael Hanselmann
    ((_, name), _, _) = row
3093 05484a24 Michael Hanselmann
    return name
3094 05484a24 Michael Hanselmann
3095 05484a24 Michael Hanselmann
  def _GetSip(row):
3096 05484a24 Michael Hanselmann
    (_, _, (_, sip)) = row
3097 05484a24 Michael Hanselmann
    return sip
3098 05484a24 Michael Hanselmann
3099 05484a24 Michael Hanselmann
  (offline, online) = compat.partition(result.data, _IsOffline)
3100 e9e26bb3 Iustin Pop
3101 4040a784 Iustin Pop
  if offline and not nowarn:
3102 05484a24 Michael Hanselmann
    ToStderr("Note: skipping offline node(s): %s" %
3103 05484a24 Michael Hanselmann
             utils.CommaJoin(map(_GetName, offline)))
3104 05484a24 Michael Hanselmann
3105 05484a24 Michael Hanselmann
  if secondary_ips:
3106 05484a24 Michael Hanselmann
    fn = _GetSip
3107 05484a24 Michael Hanselmann
  else:
3108 05484a24 Michael Hanselmann
    fn = _GetName
3109 05484a24 Michael Hanselmann
3110 05484a24 Michael Hanselmann
  return map(fn, online)
3111 4040a784 Iustin Pop
3112 4040a784 Iustin Pop
3113 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
3114 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
3115 46fbdd04 Iustin Pop

3116 46fbdd04 Iustin Pop
  @type stream: file object
3117 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
3118 46fbdd04 Iustin Pop
  @type txt: str
3119 46fbdd04 Iustin Pop
  @param txt: the message
3120 46fbdd04 Iustin Pop

3121 46fbdd04 Iustin Pop
  """
3122 225e2544 Iustin Pop
  try:
3123 225e2544 Iustin Pop
    if args:
3124 225e2544 Iustin Pop
      args = tuple(args)
3125 225e2544 Iustin Pop
      stream.write(txt % args)
3126 225e2544 Iustin Pop
    else:
3127 225e2544 Iustin Pop
      stream.write(txt)
3128 d0c8c01d Iustin Pop
    stream.write("\n")
3129 225e2544 Iustin Pop
    stream.flush()
3130 225e2544 Iustin Pop
  except IOError, err:
3131 225e2544 Iustin Pop
    if err.errno == errno.EPIPE:
3132 225e2544 Iustin Pop
      # our terminal went away, we'll exit
3133 225e2544 Iustin Pop
      sys.exit(constants.EXIT_FAILURE)
3134 225e2544 Iustin Pop
    else:
3135 225e2544 Iustin Pop
      raise
3136 46fbdd04 Iustin Pop
3137 46fbdd04 Iustin Pop
3138 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
3139 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
3140 46fbdd04 Iustin Pop

3141 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
3142 46fbdd04 Iustin Pop

3143 46fbdd04 Iustin Pop
  @type txt: str
3144 46fbdd04 Iustin Pop
  @param txt: the message
3145 46fbdd04 Iustin Pop

3146 46fbdd04 Iustin Pop
  """
3147 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
3148 46fbdd04 Iustin Pop
3149 46fbdd04 Iustin Pop
3150 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
3151 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
3152 46fbdd04 Iustin Pop

3153 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
3154 46fbdd04 Iustin Pop

3155 46fbdd04 Iustin Pop
  @type txt: str
3156 46fbdd04 Iustin Pop
  @param txt: the message
3157 46fbdd04 Iustin Pop

3158 46fbdd04 Iustin Pop
  """
3159 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
3160 479636a3 Iustin Pop
3161 479636a3 Iustin Pop
3162 479636a3 Iustin Pop
class JobExecutor(object):
3163 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
3164 479636a3 Iustin Pop

3165 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
3166 479636a3 Iustin Pop
  GetResults() calls.
3167 479636a3 Iustin Pop

3168 479636a3 Iustin Pop
  """
3169 919ca415 Iustin Pop
  def __init__(self, cl=None, verbose=True, opts=None, feedback_fn=None):
3170 479636a3 Iustin Pop
    self.queue = []
3171 479636a3 Iustin Pop
    if cl is None:
3172 479636a3 Iustin Pop
      cl = GetClient()
3173 479636a3 Iustin Pop
    self.cl = cl
3174 479636a3 Iustin Pop
    self.verbose = verbose
3175 23b4b983 Iustin Pop
    self.jobs = []
3176 cff5fa7f Iustin Pop
    self.opts = opts
3177 919ca415 Iustin Pop
    self.feedback_fn = feedback_fn
3178 60452edf Michael Hanselmann
    self._counter = itertools.count()
3179 479636a3 Iustin Pop
3180 8d99a8bf Michael Hanselmann
  @staticmethod
3181 8d99a8bf Michael Hanselmann
  def _IfName(name, fmt):
3182 8d99a8bf Michael Hanselmann
    """Helper function for formatting name.
3183 8d99a8bf Michael Hanselmann

3184 8d99a8bf Michael Hanselmann
    """
3185 8d99a8bf Michael Hanselmann
    if name:
3186 8d99a8bf Michael Hanselmann
      return fmt % name
3187 8d99a8bf Michael Hanselmann
3188 8d99a8bf Michael Hanselmann
    return ""
3189 8d99a8bf Michael Hanselmann
3190 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
3191 23b4b983 Iustin Pop
    """Record a job for later submit.
3192 479636a3 Iustin Pop

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

3196 479636a3 Iustin Pop
    """
3197 cff5fa7f Iustin Pop
    SetGenericOpcodeOpts(ops, self.opts)
3198 60452edf Michael Hanselmann
    self.queue.append((self._counter.next(), name, ops))
3199 23b4b983 Iustin Pop
3200 8d99a8bf Michael Hanselmann
  def AddJobId(self, name, status, job_id):
3201 8d99a8bf Michael Hanselmann
    """Adds a job ID to the internal queue.
3202 8d99a8bf Michael Hanselmann

3203 8d99a8bf Michael Hanselmann
    """
3204 8d99a8bf Michael Hanselmann
    self.jobs.append((self._counter.next(), status, job_id, name))
3205 8d99a8bf Michael Hanselmann
3206 66ecc479 Guido Trotter
  def SubmitPending(self, each=False):
3207 23b4b983 Iustin Pop
    """Submit all pending jobs.
3208 23b4b983 Iustin Pop

3209 23b4b983 Iustin Pop
    """
3210 66ecc479 Guido Trotter
    if each:
3211 66ecc479 Guido Trotter
      results = []
3212 60452edf Michael Hanselmann
      for (_, _, ops) in self.queue:
3213 66ecc479 Guido Trotter
        # SubmitJob will remove the success status, but raise an exception if
3214 66ecc479 Guido Trotter
        # the submission fails, so we'll notice that anyway.
3215 519fafa1 Andrea Spadaccini
        results.append([True, self.cl.SubmitJob(ops)[0]])
3216 66ecc479 Guido Trotter
    else:
3217 60452edf Michael Hanselmann
      results = self.cl.SubmitManyJobs([ops for (_, _, ops) in self.queue])
3218 60452edf Michael Hanselmann
    for ((status, data), (idx, name, _)) in zip(results, self.queue):
3219 5299e61f Iustin Pop
      self.jobs.append((idx, status, data, name))
3220 5299e61f Iustin Pop
3221 5299e61f Iustin Pop
  def _ChooseJob(self):
3222 5299e61f Iustin Pop
    """Choose a non-waiting/queued job to poll next.
3223 5299e61f Iustin Pop

3224 5299e61f Iustin Pop
    """
3225 5299e61f Iustin Pop
    assert self.jobs, "_ChooseJob called with empty job list"
3226 5299e61f Iustin Pop
3227 11705e3d Iustin Pop
    result = self.cl.QueryJobs([i[2] for i in self.jobs[:_CHOOSE_BATCH]],
3228 11705e3d Iustin Pop
                               ["status"])
3229 5299e61f Iustin Pop
    assert result
3230 5299e61f Iustin Pop
3231 5299e61f Iustin Pop
    for job_data, status in zip(self.jobs, result):
3232 91c622a8 Iustin Pop
      if (isinstance(status, list) and status and
3233 91c622a8 Iustin Pop
          status[0] in (constants.JOB_STATUS_QUEUED,
3234 47099cd1 Michael Hanselmann
                        constants.JOB_STATUS_WAITING,
3235 91c622a8 Iustin Pop
                        constants.JOB_STATUS_CANCELING)):
3236 91c622a8 Iustin Pop
        # job is still present and waiting
3237 5299e61f Iustin Pop
        continue
3238 91c622a8 Iustin Pop
      # good candidate found (either running job or lost job)
3239 5299e61f Iustin Pop
      self.jobs.remove(job_data)
3240 5299e61f Iustin Pop
      return job_data
3241 5299e61f Iustin Pop
3242 5299e61f Iustin Pop
    # no job found
3243 5299e61f Iustin Pop
    return self.jobs.pop(0)
3244 479636a3 Iustin Pop
3245 479636a3 Iustin Pop
  def GetResults(self):
3246 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
3247 479636a3 Iustin Pop

3248 479636a3 Iustin Pop
    @rtype: list
3249 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
3250 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
3251 479636a3 Iustin Pop
        there will be the error message
3252 479636a3 Iustin Pop

3253 479636a3 Iustin Pop
    """
3254 23b4b983 Iustin Pop
    if not self.jobs:
3255 23b4b983 Iustin Pop
      self.SubmitPending()
3256 479636a3 Iustin Pop
    results = []
3257 479636a3 Iustin Pop
    if self.verbose:
3258 5299e61f Iustin Pop
      ok_jobs = [row[2] for row in self.jobs if row[1]]
3259 23b4b983 Iustin Pop
      if ok_jobs:
3260 4474f112 Iustin Pop
        ToStdout("Submitted jobs %s", utils.CommaJoin(ok_jobs))
3261 5299e61f Iustin Pop
3262 5299e61f Iustin Pop
    # first, remove any non-submitted jobs
3263 cea881e5 Michael Hanselmann
    self.jobs, failures = compat.partition(self.jobs, lambda x: x[1])
3264 5299e61f Iustin Pop
    for idx, _, jid, name in failures:
3265 4474f112 Iustin Pop
      ToStderr("Failed to submit job%s: %s", self._IfName(name, " for %s"), jid)
3266 c63355f2 Iustin Pop
      results.append((idx, False, jid))
3267 5299e61f Iustin Pop
3268 5299e61f Iustin Pop
    while self.jobs:
3269 5299e61f Iustin Pop
      (idx, _, jid, name) = self._ChooseJob()
3270 4474f112 Iustin Pop
      ToStdout("Waiting for job %s%s ...", jid, self._IfName(name, " for %s"))
3271 479636a3 Iustin Pop
      try:
3272 919ca415 Iustin Pop
        job_result = PollJob(jid, cl=self.cl, feedback_fn=self.feedback_fn)
3273 479636a3 Iustin Pop
        success = True
3274 91c622a8 Iustin Pop
      except errors.JobLost, err:
3275 91c622a8 Iustin Pop
        _, job_result = FormatError(err)
3276 4474f112 Iustin Pop
        ToStderr("Job %s%s has been archived, cannot check its result",
3277 4474f112 Iustin Pop
                 jid, self._IfName(name, " for %s"))
3278 91c622a8 Iustin Pop
        success = False
3279 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
3280 479636a3 Iustin Pop
        _, job_result = FormatError(err)
3281 479636a3 Iustin Pop
        success = False
3282 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
3283 4474f112 Iustin Pop
        ToStderr("Job %s%s has failed: %s",
3284 4474f112 Iustin Pop
                 jid, self._IfName(name, " for %s"), job_result)
3285 479636a3 Iustin Pop
3286 5299e61f Iustin Pop
      results.append((idx, success, job_result))
3287 5299e61f Iustin Pop
3288 5299e61f Iustin Pop
    # sort based on the index, then drop it
3289 5299e61f Iustin Pop
    results.sort()
3290 5299e61f Iustin Pop
    results = [i[1:] for i in results]
3291 5299e61f Iustin Pop
3292 479636a3 Iustin Pop
    return results
3293 479636a3 Iustin Pop
3294 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
3295 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
3296 479636a3 Iustin Pop

3297 479636a3 Iustin Pop
    @type wait: boolean
3298 479636a3 Iustin Pop
    @param wait: whether to wait or not
3299 479636a3 Iustin Pop

3300 479636a3 Iustin Pop
    """
3301 479636a3 Iustin Pop
    if wait:
3302 479636a3 Iustin Pop
      return self.GetResults()
3303 479636a3 Iustin Pop
    else:
3304 23b4b983 Iustin Pop
      if not self.jobs:
3305 23b4b983 Iustin Pop
        self.SubmitPending()
3306 71834b2a Guido Trotter
      for _, status, result, name in self.jobs:
3307 23b4b983 Iustin Pop
        if status:
3308 4474f112 Iustin Pop
          ToStdout("%s: %s", result, name)
3309 23b4b983 Iustin Pop
        else:
3310 4474f112 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)
3311 53a8a54d Iustin Pop
      return [row[1:3] for row in self.jobs]
3312 acd19189 René Nussbaumer
3313 acd19189 René Nussbaumer
3314 acd19189 René Nussbaumer
def FormatParameterDict(buf, param_dict, actual, level=1):
3315 acd19189 René Nussbaumer
  """Formats a parameter dictionary.
3316 acd19189 René Nussbaumer

3317 acd19189 René Nussbaumer
  @type buf: L{StringIO}
3318 acd19189 René Nussbaumer
  @param buf: the buffer into which to write
3319 acd19189 René Nussbaumer
  @type param_dict: dict
3320 acd19189 René Nussbaumer
  @param param_dict: the own parameters
3321 acd19189 René Nussbaumer
  @type actual: dict
3322 acd19189 René Nussbaumer
  @param actual: the current parameter set (including defaults)
3323 acd19189 René Nussbaumer
  @param level: Level of indent
3324 acd19189 René Nussbaumer

3325 acd19189 René Nussbaumer
  """
3326 acd19189 René Nussbaumer
  indent = "  " * level
3327 acd19189 René Nussbaumer
  for key in sorted(actual):
3328 acd19189 René Nussbaumer
    val = param_dict.get(key, "default (%s)" % actual[key])
3329 acd19189 René Nussbaumer
    buf.write("%s- %s: %s\n" % (indent, key, val))
3330 25bd815c René Nussbaumer
3331 25bd815c René Nussbaumer
3332 25bd815c René Nussbaumer
def ConfirmOperation(names, list_type, text, extra=""):
3333 25bd815c René Nussbaumer
  """Ask the user to confirm an operation on a list of list_type.
3334 25bd815c René Nussbaumer

3335 25bd815c René Nussbaumer
  This function is used to request confirmation for doing an operation
3336 25bd815c René Nussbaumer
  on a given list of list_type.
3337 25bd815c René Nussbaumer

3338 25bd815c René Nussbaumer
  @type names: list
3339 25bd815c René Nussbaumer
  @param names: the list of names that we display when
3340 25bd815c René Nussbaumer
      we ask for confirmation
3341 25bd815c René Nussbaumer
  @type list_type: str
3342 25bd815c René Nussbaumer
  @param list_type: Human readable name for elements in the list (e.g. nodes)
3343 25bd815c René Nussbaumer
  @type text: str
3344 25bd815c René Nussbaumer
  @param text: the operation that the user should confirm
3345 25bd815c René Nussbaumer
  @rtype: boolean
3346 25bd815c René Nussbaumer
  @return: True or False depending on user's confirmation.
3347 25bd815c René Nussbaumer

3348 25bd815c René Nussbaumer
  """
3349 25bd815c René Nussbaumer
  count = len(names)
3350 25bd815c René Nussbaumer
  msg = ("The %s will operate on %d %s.\n%s"
3351 25bd815c René Nussbaumer
         "Do you want to continue?" % (text, count, list_type, extra))
3352 25bd815c René Nussbaumer
  affected = (("\nAffected %s:\n" % list_type) +
3353 25bd815c René Nussbaumer
              "\n".join(["  %s" % name for name in names]))
3354 25bd815c René Nussbaumer
3355 25bd815c René Nussbaumer
  choices = [("y", True, "Yes, execute the %s" % text),
3356 25bd815c René Nussbaumer
             ("n", False, "No, abort the %s" % text)]
3357 25bd815c René Nussbaumer
3358 25bd815c René Nussbaumer
  if count > 20:
3359 25bd815c René Nussbaumer
    choices.insert(1, ("v", "v", "View the list of affected %s" % list_type))
3360 25bd815c René Nussbaumer
    question = msg
3361 25bd815c René Nussbaumer
  else:
3362 25bd815c René Nussbaumer
    question = msg + affected
3363 25bd815c René Nussbaumer
3364 25bd815c René Nussbaumer
  choice = AskUser(question, choices)
3365 25bd815c René Nussbaumer
  if choice == "v":
3366 25bd815c René Nussbaumer
    choices.pop(1)
3367 25bd815c René Nussbaumer
    choice = AskUser(msg + affected, choices)
3368 25bd815c René Nussbaumer
  return choice