Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ 8c0b16f6

History | View | Annotate | Download (109.8 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 8b46606c Guido Trotter
  elif ident.startswith(UN_PREFIX):
556 8b46606c Guido Trotter
    if rest:
557 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
558 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
559 8b46606c Guido Trotter
    retval = (ident[len(UN_PREFIX):], None)
560 8b46606c Guido Trotter
  else:
561 a8469393 Iustin Pop
    kv_dict = _SplitKeyVal(opt, rest)
562 a8469393 Iustin Pop
    retval = (ident, kv_dict)
563 a8469393 Iustin Pop
  return retval
564 a8469393 Iustin Pop
565 a8469393 Iustin Pop
566 b459a848 Andrea Spadaccini
def check_key_val(option, opt, value):  # pylint: disable=W0613
567 552c8dff Michael Hanselmann
  """Custom parser class for key=val,key=val options.
568 552c8dff Michael Hanselmann

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

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

578 e7b61bb0 Iustin Pop
  This will store the parsed value as either True or False.
579 e7b61bb0 Iustin Pop

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

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

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

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

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

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

1512 a8005e17 Michael Hanselmann
  Algorithm:
1513 a8005e17 Michael Hanselmann

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

1516 a8005e17 Michael Hanselmann
    1. For each argument in definition
1517 a8005e17 Michael Hanselmann

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

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

1524 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
1525 a8005e17 Michael Hanselmann

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

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

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

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

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

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

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

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

1631 c41eea6e Iustin Pop
  @param text: the question to ask
1632 a8083063 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2425 7e49b6ce Michael Hanselmann
    @type fn: callable
2426 7e49b6ce Michael Hanselmann
    @param fn: Function to be called
2427 7e49b6ce Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2777 ee3aedff Michael Hanselmann
  @type fdefs: list of L{objects.QueryFieldDefinition}
2778 ee3aedff Michael Hanselmann

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

2787 ee3aedff Michael Hanselmann
  @type fdefs: list of L{objects.QueryFieldDefinition}
2788 ee3aedff Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2994 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
2995 2241e2b9 Iustin Pop

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

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

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

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

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

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

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

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

3139 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
3140 46fbdd04 Iustin Pop

3141 46fbdd04 Iustin Pop
  @type txt: str
3142 46fbdd04 Iustin Pop
  @param txt: the message
3143 46fbdd04 Iustin Pop

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

3151 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
3152 46fbdd04 Iustin Pop

3153 46fbdd04 Iustin Pop
  @type txt: str
3154 46fbdd04 Iustin Pop
  @param txt: the message
3155 46fbdd04 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

3295 479636a3 Iustin Pop
    @type wait: boolean
3296 479636a3 Iustin Pop
    @param wait: whether to wait or not
3297 479636a3 Iustin Pop

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

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

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

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

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

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