Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ b3f0d718

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

418 810c50b7 Iustin Pop
  """
419 810c50b7 Iustin Pop
  fname = opts.tags_source
420 810c50b7 Iustin Pop
  if fname is None:
421 810c50b7 Iustin Pop
    return
422 810c50b7 Iustin Pop
  if fname == "-":
423 810c50b7 Iustin Pop
    new_fh = sys.stdin
424 810c50b7 Iustin Pop
  else:
425 810c50b7 Iustin Pop
    new_fh = open(fname, "r")
426 810c50b7 Iustin Pop
  new_data = []
427 810c50b7 Iustin Pop
  try:
428 810c50b7 Iustin Pop
    # we don't use the nice 'new_data = [line.strip() for line in fh]'
429 810c50b7 Iustin Pop
    # because of python bug 1633941
430 810c50b7 Iustin Pop
    while True:
431 810c50b7 Iustin Pop
      line = new_fh.readline()
432 810c50b7 Iustin Pop
      if not line:
433 810c50b7 Iustin Pop
        break
434 810c50b7 Iustin Pop
      new_data.append(line.strip())
435 810c50b7 Iustin Pop
  finally:
436 810c50b7 Iustin Pop
    new_fh.close()
437 810c50b7 Iustin Pop
  args.extend(new_data)
438 810c50b7 Iustin Pop
439 810c50b7 Iustin Pop
440 846baef9 Iustin Pop
def ListTags(opts, args):
441 846baef9 Iustin Pop
  """List the tags on a given object.
442 846baef9 Iustin Pop

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

448 846baef9 Iustin Pop
  """
449 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
450 7699c3af Iustin Pop
  cl = GetClient()
451 7699c3af Iustin Pop
  result = cl.QueryTags(kind, name)
452 846baef9 Iustin Pop
  result = list(result)
453 846baef9 Iustin Pop
  result.sort()
454 846baef9 Iustin Pop
  for tag in result:
455 03298ebe Michael Hanselmann
    ToStdout(tag)
456 846baef9 Iustin Pop
457 846baef9 Iustin Pop
458 846baef9 Iustin Pop
def AddTags(opts, args):
459 846baef9 Iustin Pop
  """Add tags on a given object.
460 846baef9 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1435 c41eea6e Iustin Pop
  @param argv: the command line
1436 c41eea6e Iustin Pop
  @param commands: dictionary with special contents, see the design
1437 c41eea6e Iustin Pop
      doc for cmdline handling
1438 c41eea6e Iustin Pop
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
1439 ef9fa5b9 René Nussbaumer
  @param env_override: list of env variables allowed for default args
1440 098c0958 Michael Hanselmann

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

1520 a8005e17 Michael Hanselmann
  Algorithm:
1521 a8005e17 Michael Hanselmann

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

1524 a8005e17 Michael Hanselmann
    1. For each argument in definition
1525 a8005e17 Michael Hanselmann

1526 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
1527 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
1528 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
1529 a8005e17 Michael Hanselmann

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

1532 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
1533 a8005e17 Michael Hanselmann

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

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

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

1591 60d49723 Michael Hanselmann
  """
1592 d0c8c01d Iustin Pop
  if value and ":" in value:
1593 d0c8c01d Iustin Pop
    return value.split(":", 1)
1594 60d49723 Michael Hanselmann
  else:
1595 60d49723 Michael Hanselmann
    return (value, None)
1596 60d49723 Michael Hanselmann
1597 60d49723 Michael Hanselmann
1598 07150497 Guido Trotter
def CalculateOSNames(os_name, os_variants):
1599 07150497 Guido Trotter
  """Calculates all the names an OS can be called, according to its variants.
1600 07150497 Guido Trotter

1601 07150497 Guido Trotter
  @type os_name: string
1602 07150497 Guido Trotter
  @param os_name: base name of the os
1603 07150497 Guido Trotter
  @type os_variants: list or None
1604 07150497 Guido Trotter
  @param os_variants: list of supported variants
1605 07150497 Guido Trotter
  @rtype: list
1606 07150497 Guido Trotter
  @return: list of valid names
1607 07150497 Guido Trotter

1608 07150497 Guido Trotter
  """
1609 07150497 Guido Trotter
  if os_variants:
1610 d0c8c01d Iustin Pop
    return ["%s+%s" % (os_name, v) for v in os_variants]
1611 07150497 Guido Trotter
  else:
1612 07150497 Guido Trotter
    return [os_name]
1613 07150497 Guido Trotter
1614 07150497 Guido Trotter
1615 a4ebd726 Michael Hanselmann
def ParseFields(selected, default):
1616 a4ebd726 Michael Hanselmann
  """Parses the values of "--field"-like options.
1617 a4ebd726 Michael Hanselmann

1618 a4ebd726 Michael Hanselmann
  @type selected: string or None
1619 a4ebd726 Michael Hanselmann
  @param selected: User-selected options
1620 a4ebd726 Michael Hanselmann
  @type default: list
1621 a4ebd726 Michael Hanselmann
  @param default: Default fields
1622 a4ebd726 Michael Hanselmann

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

1639 c41eea6e Iustin Pop
  @param text: the question to ask
1640 a8083063 Iustin Pop

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

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

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

1696 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1697 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1698 e9d741b6 Iustin Pop

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

1701 e9d741b6 Iustin Pop
  """
1702 e9d741b6 Iustin Pop
1703 e9d741b6 Iustin Pop
1704 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1705 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1706 a8083063 Iustin Pop

1707 0a1e74d9 Iustin Pop
  @type ops: list
1708 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1709 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1710 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1711 0a1e74d9 Iustin Pop
             if None, a new client will be created
1712 a8083063 Iustin Pop

1713 a8083063 Iustin Pop
  """
1714 e2212007 Iustin Pop
  if cl is None:
1715 b33e986b Iustin Pop
    cl = GetClient()
1716 685ee993 Iustin Pop
1717 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1718 0a1e74d9 Iustin Pop
1719 0a1e74d9 Iustin Pop
  return job_id
1720 0a1e74d9 Iustin Pop
1721 0a1e74d9 Iustin Pop
1722 4e338533 Michael Hanselmann
def GenericPollJob(job_id, cbs, report_cbs):
1723 4e338533 Michael Hanselmann
  """Generic job-polling function.
1724 0a1e74d9 Iustin Pop

1725 4e338533 Michael Hanselmann
  @type job_id: number
1726 4e338533 Michael Hanselmann
  @param job_id: Job ID
1727 4e338533 Michael Hanselmann
  @type cbs: Instance of L{JobPollCbBase}
1728 4e338533 Michael Hanselmann
  @param cbs: Data callbacks
1729 4e338533 Michael Hanselmann
  @type report_cbs: Instance of L{JobPollReportCbBase}
1730 4e338533 Michael Hanselmann
  @param report_cbs: Reporting callbacks
1731 0a1e74d9 Iustin Pop

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

1803 4e338533 Michael Hanselmann
  """
1804 4e338533 Michael Hanselmann
  def __init__(self):
1805 4e338533 Michael Hanselmann
    """Initializes this class.
1806 4e338533 Michael Hanselmann

1807 4e338533 Michael Hanselmann
    """
1808 4e338533 Michael Hanselmann
1809 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1810 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1811 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1812 4e338533 Michael Hanselmann

1813 4e338533 Michael Hanselmann
    """
1814 4e338533 Michael Hanselmann
    raise NotImplementedError()
1815 4e338533 Michael Hanselmann
1816 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1817 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1818 4e338533 Michael Hanselmann

1819 4e338533 Michael Hanselmann
    @type job_ids: list of numbers
1820 4e338533 Michael Hanselmann
    @param job_ids: Job IDs
1821 4e338533 Michael Hanselmann
    @type fields: list of strings
1822 4e338533 Michael Hanselmann
    @param fields: Fields
1823 4e338533 Michael Hanselmann

1824 4e338533 Michael Hanselmann
    """
1825 4e338533 Michael Hanselmann
    raise NotImplementedError()
1826 4e338533 Michael Hanselmann
1827 4e338533 Michael Hanselmann
1828 4e338533 Michael Hanselmann
class JobPollReportCbBase:
1829 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} reporting callbacks.
1830 4e338533 Michael Hanselmann

1831 4e338533 Michael Hanselmann
  """
1832 4e338533 Michael Hanselmann
  def __init__(self):
1833 4e338533 Michael Hanselmann
    """Initializes this class.
1834 4e338533 Michael Hanselmann

1835 4e338533 Michael Hanselmann
    """
1836 4e338533 Michael Hanselmann
1837 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1838 4e338533 Michael Hanselmann
    """Handles a log message.
1839 4e338533 Michael Hanselmann

1840 4e338533 Michael Hanselmann
    """
1841 4e338533 Michael Hanselmann
    raise NotImplementedError()
1842 4e338533 Michael Hanselmann
1843 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1844 4e338533 Michael Hanselmann
    """Called for if a job hasn't changed in a while.
1845 4e338533 Michael Hanselmann

1846 4e338533 Michael Hanselmann
    @type job_id: number
1847 4e338533 Michael Hanselmann
    @param job_id: Job ID
1848 4e338533 Michael Hanselmann
    @type status: string or None
1849 4e338533 Michael Hanselmann
    @param status: Job status if available
1850 4e338533 Michael Hanselmann

1851 4e338533 Michael Hanselmann
    """
1852 4e338533 Michael Hanselmann
    raise NotImplementedError()
1853 4e338533 Michael Hanselmann
1854 4e338533 Michael Hanselmann
1855 4e338533 Michael Hanselmann
class _LuxiJobPollCb(JobPollCbBase):
1856 4e338533 Michael Hanselmann
  def __init__(self, cl):
1857 4e338533 Michael Hanselmann
    """Initializes this class.
1858 4e338533 Michael Hanselmann

1859 4e338533 Michael Hanselmann
    """
1860 4e338533 Michael Hanselmann
    JobPollCbBase.__init__(self)
1861 4e338533 Michael Hanselmann
    self.cl = cl
1862 4e338533 Michael Hanselmann
1863 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1864 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1865 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1866 4e338533 Michael Hanselmann

1867 4e338533 Michael Hanselmann
    """
1868 4e338533 Michael Hanselmann
    return self.cl.WaitForJobChangeOnce(job_id, fields,
1869 4e338533 Michael Hanselmann
                                        prev_job_info, prev_log_serial)
1870 4e338533 Michael Hanselmann
1871 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1872 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1873 4e338533 Michael Hanselmann

1874 4e338533 Michael Hanselmann
    """
1875 4e338533 Michael Hanselmann
    return self.cl.QueryJobs(job_ids, fields)
1876 4e338533 Michael Hanselmann
1877 4e338533 Michael Hanselmann
1878 4e338533 Michael Hanselmann
class FeedbackFnJobPollReportCb(JobPollReportCbBase):
1879 4e338533 Michael Hanselmann
  def __init__(self, feedback_fn):
1880 4e338533 Michael Hanselmann
    """Initializes this class.
1881 4e338533 Michael Hanselmann

1882 4e338533 Michael Hanselmann
    """
1883 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1884 4e338533 Michael Hanselmann
1885 4e338533 Michael Hanselmann
    self.feedback_fn = feedback_fn
1886 4e338533 Michael Hanselmann
1887 4e338533 Michael Hanselmann
    assert callable(feedback_fn)
1888 4e338533 Michael Hanselmann
1889 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1890 4e338533 Michael Hanselmann
    """Handles a log message.
1891 4e338533 Michael Hanselmann

1892 4e338533 Michael Hanselmann
    """
1893 4e338533 Michael Hanselmann
    self.feedback_fn((timestamp, log_type, log_msg))
1894 4e338533 Michael Hanselmann
1895 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1896 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1897 4e338533 Michael Hanselmann

1898 4e338533 Michael Hanselmann
    """
1899 4e338533 Michael Hanselmann
    # Ignore
1900 4e338533 Michael Hanselmann
1901 4e338533 Michael Hanselmann
1902 4e338533 Michael Hanselmann
class StdioJobPollReportCb(JobPollReportCbBase):
1903 4e338533 Michael Hanselmann
  def __init__(self):
1904 4e338533 Michael Hanselmann
    """Initializes this class.
1905 4e338533 Michael Hanselmann

1906 4e338533 Michael Hanselmann
    """
1907 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1908 4e338533 Michael Hanselmann
1909 4e338533 Michael Hanselmann
    self.notified_queued = False
1910 4e338533 Michael Hanselmann
    self.notified_waitlock = False
1911 4e338533 Michael Hanselmann
1912 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1913 4e338533 Michael Hanselmann
    """Handles a log message.
1914 4e338533 Michael Hanselmann

1915 4e338533 Michael Hanselmann
    """
1916 4e338533 Michael Hanselmann
    ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)),
1917 8a7f1c61 Michael Hanselmann
             FormatLogMessage(log_type, log_msg))
1918 4e338533 Michael Hanselmann
1919 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1920 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1921 4e338533 Michael Hanselmann

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

1938 8a7f1c61 Michael Hanselmann
  """
1939 8a7f1c61 Michael Hanselmann
  if log_type != constants.ELOG_MESSAGE:
1940 8a7f1c61 Michael Hanselmann
    log_msg = str(log_msg)
1941 8a7f1c61 Michael Hanselmann
1942 8a7f1c61 Michael Hanselmann
  return utils.SafeEncode(log_msg)
1943 8a7f1c61 Michael Hanselmann
1944 8a7f1c61 Michael Hanselmann
1945 583163a6 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None, reporter=None):
1946 4e338533 Michael Hanselmann
  """Function to poll for the result of a job.
1947 4e338533 Michael Hanselmann

1948 4e338533 Michael Hanselmann
  @type job_id: job identified
1949 4e338533 Michael Hanselmann
  @param job_id: the job to poll for results
1950 4e338533 Michael Hanselmann
  @type cl: luxi.Client
1951 4e338533 Michael Hanselmann
  @param cl: the luxi client to use for communicating with the master;
1952 4e338533 Michael Hanselmann
             if None, a new client will be created
1953 4e338533 Michael Hanselmann

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

1972 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1973 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1974 0a1e74d9 Iustin Pop
  interaction functions.
1975 0a1e74d9 Iustin Pop

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

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

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

2001 94428652 Iustin Pop
  """
2002 94428652 Iustin Pop
  if opts and opts.submit_only:
2003 293ba2d8 Iustin Pop
    job = [op]
2004 293ba2d8 Iustin Pop
    SetGenericOpcodeOpts(job, opts)
2005 293ba2d8 Iustin Pop
    job_id = SendJob(job, cl=cl)
2006 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
2007 94428652 Iustin Pop
  else:
2008 293ba2d8 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
2009 293ba2d8 Iustin Pop
2010 293ba2d8 Iustin Pop
2011 293ba2d8 Iustin Pop
def SetGenericOpcodeOpts(opcode_list, options):
2012 293ba2d8 Iustin Pop
  """Processor for generic options.
2013 293ba2d8 Iustin Pop

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

2017 293ba2d8 Iustin Pop
  @param opcode_list: list of opcodes
2018 293ba2d8 Iustin Pop
  @param options: command line options or None
2019 293ba2d8 Iustin Pop
  @return: None (in-place modification)
2020 293ba2d8 Iustin Pop

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

2058 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
2059 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
2060 73702ee7 Iustin Pop
  second, a string describing the error message (not
2061 73702ee7 Iustin Pop
  newline-terminated).
2062 73702ee7 Iustin Pop

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

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

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

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

2244 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
2245 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
2246 d77490c5 Iustin Pop
  @type args: list
2247 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
2248 d77490c5 Iustin Pop
  @rtype: int
2249 d77490c5 Iustin Pop
  @return: the desired exit code
2250 d77490c5 Iustin Pop

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

2381 7e49b6ce Michael Hanselmann
  """
2382 7e49b6ce Michael Hanselmann
  def __init__(self, feedback_fn, cluster_name, master_node, online_nodes):
2383 7e49b6ce Michael Hanselmann
    """Initializes this class.
2384 7e49b6ce Michael Hanselmann

2385 7e49b6ce Michael Hanselmann
    @type feedback_fn: callable
2386 7e49b6ce Michael Hanselmann
    @param feedback_fn: Feedback function
2387 7e49b6ce Michael Hanselmann
    @type cluster_name: string
2388 7e49b6ce Michael Hanselmann
    @param cluster_name: Cluster name
2389 7e49b6ce Michael Hanselmann
    @type master_node: string
2390 7e49b6ce Michael Hanselmann
    @param master_node Master node name
2391 7e49b6ce Michael Hanselmann
    @type online_nodes: list
2392 7e49b6ce Michael Hanselmann
    @param online_nodes: List of names of online nodes
2393 7e49b6ce Michael Hanselmann

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

2410 7e49b6ce Michael Hanselmann
    @type node_name: string
2411 7e49b6ce Michael Hanselmann
    @param node_name: Machine name
2412 7e49b6ce Michael Hanselmann
    @type cmd: list
2413 7e49b6ce Michael Hanselmann
    @param cmd: Command
2414 7e49b6ce Michael Hanselmann

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

2433 7e49b6ce Michael Hanselmann
    @type fn: callable
2434 7e49b6ce Michael Hanselmann
    @param fn: Function to be called
2435 7e49b6ce Michael Hanselmann

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

2476 7e49b6ce Michael Hanselmann
  @type feedback_fn: callable
2477 7e49b6ce Michael Hanselmann
  @param feedback_fn: Feedback function
2478 7e49b6ce Michael Hanselmann
  @type fn: callable
2479 7e49b6ce Michael Hanselmann
  @param fn: Function to be called when daemons are stopped
2480 7e49b6ce Michael Hanselmann

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

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

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

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

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

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

2663 ee3aedff Michael Hanselmann
  """
2664 f0b1bafe Iustin Pop
  def __init__(self, fn, status_fn, verbose):
2665 ee3aedff Michael Hanselmann
    """Initializes this class.
2666 ee3aedff Michael Hanselmann

2667 ee3aedff Michael Hanselmann
    @type fn: callable
2668 ee3aedff Michael Hanselmann
    @param fn: Formatting function
2669 ee3aedff Michael Hanselmann
    @type status_fn: callable
2670 ee3aedff Michael Hanselmann
    @param status_fn: Function to report fields' status
2671 f0b1bafe Iustin Pop
    @type verbose: boolean
2672 f0b1bafe Iustin Pop
    @param verbose: whether to use verbose field descriptions or not
2673 ee3aedff Michael Hanselmann

2674 ee3aedff Michael Hanselmann
    """
2675 ee3aedff Michael Hanselmann
    self._fn = fn
2676 ee3aedff Michael Hanselmann
    self._status_fn = status_fn
2677 cbfa4f0f Michael Hanselmann
    self._verbose = verbose
2678 ee3aedff Michael Hanselmann
2679 ee3aedff Michael Hanselmann
  def __call__(self, data):
2680 ee3aedff Michael Hanselmann
    """Returns a field's string representation.
2681 ee3aedff Michael Hanselmann

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

2700 ae95e419 René Nussbaumer
  @param status: The result status
2701 f2c6673d Michael Hanselmann
  @type verbose: boolean
2702 f2c6673d Michael Hanselmann
  @param verbose: Whether to return the verbose text
2703 ae95e419 René Nussbaumer
  @return: Text of result status
2704 a6070ef7 Michael Hanselmann

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

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

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

2785 ee3aedff Michael Hanselmann
  @type fdefs: list of L{objects.QueryFieldDefinition}
2786 ee3aedff Michael Hanselmann

2787 ee3aedff Michael Hanselmann
  """
2788 ee3aedff Michael Hanselmann
  return [fdef for fdef in fdefs
2789 ee3aedff Michael Hanselmann
          if fdef.kind == constants.QFT_UNKNOWN]
2790 ee3aedff Michael Hanselmann
2791 ee3aedff Michael Hanselmann
2792 ee3aedff Michael Hanselmann
def _WarnUnknownFields(fdefs):
2793 ee3aedff Michael Hanselmann
  """Prints a warning to stderr if a query included unknown fields.
2794 ee3aedff Michael Hanselmann

2795 ee3aedff Michael Hanselmann
  @type fdefs: list of L{objects.QueryFieldDefinition}
2796 ee3aedff Michael Hanselmann

2797 ee3aedff Michael Hanselmann
  """
2798 ee3aedff Michael Hanselmann
  unknown = _GetUnknownFields(fdefs)
2799 ee3aedff Michael Hanselmann
  if unknown:
2800 ee3aedff Michael Hanselmann
    ToStderr("Warning: Queried for unknown fields %s",
2801 ee3aedff Michael Hanselmann
             utils.CommaJoin(fdef.name for fdef in unknown))
2802 ee3aedff Michael Hanselmann
    return True
2803 ee3aedff Michael Hanselmann
2804 ee3aedff Michael Hanselmann
  return False
2805 ee3aedff Michael Hanselmann
2806 ee3aedff Michael Hanselmann
2807 ee3aedff Michael Hanselmann
def GenericList(resource, fields, names, unit, separator, header, cl=None,
2808 03ec545a Michael Hanselmann
                format_override=None, verbose=False, force_filter=False,
2809 f037e9d7 Michael Hanselmann
                namefield=None, qfilter=None):
2810 ee3aedff Michael Hanselmann
  """Generic implementation for listing all items of a resource.
2811 ee3aedff Michael Hanselmann

2812 abd66bf8 Michael Hanselmann
  @param resource: One of L{constants.QR_VIA_LUXI}
2813 ee3aedff Michael Hanselmann
  @type fields: list of strings
2814 ee3aedff Michael Hanselmann
  @param fields: List of fields to query for
2815 ee3aedff Michael Hanselmann
  @type names: list of strings
2816 ee3aedff Michael Hanselmann
  @param names: Names of items to query for
2817 ee3aedff Michael Hanselmann
  @type unit: string or None
2818 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT} or
2819 ee3aedff Michael Hanselmann
    None for automatic choice (human-readable for non-separator usage,
2820 ee3aedff Michael Hanselmann
    otherwise megabytes); this is a one-letter string
2821 ee3aedff Michael Hanselmann
  @type separator: string or None
2822 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2823 ee3aedff Michael Hanselmann
  @type header: bool
2824 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2825 2928de47 Michael Hanselmann
  @type force_filter: bool
2826 2928de47 Michael Hanselmann
  @param force_filter: Whether to always treat names as filter
2827 ee3aedff Michael Hanselmann
  @type format_override: dict
2828 ee3aedff Michael Hanselmann
  @param format_override: Dictionary for overriding field formatting functions,
2829 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2830 f0b1bafe Iustin Pop
  @type verbose: boolean
2831 f0b1bafe Iustin Pop
  @param verbose: whether to use verbose field descriptions or not
2832 03ec545a Michael Hanselmann
  @type namefield: string
2833 03ec545a Michael Hanselmann
  @param namefield: Name of field to use for simple filters (see
2834 03ec545a Michael Hanselmann
    L{qlang.MakeFilter} for details)
2835 f037e9d7 Michael Hanselmann
  @type qfilter: list or None
2836 f037e9d7 Michael Hanselmann
  @param qfilter: Query filter (in addition to names)
2837 ee3aedff Michael Hanselmann

2838 ee3aedff Michael Hanselmann
  """
2839 ee3aedff Michael Hanselmann
  if not names:
2840 ee3aedff Michael Hanselmann
    names = None
2841 ee3aedff Michael Hanselmann
2842 f037e9d7 Michael Hanselmann
  namefilter = qlang.MakeFilter(names, force_filter, namefield=namefield)
2843 f037e9d7 Michael Hanselmann
2844 f037e9d7 Michael Hanselmann
  if qfilter is None:
2845 f037e9d7 Michael Hanselmann
    qfilter = namefilter
2846 f037e9d7 Michael Hanselmann
  elif namefilter is not None:
2847 f037e9d7 Michael Hanselmann
    qfilter = [qlang.OP_AND, namefilter, qfilter]
2848 2928de47 Michael Hanselmann
2849 727274dd Iustin Pop
  if cl is None:
2850 727274dd Iustin Pop
    cl = GetClient()
2851 727274dd Iustin Pop
2852 2e5c33db Iustin Pop
  response = cl.Query(resource, fields, qfilter)
2853 ee3aedff Michael Hanselmann
2854 ee3aedff Michael Hanselmann
  found_unknown = _WarnUnknownFields(response.fields)
2855 ee3aedff Michael Hanselmann
2856 ee3aedff Michael Hanselmann
  (status, data) = FormatQueryResult(response, unit=unit, separator=separator,
2857 ee3aedff Michael Hanselmann
                                     header=header,
2858 f0b1bafe Iustin Pop
                                     format_override=format_override,
2859 f0b1bafe Iustin Pop
                                     verbose=verbose)
2860 ee3aedff Michael Hanselmann
2861 ee3aedff Michael Hanselmann
  for line in data:
2862 ee3aedff Michael Hanselmann
    ToStdout(line)
2863 ee3aedff Michael Hanselmann
2864 ee3aedff Michael Hanselmann
  assert ((found_unknown and status == QR_UNKNOWN) or
2865 ee3aedff Michael Hanselmann
          (not found_unknown and status != QR_UNKNOWN))
2866 ee3aedff Michael Hanselmann
2867 ee3aedff Michael Hanselmann
  if status == QR_UNKNOWN:
2868 ee3aedff Michael Hanselmann
    return constants.EXIT_UNKNOWN_FIELD
2869 ee3aedff Michael Hanselmann
2870 ee3aedff Michael Hanselmann
  # TODO: Should the list command fail if not all data could be collected?
2871 ee3aedff Michael Hanselmann
  return constants.EXIT_SUCCESS
2872 ee3aedff Michael Hanselmann
2873 ee3aedff Michael Hanselmann
2874 ee3aedff Michael Hanselmann
def GenericListFields(resource, fields, separator, header, cl=None):
2875 ee3aedff Michael Hanselmann
  """Generic implementation for listing fields for a resource.
2876 ee3aedff Michael Hanselmann

2877 abd66bf8 Michael Hanselmann
  @param resource: One of L{constants.QR_VIA_LUXI}
2878 ee3aedff Michael Hanselmann
  @type fields: list of strings
2879 ee3aedff Michael Hanselmann
  @param fields: List of fields to query for
2880 ee3aedff Michael Hanselmann
  @type separator: string or None
2881 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2882 ee3aedff Michael Hanselmann
  @type header: bool
2883 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2884 ee3aedff Michael Hanselmann

2885 ee3aedff Michael Hanselmann
  """
2886 ee3aedff Michael Hanselmann
  if cl is None:
2887 ee3aedff Michael Hanselmann
    cl = GetClient()
2888 ee3aedff Michael Hanselmann
2889 ee3aedff Michael Hanselmann
  if not fields:
2890 ee3aedff Michael Hanselmann
    fields = None
2891 ee3aedff Michael Hanselmann
2892 ee3aedff Michael Hanselmann
  response = cl.QueryFields(resource, fields)
2893 ee3aedff Michael Hanselmann
2894 ee3aedff Michael Hanselmann
  found_unknown = _WarnUnknownFields(response.fields)
2895 ee3aedff Michael Hanselmann
2896 ee3aedff Michael Hanselmann
  columns = [
2897 ee3aedff Michael Hanselmann
    TableColumn("Name", str, False),
2898 ee3aedff Michael Hanselmann
    TableColumn("Title", str, False),
2899 ea1440c1 Michael Hanselmann
    TableColumn("Description", str, False),
2900 ee3aedff Michael Hanselmann
    ]
2901 ee3aedff Michael Hanselmann
2902 ea1440c1 Michael Hanselmann
  rows = [[fdef.name, fdef.title, fdef.doc] for fdef in response.fields]
2903 ee3aedff Michael Hanselmann
2904 ee3aedff Michael Hanselmann
  for line in FormatTable(rows, columns, header, separator):
2905 ee3aedff Michael Hanselmann
    ToStdout(line)
2906 ee3aedff Michael Hanselmann
2907 ee3aedff Michael Hanselmann
  if found_unknown:
2908 ee3aedff Michael Hanselmann
    return constants.EXIT_UNKNOWN_FIELD
2909 ee3aedff Michael Hanselmann
2910 ee3aedff Michael Hanselmann
  return constants.EXIT_SUCCESS
2911 ee3aedff Michael Hanselmann
2912 ee3aedff Michael Hanselmann
2913 ee3aedff Michael Hanselmann
class TableColumn:
2914 ee3aedff Michael Hanselmann
  """Describes a column for L{FormatTable}.
2915 ee3aedff Michael Hanselmann

2916 ee3aedff Michael Hanselmann
  """
2917 ee3aedff Michael Hanselmann
  def __init__(self, title, fn, align_right):
2918 ee3aedff Michael Hanselmann
    """Initializes this class.
2919 ee3aedff Michael Hanselmann

2920 ee3aedff Michael Hanselmann
    @type title: string
2921 ee3aedff Michael Hanselmann
    @param title: Column title
2922 ee3aedff Michael Hanselmann
    @type fn: callable
2923 ee3aedff Michael Hanselmann
    @param fn: Formatting function
2924 ee3aedff Michael Hanselmann
    @type align_right: bool
2925 ee3aedff Michael Hanselmann
    @param align_right: Whether to align values on the right-hand side
2926 ee3aedff Michael Hanselmann

2927 ee3aedff Michael Hanselmann
    """
2928 ee3aedff Michael Hanselmann
    self.title = title
2929 ee3aedff Michael Hanselmann
    self.format = fn
2930 ee3aedff Michael Hanselmann
    self.align_right = align_right
2931 ee3aedff Michael Hanselmann
2932 ee3aedff Michael Hanselmann
2933 ee3aedff Michael Hanselmann
def _GetColFormatString(width, align_right):
2934 ee3aedff Michael Hanselmann
  """Returns the format string for a field.
2935 ee3aedff Michael Hanselmann

2936 ee3aedff Michael Hanselmann
  """
2937 ee3aedff Michael Hanselmann
  if align_right:
2938 ee3aedff Michael Hanselmann
    sign = ""
2939 ee3aedff Michael Hanselmann
  else:
2940 ee3aedff Michael Hanselmann
    sign = "-"
2941 ee3aedff Michael Hanselmann
2942 ee3aedff Michael Hanselmann
  return "%%%s%ss" % (sign, width)
2943 ee3aedff Michael Hanselmann
2944 ee3aedff Michael Hanselmann
2945 ee3aedff Michael Hanselmann
def FormatTable(rows, columns, header, separator):
2946 ee3aedff Michael Hanselmann
  """Formats data as a table.
2947 ee3aedff Michael Hanselmann

2948 ee3aedff Michael Hanselmann
  @type rows: list of lists
2949 ee3aedff Michael Hanselmann
  @param rows: Row data, one list per row
2950 ee3aedff Michael Hanselmann
  @type columns: list of L{TableColumn}
2951 ee3aedff Michael Hanselmann
  @param columns: Column descriptions
2952 ee3aedff Michael Hanselmann
  @type header: bool
2953 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2954 ee3aedff Michael Hanselmann
  @type separator: string or None
2955 ee3aedff Michael Hanselmann
  @param separator: String used to separate columns
2956 ee3aedff Michael Hanselmann

2957 ee3aedff Michael Hanselmann
  """
2958 ee3aedff Michael Hanselmann
  if header:
2959 ee3aedff Michael Hanselmann
    data = [[col.title for col in columns]]
2960 ee3aedff Michael Hanselmann
    colwidth = [len(col.title) for col in columns]
2961 ee3aedff Michael Hanselmann
  else:
2962 ee3aedff Michael Hanselmann
    data = []
2963 ee3aedff Michael Hanselmann
    colwidth = [0 for _ in columns]
2964 ee3aedff Michael Hanselmann
2965 ee3aedff Michael Hanselmann
  # Format row data
2966 ee3aedff Michael Hanselmann
  for row in rows:
2967 ee3aedff Michael Hanselmann
    assert len(row) == len(columns)
2968 ee3aedff Michael Hanselmann
2969 ee3aedff Michael Hanselmann
    formatted = [col.format(value) for value, col in zip(row, columns)]
2970 ee3aedff Michael Hanselmann
2971 ee3aedff Michael Hanselmann
    if separator is None:
2972 ee3aedff Michael Hanselmann
      # Update column widths
2973 ee3aedff Michael Hanselmann
      for idx, (oldwidth, value) in enumerate(zip(colwidth, formatted)):
2974 ee3aedff Michael Hanselmann
        # Modifying a list's items while iterating is fine
2975 ee3aedff Michael Hanselmann
        colwidth[idx] = max(oldwidth, len(value))
2976 ee3aedff Michael Hanselmann
2977 ee3aedff Michael Hanselmann
    data.append(formatted)
2978 ee3aedff Michael Hanselmann
2979 ee3aedff Michael Hanselmann
  if separator is not None:
2980 ee3aedff Michael Hanselmann
    # Return early if a separator is used
2981 ee3aedff Michael Hanselmann
    return [separator.join(row) for row in data]
2982 ee3aedff Michael Hanselmann
2983 ee3aedff Michael Hanselmann
  if columns and not columns[-1].align_right:
2984 ee3aedff Michael Hanselmann
    # Avoid unnecessary spaces at end of line
2985 ee3aedff Michael Hanselmann
    colwidth[-1] = 0
2986 ee3aedff Michael Hanselmann
2987 ee3aedff Michael Hanselmann
  # Build format string
2988 ee3aedff Michael Hanselmann
  fmt = " ".join([_GetColFormatString(width, col.align_right)
2989 ee3aedff Michael Hanselmann
                  for col, width in zip(columns, colwidth)])
2990 ee3aedff Michael Hanselmann
2991 ee3aedff Michael Hanselmann
  return [fmt % tuple(row) for row in data]
2992 ee3aedff Michael Hanselmann
2993 ee3aedff Michael Hanselmann
2994 3386e7a9 Iustin Pop
def FormatTimestamp(ts):
2995 3386e7a9 Iustin Pop
  """Formats a given timestamp.
2996 3386e7a9 Iustin Pop

2997 3386e7a9 Iustin Pop
  @type ts: timestamp
2998 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
2999 3386e7a9 Iustin Pop

3000 3386e7a9 Iustin Pop
  @rtype: string
3001 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
3002 3386e7a9 Iustin Pop

3003 3386e7a9 Iustin Pop
  """
3004 e687ec01 Michael Hanselmann
  if not isinstance(ts, (tuple, list)) or len(ts) != 2:
3005 d0c8c01d Iustin Pop
    return "?"
3006 26a72a48 Michael Hanselmann
3007 26a72a48 Michael Hanselmann
  (sec, usecs) = ts
3008 26a72a48 Michael Hanselmann
  return utils.FormatTime(sec, usecs=usecs)
3009 2241e2b9 Iustin Pop
3010 2241e2b9 Iustin Pop
3011 2241e2b9 Iustin Pop
def ParseTimespec(value):
3012 2241e2b9 Iustin Pop
  """Parse a time specification.
3013 2241e2b9 Iustin Pop

3014 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
3015 2241e2b9 Iustin Pop

3016 2241e2b9 Iustin Pop
    - s: seconds
3017 2241e2b9 Iustin Pop
    - m: minutes
3018 2241e2b9 Iustin Pop
    - h: hours
3019 2241e2b9 Iustin Pop
    - d: day
3020 2241e2b9 Iustin Pop
    - w: weeks
3021 2241e2b9 Iustin Pop

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

3024 2241e2b9 Iustin Pop
  """
3025 2241e2b9 Iustin Pop
  value = str(value)
3026 2241e2b9 Iustin Pop
  if not value:
3027 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
3028 2241e2b9 Iustin Pop
  suffix_map = {
3029 d0c8c01d Iustin Pop
    "s": 1,
3030 d0c8c01d Iustin Pop
    "m": 60,
3031 d0c8c01d Iustin Pop
    "h": 3600,
3032 d0c8c01d Iustin Pop
    "d": 86400,
3033 d0c8c01d Iustin Pop
    "w": 604800,
3034 2241e2b9 Iustin Pop
    }
3035 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
3036 2241e2b9 Iustin Pop
    try:
3037 2241e2b9 Iustin Pop
      value = int(value)
3038 691744c4 Iustin Pop
    except (TypeError, ValueError):
3039 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
3040 2241e2b9 Iustin Pop
  else:
3041 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
3042 2241e2b9 Iustin Pop
    value = value[:-1]
3043 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
3044 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
3045 2241e2b9 Iustin Pop
                                 " suffix passed)")
3046 2241e2b9 Iustin Pop
    try:
3047 2241e2b9 Iustin Pop
      value = int(value) * multiplier
3048 691744c4 Iustin Pop
    except (TypeError, ValueError):
3049 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
3050 2241e2b9 Iustin Pop
  return value
3051 46fbdd04 Iustin Pop
3052 46fbdd04 Iustin Pop
3053 e9e26bb3 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False, secondary_ips=False,
3054 05484a24 Michael Hanselmann
                   filter_master=False, nodegroup=None):
3055 4040a784 Iustin Pop
  """Returns the names of online nodes.
3056 4040a784 Iustin Pop

3057 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
3058 4040a784 Iustin Pop
  the online nodes.
3059 4040a784 Iustin Pop

3060 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
3061 4040a784 Iustin Pop
      offline ones)
3062 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
3063 4040a784 Iustin Pop
  @type nowarn: boolean
3064 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
3065 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
3066 4040a784 Iustin Pop
      note is not displayed
3067 e9e26bb3 Iustin Pop
  @type secondary_ips: boolean
3068 e9e26bb3 Iustin Pop
  @param secondary_ips: if True, return the secondary IPs instead of the
3069 e9e26bb3 Iustin Pop
      names, useful for doing network traffic over the replication interface
3070 e9e26bb3 Iustin Pop
      (if any)
3071 e9e26bb3 Iustin Pop
  @type filter_master: boolean
3072 e9e26bb3 Iustin Pop
  @param filter_master: if True, do not return the master node in the list
3073 e9e26bb3 Iustin Pop
      (useful in coordination with secondary_ips where we cannot check our
3074 e9e26bb3 Iustin Pop
      node name against the list)
3075 05484a24 Michael Hanselmann
  @type nodegroup: string
3076 05484a24 Michael Hanselmann
  @param nodegroup: If set, only return nodes in this node group
3077 4040a784 Iustin Pop

3078 4040a784 Iustin Pop
  """
3079 4040a784 Iustin Pop
  if cl is None:
3080 4040a784 Iustin Pop
    cl = GetClient()
3081 4040a784 Iustin Pop
3082 2e5c33db Iustin Pop
  qfilter = []
3083 05484a24 Michael Hanselmann
3084 05484a24 Michael Hanselmann
  if nodes:
3085 2e5c33db Iustin Pop
    qfilter.append(qlang.MakeSimpleFilter("name", nodes))
3086 05484a24 Michael Hanselmann
3087 05484a24 Michael Hanselmann
  if nodegroup is not None:
3088 2e5c33db Iustin Pop
    qfilter.append([qlang.OP_OR, [qlang.OP_EQUAL, "group", nodegroup],
3089 05484a24 Michael Hanselmann
                                 [qlang.OP_EQUAL, "group.uuid", nodegroup]])
3090 e9e26bb3 Iustin Pop
3091 e9e26bb3 Iustin Pop
  if filter_master:
3092 2e5c33db Iustin Pop
    qfilter.append([qlang.OP_NOT, [qlang.OP_TRUE, "master"]])
3093 05484a24 Michael Hanselmann
3094 2e5c33db Iustin Pop
  if qfilter:
3095 2e5c33db Iustin Pop
    if len(qfilter) > 1:
3096 2e5c33db Iustin Pop
      final_filter = [qlang.OP_AND] + qfilter
3097 05484a24 Michael Hanselmann
    else:
3098 2e5c33db Iustin Pop
      assert len(qfilter) == 1
3099 2e5c33db Iustin Pop
      final_filter = qfilter[0]
3100 e9e26bb3 Iustin Pop
  else:
3101 05484a24 Michael Hanselmann
    final_filter = None
3102 05484a24 Michael Hanselmann
3103 05484a24 Michael Hanselmann
  result = cl.Query(constants.QR_NODE, ["name", "offline", "sip"], final_filter)
3104 05484a24 Michael Hanselmann
3105 05484a24 Michael Hanselmann
  def _IsOffline(row):
3106 05484a24 Michael Hanselmann
    (_, (_, offline), _) = row
3107 05484a24 Michael Hanselmann
    return offline
3108 05484a24 Michael Hanselmann
3109 05484a24 Michael Hanselmann
  def _GetName(row):
3110 05484a24 Michael Hanselmann
    ((_, name), _, _) = row
3111 05484a24 Michael Hanselmann
    return name
3112 05484a24 Michael Hanselmann
3113 05484a24 Michael Hanselmann
  def _GetSip(row):
3114 05484a24 Michael Hanselmann
    (_, _, (_, sip)) = row
3115 05484a24 Michael Hanselmann
    return sip
3116 05484a24 Michael Hanselmann
3117 05484a24 Michael Hanselmann
  (offline, online) = compat.partition(result.data, _IsOffline)
3118 e9e26bb3 Iustin Pop
3119 4040a784 Iustin Pop
  if offline and not nowarn:
3120 05484a24 Michael Hanselmann
    ToStderr("Note: skipping offline node(s): %s" %
3121 05484a24 Michael Hanselmann
             utils.CommaJoin(map(_GetName, offline)))
3122 05484a24 Michael Hanselmann
3123 05484a24 Michael Hanselmann
  if secondary_ips:
3124 05484a24 Michael Hanselmann
    fn = _GetSip
3125 05484a24 Michael Hanselmann
  else:
3126 05484a24 Michael Hanselmann
    fn = _GetName
3127 05484a24 Michael Hanselmann
3128 05484a24 Michael Hanselmann
  return map(fn, online)
3129 4040a784 Iustin Pop
3130 4040a784 Iustin Pop
3131 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
3132 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
3133 46fbdd04 Iustin Pop

3134 46fbdd04 Iustin Pop
  @type stream: file object
3135 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
3136 46fbdd04 Iustin Pop
  @type txt: str
3137 46fbdd04 Iustin Pop
  @param txt: the message
3138 46fbdd04 Iustin Pop

3139 46fbdd04 Iustin Pop
  """
3140 225e2544 Iustin Pop
  try:
3141 225e2544 Iustin Pop
    if args:
3142 225e2544 Iustin Pop
      args = tuple(args)
3143 225e2544 Iustin Pop
      stream.write(txt % args)
3144 225e2544 Iustin Pop
    else:
3145 225e2544 Iustin Pop
      stream.write(txt)
3146 d0c8c01d Iustin Pop
    stream.write("\n")
3147 225e2544 Iustin Pop
    stream.flush()
3148 225e2544 Iustin Pop
  except IOError, err:
3149 225e2544 Iustin Pop
    if err.errno == errno.EPIPE:
3150 225e2544 Iustin Pop
      # our terminal went away, we'll exit
3151 225e2544 Iustin Pop
      sys.exit(constants.EXIT_FAILURE)
3152 225e2544 Iustin Pop
    else:
3153 225e2544 Iustin Pop
      raise
3154 46fbdd04 Iustin Pop
3155 46fbdd04 Iustin Pop
3156 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
3157 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
3158 46fbdd04 Iustin Pop

3159 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
3160 46fbdd04 Iustin Pop

3161 46fbdd04 Iustin Pop
  @type txt: str
3162 46fbdd04 Iustin Pop
  @param txt: the message
3163 46fbdd04 Iustin Pop

3164 46fbdd04 Iustin Pop
  """
3165 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
3166 46fbdd04 Iustin Pop
3167 46fbdd04 Iustin Pop
3168 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
3169 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
3170 46fbdd04 Iustin Pop

3171 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
3172 46fbdd04 Iustin Pop

3173 46fbdd04 Iustin Pop
  @type txt: str
3174 46fbdd04 Iustin Pop
  @param txt: the message
3175 46fbdd04 Iustin Pop

3176 46fbdd04 Iustin Pop
  """
3177 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
3178 479636a3 Iustin Pop
3179 479636a3 Iustin Pop
3180 479636a3 Iustin Pop
class JobExecutor(object):
3181 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
3182 479636a3 Iustin Pop

3183 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
3184 479636a3 Iustin Pop
  GetResults() calls.
3185 479636a3 Iustin Pop

3186 479636a3 Iustin Pop
  """
3187 919ca415 Iustin Pop
  def __init__(self, cl=None, verbose=True, opts=None, feedback_fn=None):
3188 479636a3 Iustin Pop
    self.queue = []
3189 479636a3 Iustin Pop
    if cl is None:
3190 479636a3 Iustin Pop
      cl = GetClient()
3191 479636a3 Iustin Pop
    self.cl = cl
3192 479636a3 Iustin Pop
    self.verbose = verbose
3193 23b4b983 Iustin Pop
    self.jobs = []
3194 cff5fa7f Iustin Pop
    self.opts = opts
3195 919ca415 Iustin Pop
    self.feedback_fn = feedback_fn
3196 60452edf Michael Hanselmann
    self._counter = itertools.count()
3197 479636a3 Iustin Pop
3198 8d99a8bf Michael Hanselmann
  @staticmethod
3199 8d99a8bf Michael Hanselmann
  def _IfName(name, fmt):
3200 8d99a8bf Michael Hanselmann
    """Helper function for formatting name.
3201 8d99a8bf Michael Hanselmann

3202 8d99a8bf Michael Hanselmann
    """
3203 8d99a8bf Michael Hanselmann
    if name:
3204 8d99a8bf Michael Hanselmann
      return fmt % name
3205 8d99a8bf Michael Hanselmann
3206 8d99a8bf Michael Hanselmann
    return ""
3207 8d99a8bf Michael Hanselmann
3208 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
3209 23b4b983 Iustin Pop
    """Record a job for later submit.
3210 479636a3 Iustin Pop

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

3214 479636a3 Iustin Pop
    """
3215 cff5fa7f Iustin Pop
    SetGenericOpcodeOpts(ops, self.opts)
3216 60452edf Michael Hanselmann
    self.queue.append((self._counter.next(), name, ops))
3217 23b4b983 Iustin Pop
3218 8d99a8bf Michael Hanselmann
  def AddJobId(self, name, status, job_id):
3219 8d99a8bf Michael Hanselmann
    """Adds a job ID to the internal queue.
3220 8d99a8bf Michael Hanselmann

3221 8d99a8bf Michael Hanselmann
    """
3222 8d99a8bf Michael Hanselmann
    self.jobs.append((self._counter.next(), status, job_id, name))
3223 8d99a8bf Michael Hanselmann
3224 66ecc479 Guido Trotter
  def SubmitPending(self, each=False):
3225 23b4b983 Iustin Pop
    """Submit all pending jobs.
3226 23b4b983 Iustin Pop

3227 23b4b983 Iustin Pop
    """
3228 66ecc479 Guido Trotter
    if each:
3229 66ecc479 Guido Trotter
      results = []
3230 60452edf Michael Hanselmann
      for (_, _, ops) in self.queue:
3231 66ecc479 Guido Trotter
        # SubmitJob will remove the success status, but raise an exception if
3232 66ecc479 Guido Trotter
        # the submission fails, so we'll notice that anyway.
3233 519fafa1 Andrea Spadaccini
        results.append([True, self.cl.SubmitJob(ops)[0]])
3234 66ecc479 Guido Trotter
    else:
3235 60452edf Michael Hanselmann
      results = self.cl.SubmitManyJobs([ops for (_, _, ops) in self.queue])
3236 60452edf Michael Hanselmann
    for ((status, data), (idx, name, _)) in zip(results, self.queue):
3237 5299e61f Iustin Pop
      self.jobs.append((idx, status, data, name))
3238 5299e61f Iustin Pop
3239 5299e61f Iustin Pop
  def _ChooseJob(self):
3240 5299e61f Iustin Pop
    """Choose a non-waiting/queued job to poll next.
3241 5299e61f Iustin Pop

3242 5299e61f Iustin Pop
    """
3243 5299e61f Iustin Pop
    assert self.jobs, "_ChooseJob called with empty job list"
3244 5299e61f Iustin Pop
3245 11705e3d Iustin Pop
    result = self.cl.QueryJobs([i[2] for i in self.jobs[:_CHOOSE_BATCH]],
3246 11705e3d Iustin Pop
                               ["status"])
3247 5299e61f Iustin Pop
    assert result
3248 5299e61f Iustin Pop
3249 5299e61f Iustin Pop
    for job_data, status in zip(self.jobs, result):
3250 91c622a8 Iustin Pop
      if (isinstance(status, list) and status and
3251 91c622a8 Iustin Pop
          status[0] in (constants.JOB_STATUS_QUEUED,
3252 47099cd1 Michael Hanselmann
                        constants.JOB_STATUS_WAITING,
3253 91c622a8 Iustin Pop
                        constants.JOB_STATUS_CANCELING)):
3254 91c622a8 Iustin Pop
        # job is still present and waiting
3255 5299e61f Iustin Pop
        continue
3256 91c622a8 Iustin Pop
      # good candidate found (either running job or lost job)
3257 5299e61f Iustin Pop
      self.jobs.remove(job_data)
3258 5299e61f Iustin Pop
      return job_data
3259 5299e61f Iustin Pop
3260 5299e61f Iustin Pop
    # no job found
3261 5299e61f Iustin Pop
    return self.jobs.pop(0)
3262 479636a3 Iustin Pop
3263 479636a3 Iustin Pop
  def GetResults(self):
3264 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
3265 479636a3 Iustin Pop

3266 479636a3 Iustin Pop
    @rtype: list
3267 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
3268 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
3269 479636a3 Iustin Pop
        there will be the error message
3270 479636a3 Iustin Pop

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

3315 479636a3 Iustin Pop
    @type wait: boolean
3316 479636a3 Iustin Pop
    @param wait: whether to wait or not
3317 479636a3 Iustin Pop

3318 479636a3 Iustin Pop
    """
3319 479636a3 Iustin Pop
    if wait:
3320 479636a3 Iustin Pop
      return self.GetResults()
3321 479636a3 Iustin Pop
    else:
3322 23b4b983 Iustin Pop
      if not self.jobs:
3323 23b4b983 Iustin Pop
        self.SubmitPending()
3324 71834b2a Guido Trotter
      for _, status, result, name in self.jobs:
3325 23b4b983 Iustin Pop
        if status:
3326 4474f112 Iustin Pop
          ToStdout("%s: %s", result, name)
3327 23b4b983 Iustin Pop
        else:
3328 4474f112 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)
3329 53a8a54d Iustin Pop
      return [row[1:3] for row in self.jobs]
3330 acd19189 René Nussbaumer
3331 acd19189 René Nussbaumer
3332 acd19189 René Nussbaumer
def FormatParameterDict(buf, param_dict, actual, level=1):
3333 acd19189 René Nussbaumer
  """Formats a parameter dictionary.
3334 acd19189 René Nussbaumer

3335 acd19189 René Nussbaumer
  @type buf: L{StringIO}
3336 acd19189 René Nussbaumer
  @param buf: the buffer into which to write
3337 acd19189 René Nussbaumer
  @type param_dict: dict
3338 acd19189 René Nussbaumer
  @param param_dict: the own parameters
3339 acd19189 René Nussbaumer
  @type actual: dict
3340 acd19189 René Nussbaumer
  @param actual: the current parameter set (including defaults)
3341 acd19189 René Nussbaumer
  @param level: Level of indent
3342 acd19189 René Nussbaumer

3343 acd19189 René Nussbaumer
  """
3344 acd19189 René Nussbaumer
  indent = "  " * level
3345 acd19189 René Nussbaumer
  for key in sorted(actual):
3346 acd19189 René Nussbaumer
    val = param_dict.get(key, "default (%s)" % actual[key])
3347 acd19189 René Nussbaumer
    buf.write("%s- %s: %s\n" % (indent, key, val))
3348 25bd815c René Nussbaumer
3349 25bd815c René Nussbaumer
3350 25bd815c René Nussbaumer
def ConfirmOperation(names, list_type, text, extra=""):
3351 25bd815c René Nussbaumer
  """Ask the user to confirm an operation on a list of list_type.
3352 25bd815c René Nussbaumer

3353 25bd815c René Nussbaumer
  This function is used to request confirmation for doing an operation
3354 25bd815c René Nussbaumer
  on a given list of list_type.
3355 25bd815c René Nussbaumer

3356 25bd815c René Nussbaumer
  @type names: list
3357 25bd815c René Nussbaumer
  @param names: the list of names that we display when
3358 25bd815c René Nussbaumer
      we ask for confirmation
3359 25bd815c René Nussbaumer
  @type list_type: str
3360 25bd815c René Nussbaumer
  @param list_type: Human readable name for elements in the list (e.g. nodes)
3361 25bd815c René Nussbaumer
  @type text: str
3362 25bd815c René Nussbaumer
  @param text: the operation that the user should confirm
3363 25bd815c René Nussbaumer
  @rtype: boolean
3364 25bd815c René Nussbaumer
  @return: True or False depending on user's confirmation.
3365 25bd815c René Nussbaumer

3366 25bd815c René Nussbaumer
  """
3367 25bd815c René Nussbaumer
  count = len(names)
3368 25bd815c René Nussbaumer
  msg = ("The %s will operate on %d %s.\n%s"
3369 25bd815c René Nussbaumer
         "Do you want to continue?" % (text, count, list_type, extra))
3370 25bd815c René Nussbaumer
  affected = (("\nAffected %s:\n" % list_type) +
3371 25bd815c René Nussbaumer
              "\n".join(["  %s" % name for name in names]))
3372 25bd815c René Nussbaumer
3373 25bd815c René Nussbaumer
  choices = [("y", True, "Yes, execute the %s" % text),
3374 25bd815c René Nussbaumer
             ("n", False, "No, abort the %s" % text)]
3375 25bd815c René Nussbaumer
3376 25bd815c René Nussbaumer
  if count > 20:
3377 25bd815c René Nussbaumer
    choices.insert(1, ("v", "v", "View the list of affected %s" % list_type))
3378 25bd815c René Nussbaumer
    question = msg
3379 25bd815c René Nussbaumer
  else:
3380 25bd815c René Nussbaumer
    question = msg + affected
3381 25bd815c René Nussbaumer
3382 25bd815c René Nussbaumer
  choice = AskUser(question, choices)
3383 25bd815c René Nussbaumer
  if choice == "v":
3384 25bd815c René Nussbaumer
    choices.pop(1)
3385 25bd815c René Nussbaumer
    choice = AskUser(msg + affected, choices)
3386 25bd815c René Nussbaumer
  return choice