Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ 5a7cb9d3

History | View | Annotate | Download (117.8 kB)

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

318 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor.
319 863d7f46 Michael Hanselmann

320 863d7f46 Michael Hanselmann
  """
321 b459a848 Andrea Spadaccini
  # pylint: disable=W0622
322 863d7f46 Michael Hanselmann
  def __init__(self, min=0, max=None, choices=None):
323 863d7f46 Michael Hanselmann
    _Argument.__init__(self, min=min, max=max)
324 863d7f46 Michael Hanselmann
    self.choices = choices
325 863d7f46 Michael Hanselmann
326 863d7f46 Michael Hanselmann
  def __repr__(self):
327 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s choices=%r>" %
328 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max, self.choices))
329 863d7f46 Michael Hanselmann
330 863d7f46 Michael Hanselmann
331 863d7f46 Michael Hanselmann
class ArgChoice(ArgSuggest):
332 863d7f46 Michael Hanselmann
  """Choice argument.
333 863d7f46 Michael Hanselmann

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

337 863d7f46 Michael Hanselmann
  """
338 863d7f46 Michael Hanselmann
339 863d7f46 Michael Hanselmann
340 863d7f46 Michael Hanselmann
class ArgUnknown(_Argument):
341 863d7f46 Michael Hanselmann
  """Unknown argument to program (e.g. determined at runtime).
342 863d7f46 Michael Hanselmann

343 863d7f46 Michael Hanselmann
  """
344 863d7f46 Michael Hanselmann
345 863d7f46 Michael Hanselmann
346 863d7f46 Michael Hanselmann
class ArgInstance(_Argument):
347 863d7f46 Michael Hanselmann
  """Instances argument.
348 863d7f46 Michael Hanselmann

349 863d7f46 Michael Hanselmann
  """
350 863d7f46 Michael Hanselmann
351 863d7f46 Michael Hanselmann
352 863d7f46 Michael Hanselmann
class ArgNode(_Argument):
353 863d7f46 Michael Hanselmann
  """Node argument.
354 863d7f46 Michael Hanselmann

355 863d7f46 Michael Hanselmann
  """
356 863d7f46 Michael Hanselmann
357 667dbd6b Adeodato Simo
358 667dbd6b Adeodato Simo
class ArgGroup(_Argument):
359 667dbd6b Adeodato Simo
  """Node group argument.
360 667dbd6b Adeodato Simo

361 667dbd6b Adeodato Simo
  """
362 667dbd6b Adeodato Simo
363 667dbd6b Adeodato Simo
364 863d7f46 Michael Hanselmann
class ArgJobId(_Argument):
365 863d7f46 Michael Hanselmann
  """Job ID argument.
366 863d7f46 Michael Hanselmann

367 863d7f46 Michael Hanselmann
  """
368 863d7f46 Michael Hanselmann
369 863d7f46 Michael Hanselmann
370 863d7f46 Michael Hanselmann
class ArgFile(_Argument):
371 863d7f46 Michael Hanselmann
  """File path argument.
372 863d7f46 Michael Hanselmann

373 863d7f46 Michael Hanselmann
  """
374 863d7f46 Michael Hanselmann
375 863d7f46 Michael Hanselmann
376 863d7f46 Michael Hanselmann
class ArgCommand(_Argument):
377 863d7f46 Michael Hanselmann
  """Command argument.
378 863d7f46 Michael Hanselmann

379 863d7f46 Michael Hanselmann
  """
380 863d7f46 Michael Hanselmann
381 863d7f46 Michael Hanselmann
382 83ec7961 Michael Hanselmann
class ArgHost(_Argument):
383 83ec7961 Michael Hanselmann
  """Host argument.
384 83ec7961 Michael Hanselmann

385 83ec7961 Michael Hanselmann
  """
386 83ec7961 Michael Hanselmann
387 83ec7961 Michael Hanselmann
388 f9faf9c3 René Nussbaumer
class ArgOs(_Argument):
389 f9faf9c3 René Nussbaumer
  """OS argument.
390 f9faf9c3 René Nussbaumer

391 f9faf9c3 René Nussbaumer
  """
392 f9faf9c3 René Nussbaumer
393 f9faf9c3 René Nussbaumer
394 4a265c08 Michael Hanselmann
ARGS_NONE = []
395 4a265c08 Michael Hanselmann
ARGS_MANY_INSTANCES = [ArgInstance()]
396 4a265c08 Michael Hanselmann
ARGS_MANY_NODES = [ArgNode()]
397 667dbd6b Adeodato Simo
ARGS_MANY_GROUPS = [ArgGroup()]
398 4a265c08 Michael Hanselmann
ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
399 4a265c08 Michael Hanselmann
ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
400 dadf6b7d Michael Hanselmann
# TODO
401 dadf6b7d Michael Hanselmann
ARGS_ONE_GROUP = [ArgGroup(min=1, max=1)]
402 f9faf9c3 René Nussbaumer
ARGS_ONE_OS = [ArgOs(min=1, max=1)]
403 4a265c08 Michael Hanselmann
404 4a265c08 Michael Hanselmann
405 846baef9 Iustin Pop
def _ExtractTagsObject(opts, args):
406 846baef9 Iustin Pop
  """Extract the tag type object.
407 846baef9 Iustin Pop

408 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
409 846baef9 Iustin Pop

410 846baef9 Iustin Pop
  """
411 846baef9 Iustin Pop
  if not hasattr(opts, "tag_type"):
412 846baef9 Iustin Pop
    raise errors.ProgrammerError("tag_type not passed to _ExtractTagsObject")
413 846baef9 Iustin Pop
  kind = opts.tag_type
414 846baef9 Iustin Pop
  if kind == constants.TAG_CLUSTER:
415 846baef9 Iustin Pop
    retval = kind, kind
416 819cbfe5 Michael Hanselmann
  elif kind in (constants.TAG_NODEGROUP,
417 819cbfe5 Michael Hanselmann
                constants.TAG_NODE,
418 819cbfe5 Michael Hanselmann
                constants.TAG_INSTANCE):
419 846baef9 Iustin Pop
    if not args:
420 2cfbc784 Iustin Pop
      raise errors.OpPrereqError("no arguments passed to the command",
421 2cfbc784 Iustin Pop
                                 errors.ECODE_INVAL)
422 846baef9 Iustin Pop
    name = args.pop(0)
423 846baef9 Iustin Pop
    retval = kind, name
424 846baef9 Iustin Pop
  else:
425 846baef9 Iustin Pop
    raise errors.ProgrammerError("Unhandled tag type '%s'" % kind)
426 846baef9 Iustin Pop
  return retval
427 846baef9 Iustin Pop
428 846baef9 Iustin Pop
429 810c50b7 Iustin Pop
def _ExtendTags(opts, args):
430 810c50b7 Iustin Pop
  """Extend the args if a source file has been given.
431 810c50b7 Iustin Pop

432 810c50b7 Iustin Pop
  This function will extend the tags with the contents of the file
433 810c50b7 Iustin Pop
  passed in the 'tags_source' attribute of the opts parameter. A file
434 810c50b7 Iustin Pop
  named '-' will be replaced by stdin.
435 810c50b7 Iustin Pop

436 810c50b7 Iustin Pop
  """
437 810c50b7 Iustin Pop
  fname = opts.tags_source
438 810c50b7 Iustin Pop
  if fname is None:
439 810c50b7 Iustin Pop
    return
440 810c50b7 Iustin Pop
  if fname == "-":
441 810c50b7 Iustin Pop
    new_fh = sys.stdin
442 810c50b7 Iustin Pop
  else:
443 810c50b7 Iustin Pop
    new_fh = open(fname, "r")
444 810c50b7 Iustin Pop
  new_data = []
445 810c50b7 Iustin Pop
  try:
446 810c50b7 Iustin Pop
    # we don't use the nice 'new_data = [line.strip() for line in fh]'
447 810c50b7 Iustin Pop
    # because of python bug 1633941
448 810c50b7 Iustin Pop
    while True:
449 810c50b7 Iustin Pop
      line = new_fh.readline()
450 810c50b7 Iustin Pop
      if not line:
451 810c50b7 Iustin Pop
        break
452 810c50b7 Iustin Pop
      new_data.append(line.strip())
453 810c50b7 Iustin Pop
  finally:
454 810c50b7 Iustin Pop
    new_fh.close()
455 810c50b7 Iustin Pop
  args.extend(new_data)
456 810c50b7 Iustin Pop
457 810c50b7 Iustin Pop
458 846baef9 Iustin Pop
def ListTags(opts, args):
459 846baef9 Iustin Pop
  """List the 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 f2374060 Iustin Pop
  cl = GetClient(query=True)
469 7699c3af Iustin Pop
  result = cl.QueryTags(kind, name)
470 846baef9 Iustin Pop
  result = list(result)
471 846baef9 Iustin Pop
  result.sort()
472 846baef9 Iustin Pop
  for tag in result:
473 03298ebe Michael Hanselmann
    ToStdout(tag)
474 846baef9 Iustin Pop
475 846baef9 Iustin Pop
476 846baef9 Iustin Pop
def AddTags(opts, args):
477 846baef9 Iustin Pop
  """Add tags on a given object.
478 846baef9 Iustin Pop

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

484 846baef9 Iustin Pop
  """
485 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
486 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
487 846baef9 Iustin Pop
  if not args:
488 2cfbc784 Iustin Pop
    raise errors.OpPrereqError("No tags to be added", errors.ECODE_INVAL)
489 d1602edc Iustin Pop
  op = opcodes.OpTagsSet(kind=kind, name=name, tags=args)
490 6bc3ed14 Michael Hanselmann
  SubmitOrSend(op, opts)
491 846baef9 Iustin Pop
492 846baef9 Iustin Pop
493 846baef9 Iustin Pop
def RemoveTags(opts, args):
494 846baef9 Iustin Pop
  """Remove tags from a given object.
495 846baef9 Iustin Pop

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

501 846baef9 Iustin Pop
  """
502 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
503 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
504 846baef9 Iustin Pop
  if not args:
505 2cfbc784 Iustin Pop
    raise errors.OpPrereqError("No tags to be removed", errors.ECODE_INVAL)
506 3f0ab95f Iustin Pop
  op = opcodes.OpTagsDel(kind=kind, name=name, tags=args)
507 6bc3ed14 Michael Hanselmann
  SubmitOrSend(op, opts)
508 846baef9 Iustin Pop
509 a8083063 Iustin Pop
510 b459a848 Andrea Spadaccini
def check_unit(option, opt, value): # pylint: disable=W0613
511 65fe4693 Iustin Pop
  """OptParsers custom converter for units.
512 65fe4693 Iustin Pop

513 65fe4693 Iustin Pop
  """
514 a8083063 Iustin Pop
  try:
515 a8083063 Iustin Pop
    return utils.ParseUnit(value)
516 a8083063 Iustin Pop
  except errors.UnitParseError, err:
517 3ecf6786 Iustin Pop
    raise OptionValueError("option %s: %s" % (opt, err))
518 a8083063 Iustin Pop
519 a8083063 Iustin Pop
520 a8469393 Iustin Pop
def _SplitKeyVal(opt, data):
521 a8469393 Iustin Pop
  """Convert a KeyVal string into a dict.
522 a8469393 Iustin Pop

523 a8469393 Iustin Pop
  This function will convert a key=val[,...] string into a dict. Empty
524 a8469393 Iustin Pop
  values will be converted specially: keys which have the prefix 'no_'
525 a8469393 Iustin Pop
  will have the value=False and the prefix stripped, the others will
526 a8469393 Iustin Pop
  have value=True.
527 a8469393 Iustin Pop

528 a8469393 Iustin Pop
  @type opt: string
529 a8469393 Iustin Pop
  @param opt: a string holding the option name for which we process the
530 a8469393 Iustin Pop
      data, used in building error messages
531 a8469393 Iustin Pop
  @type data: string
532 a8469393 Iustin Pop
  @param data: a string of the format key=val,key=val,...
533 a8469393 Iustin Pop
  @rtype: dict
534 a8469393 Iustin Pop
  @return: {key=val, key=val}
535 a8469393 Iustin Pop
  @raises errors.ParameterError: if there are duplicate keys
536 a8469393 Iustin Pop

537 a8469393 Iustin Pop
  """
538 a8469393 Iustin Pop
  kv_dict = {}
539 4f31882e Guido Trotter
  if data:
540 1b3a7656 Iustin Pop
    for elem in utils.UnescapeAndSplit(data, sep=","):
541 4f31882e Guido Trotter
      if "=" in elem:
542 4f31882e Guido Trotter
        key, val = elem.split("=", 1)
543 a8469393 Iustin Pop
      else:
544 4f31882e Guido Trotter
        if elem.startswith(NO_PREFIX):
545 4f31882e Guido Trotter
          key, val = elem[len(NO_PREFIX):], False
546 4f31882e Guido Trotter
        elif elem.startswith(UN_PREFIX):
547 4f31882e Guido Trotter
          key, val = elem[len(UN_PREFIX):], None
548 4f31882e Guido Trotter
        else:
549 4f31882e Guido Trotter
          key, val = elem, True
550 4f31882e Guido Trotter
      if key in kv_dict:
551 4f31882e Guido Trotter
        raise errors.ParameterError("Duplicate key '%s' in option %s" %
552 4f31882e Guido Trotter
                                    (key, opt))
553 4f31882e Guido Trotter
      kv_dict[key] = val
554 a8469393 Iustin Pop
  return kv_dict
555 a8469393 Iustin Pop
556 a8469393 Iustin Pop
557 b459a848 Andrea Spadaccini
def check_ident_key_val(option, opt, value):  # pylint: disable=W0613
558 552c8dff Michael Hanselmann
  """Custom parser for ident:key=val,key=val options.
559 552c8dff Michael Hanselmann

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

563 a8469393 Iustin Pop
  """
564 a8469393 Iustin Pop
  if ":" not in value:
565 d0c8c01d Iustin Pop
    ident, rest = value, ""
566 a8469393 Iustin Pop
  else:
567 a8469393 Iustin Pop
    ident, rest = value.split(":", 1)
568 8b46606c Guido Trotter
569 8b46606c Guido Trotter
  if ident.startswith(NO_PREFIX):
570 8b46606c Guido Trotter
    if rest:
571 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
572 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
573 8b46606c Guido Trotter
    retval = (ident[len(NO_PREFIX):], False)
574 956631b6 Michael Hanselmann
  elif (ident.startswith(UN_PREFIX) and
575 956631b6 Michael Hanselmann
        (len(ident) <= len(UN_PREFIX) or
576 956631b6 Michael Hanselmann
         not ident[len(UN_PREFIX)][0].isdigit())):
577 8b46606c Guido Trotter
    if rest:
578 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
579 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
580 8b46606c Guido Trotter
    retval = (ident[len(UN_PREFIX):], None)
581 8b46606c Guido Trotter
  else:
582 a8469393 Iustin Pop
    kv_dict = _SplitKeyVal(opt, rest)
583 a8469393 Iustin Pop
    retval = (ident, kv_dict)
584 a8469393 Iustin Pop
  return retval
585 a8469393 Iustin Pop
586 a8469393 Iustin Pop
587 b459a848 Andrea Spadaccini
def check_key_val(option, opt, value):  # pylint: disable=W0613
588 552c8dff Michael Hanselmann
  """Custom parser class for key=val,key=val options.
589 552c8dff Michael Hanselmann

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

592 a8469393 Iustin Pop
  """
593 a8469393 Iustin Pop
  return _SplitKeyVal(opt, value)
594 a8469393 Iustin Pop
595 a8469393 Iustin Pop
596 b459a848 Andrea Spadaccini
def check_bool(option, opt, value): # pylint: disable=W0613
597 e7b61bb0 Iustin Pop
  """Custom parser for yes/no options.
598 e7b61bb0 Iustin Pop

599 e7b61bb0 Iustin Pop
  This will store the parsed value as either True or False.
600 e7b61bb0 Iustin Pop

601 e7b61bb0 Iustin Pop
  """
602 e7b61bb0 Iustin Pop
  value = value.lower()
603 e7b61bb0 Iustin Pop
  if value == constants.VALUE_FALSE or value == "no":
604 e7b61bb0 Iustin Pop
    return False
605 e7b61bb0 Iustin Pop
  elif value == constants.VALUE_TRUE or value == "yes":
606 e7b61bb0 Iustin Pop
    return True
607 e7b61bb0 Iustin Pop
  else:
608 e7b61bb0 Iustin Pop
    raise errors.ParameterError("Invalid boolean value '%s'" % value)
609 e7b61bb0 Iustin Pop
610 e7b61bb0 Iustin Pop
611 499eb088 Iustin Pop
def check_list(option, opt, value): # pylint: disable=W0613
612 499eb088 Iustin Pop
  """Custom parser for comma-separated lists.
613 499eb088 Iustin Pop

614 499eb088 Iustin Pop
  """
615 499eb088 Iustin Pop
  # we have to make this explicit check since "".split(",") is [""],
616 499eb088 Iustin Pop
  # not an empty list :(
617 499eb088 Iustin Pop
  if not value:
618 499eb088 Iustin Pop
    return []
619 499eb088 Iustin Pop
  else:
620 499eb088 Iustin Pop
    return utils.UnescapeAndSplit(value)
621 499eb088 Iustin Pop
622 499eb088 Iustin Pop
623 cd415612 René Nussbaumer
def check_maybefloat(option, opt, value): # pylint: disable=W0613
624 cd415612 René Nussbaumer
  """Custom parser for float numbers which might be also defaults.
625 cd415612 René Nussbaumer

626 cd415612 René Nussbaumer
  """
627 cd415612 René Nussbaumer
  value = value.lower()
628 cd415612 René Nussbaumer
629 cd415612 René Nussbaumer
  if value == constants.VALUE_DEFAULT:
630 cd415612 René Nussbaumer
    return value
631 cd415612 René Nussbaumer
  else:
632 cd415612 René Nussbaumer
    return float(value)
633 cd415612 René Nussbaumer
634 cd415612 René Nussbaumer
635 63d44c55 Michael Hanselmann
# completion_suggestion is normally a list. Using numeric values not evaluating
636 63d44c55 Michael Hanselmann
# to False for dynamic completion.
637 63d44c55 Michael Hanselmann
(OPT_COMPL_MANY_NODES,
638 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_NODE,
639 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_INSTANCE,
640 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_OS,
641 2d3ed64b Michael Hanselmann
 OPT_COMPL_ONE_IALLOCATOR,
642 36e247e1 Guido Trotter
 OPT_COMPL_INST_ADD_NODES,
643 36e247e1 Guido Trotter
 OPT_COMPL_ONE_NODEGROUP) = range(100, 107)
644 63d44c55 Michael Hanselmann
645 63d44c55 Michael Hanselmann
OPT_COMPL_ALL = frozenset([
646 63d44c55 Michael Hanselmann
  OPT_COMPL_MANY_NODES,
647 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_NODE,
648 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_INSTANCE,
649 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_OS,
650 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_IALLOCATOR,
651 2d3ed64b Michael Hanselmann
  OPT_COMPL_INST_ADD_NODES,
652 36e247e1 Guido Trotter
  OPT_COMPL_ONE_NODEGROUP,
653 63d44c55 Michael Hanselmann
  ])
654 63d44c55 Michael Hanselmann
655 63d44c55 Michael Hanselmann
656 552c8dff Michael Hanselmann
class CliOption(Option):
657 552c8dff Michael Hanselmann
  """Custom option class for optparse.
658 a8469393 Iustin Pop

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

1486 d971402f Michael Hanselmann
  """
1487 d971402f Michael Hanselmann
  def __init__(self, exit_error):
1488 d971402f Michael Hanselmann
    """Initializes instances of this class.
1489 d971402f Michael Hanselmann

1490 d971402f Michael Hanselmann
    @type exit_error: bool
1491 d971402f Michael Hanselmann
    @param exit_error: Whether to report failure on exit
1492 d971402f Michael Hanselmann

1493 d971402f Michael Hanselmann
    """
1494 d971402f Michael Hanselmann
    Exception.__init__(self)
1495 d971402f Michael Hanselmann
    self.exit_error = exit_error
1496 d971402f Michael Hanselmann
1497 d971402f Michael Hanselmann
1498 d971402f Michael Hanselmann
class _ShowVersion(Exception):
1499 d971402f Michael Hanselmann
  """Exception class for L{_ParseArgs}.
1500 d971402f Michael Hanselmann

1501 d971402f Michael Hanselmann
  """
1502 d971402f Michael Hanselmann
1503 d971402f Michael Hanselmann
1504 d971402f Michael Hanselmann
def _ParseArgs(binary, argv, commands, aliases, env_override):
1505 c41eea6e Iustin Pop
  """Parser for the command line arguments.
1506 a8083063 Iustin Pop

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

1510 d971402f Michael Hanselmann
  @param binary: Script name
1511 d971402f Michael Hanselmann
  @param argv: Command line arguments
1512 d971402f Michael Hanselmann
  @param commands: Dictionary containing command definitions
1513 d971402f Michael Hanselmann
  @param aliases: dictionary with command aliases {"alias": "target", ...}
1514 ef9fa5b9 René Nussbaumer
  @param env_override: list of env variables allowed for default args
1515 d971402f Michael Hanselmann
  @raise _ShowUsage: If usage description should be shown
1516 d971402f Michael Hanselmann
  @raise _ShowVersion: If version should be shown
1517 098c0958 Michael Hanselmann

1518 a8083063 Iustin Pop
  """
1519 ef9fa5b9 René Nussbaumer
  assert not (env_override - set(commands))
1520 d971402f Michael Hanselmann
  assert not (set(aliases.keys()) & set(commands.keys()))
1521 ef9fa5b9 René Nussbaumer
1522 d971402f Michael Hanselmann
  if len(argv) > 1:
1523 d971402f Michael Hanselmann
    cmd = argv[1]
1524 a8083063 Iustin Pop
  else:
1525 d971402f Michael Hanselmann
    # No option or command given
1526 d971402f Michael Hanselmann
    raise _ShowUsage(exit_error=True)
1527 a8083063 Iustin Pop
1528 d971402f Michael Hanselmann
  if cmd == "--version":
1529 d971402f Michael Hanselmann
    raise _ShowVersion()
1530 d971402f Michael Hanselmann
  elif cmd == "--help":
1531 d971402f Michael Hanselmann
    raise _ShowUsage(exit_error=False)
1532 d971402f Michael Hanselmann
  elif not (cmd in commands or cmd in aliases):
1533 d971402f Michael Hanselmann
    raise _ShowUsage(exit_error=True)
1534 de47cf8f Guido Trotter
1535 de47cf8f Guido Trotter
  # get command, unalias it, and look it up in commands
1536 de47cf8f Guido Trotter
  if cmd in aliases:
1537 de47cf8f Guido Trotter
    if aliases[cmd] not in commands:
1538 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' maps to non-existing"
1539 de47cf8f Guido Trotter
                                   " command '%s'" % (cmd, aliases[cmd]))
1540 de47cf8f Guido Trotter
1541 de47cf8f Guido Trotter
    cmd = aliases[cmd]
1542 de47cf8f Guido Trotter
1543 ef9fa5b9 René Nussbaumer
  if cmd in env_override:
1544 ef9fa5b9 René Nussbaumer
    args_env_name = ("%s_%s" % (binary.replace("-", "_"), cmd)).upper()
1545 ef9fa5b9 René Nussbaumer
    env_args = os.environ.get(args_env_name)
1546 ef9fa5b9 René Nussbaumer
    if env_args:
1547 d971402f Michael Hanselmann
      argv = utils.InsertAtPos(argv, 2, shlex.split(env_args))
1548 ef9fa5b9 René Nussbaumer
1549 a8005e17 Michael Hanselmann
  func, args_def, parser_opts, usage, description = commands[cmd]
1550 bf5338b3 Michael Hanselmann
  parser = OptionParser(option_list=parser_opts + COMMON_OPTS,
1551 bf5338b3 Michael Hanselmann
                        description=description,
1552 bf5338b3 Michael Hanselmann
                        formatter=TitledHelpFormatter(),
1553 bf5338b3 Michael Hanselmann
                        usage="%%prog %s %s" % (cmd, usage))
1554 a8083063 Iustin Pop
  parser.disable_interspersed_args()
1555 d971402f Michael Hanselmann
  options, args = parser.parse_args(args=argv[2:])
1556 a8005e17 Michael Hanselmann
1557 a8005e17 Michael Hanselmann
  if not _CheckArguments(cmd, args_def, args):
1558 a8083063 Iustin Pop
    return None, None, None
1559 a8083063 Iustin Pop
1560 a8083063 Iustin Pop
  return func, options, args
1561 a8083063 Iustin Pop
1562 a8083063 Iustin Pop
1563 d971402f Michael Hanselmann
def _FormatUsage(binary, commands):
1564 d971402f Michael Hanselmann
  """Generates a nice description of all commands.
1565 d971402f Michael Hanselmann

1566 d971402f Michael Hanselmann
  @param binary: Script name
1567 d971402f Michael Hanselmann
  @param commands: Dictionary containing command definitions
1568 d971402f Michael Hanselmann

1569 d971402f Michael Hanselmann
  """
1570 d971402f Michael Hanselmann
  # compute the max line length for cmd + usage
1571 d971402f Michael Hanselmann
  mlen = min(60, max(map(len, commands)))
1572 d971402f Michael Hanselmann
1573 d971402f Michael Hanselmann
  yield "Usage: %s {command} [options...] [argument...]" % binary
1574 d971402f Michael Hanselmann
  yield "%s <command> --help to see details, or man %s" % (binary, binary)
1575 d971402f Michael Hanselmann
  yield ""
1576 d971402f Michael Hanselmann
  yield "Commands:"
1577 d971402f Michael Hanselmann
1578 d971402f Michael Hanselmann
  # and format a nice command list
1579 d971402f Michael Hanselmann
  for (cmd, (_, _, _, _, help_text)) in sorted(commands.items()):
1580 d971402f Michael Hanselmann
    help_lines = textwrap.wrap(help_text, 79 - 3 - mlen)
1581 d971402f Michael Hanselmann
    yield " %-*s - %s" % (mlen, cmd, help_lines.pop(0))
1582 d971402f Michael Hanselmann
    for line in help_lines:
1583 d971402f Michael Hanselmann
      yield " %-*s   %s" % (mlen, "", line)
1584 d971402f Michael Hanselmann
1585 d971402f Michael Hanselmann
  yield ""
1586 d971402f Michael Hanselmann
1587 d971402f Michael Hanselmann
1588 a8005e17 Michael Hanselmann
def _CheckArguments(cmd, args_def, args):
1589 a8005e17 Michael Hanselmann
  """Verifies the arguments using the argument definition.
1590 a8005e17 Michael Hanselmann

1591 a8005e17 Michael Hanselmann
  Algorithm:
1592 a8005e17 Michael Hanselmann

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

1595 a8005e17 Michael Hanselmann
    1. For each argument in definition
1596 a8005e17 Michael Hanselmann

1597 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
1598 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
1599 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
1600 a8005e17 Michael Hanselmann

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

1603 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
1604 a8005e17 Michael Hanselmann

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

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

1609 a8005e17 Michael Hanselmann
  """
1610 a8005e17 Michael Hanselmann
  if args and not args_def:
1611 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects no arguments", cmd)
1612 a8005e17 Michael Hanselmann
    return False
1613 a8005e17 Michael Hanselmann
1614 a8005e17 Michael Hanselmann
  min_count = None
1615 a8005e17 Michael Hanselmann
  max_count = None
1616 a8005e17 Michael Hanselmann
  check_max = None
1617 a8005e17 Michael Hanselmann
1618 a8005e17 Michael Hanselmann
  last_idx = len(args_def) - 1
1619 a8005e17 Michael Hanselmann
1620 a8005e17 Michael Hanselmann
  for idx, arg in enumerate(args_def):
1621 a8005e17 Michael Hanselmann
    if min_count is None:
1622 a8005e17 Michael Hanselmann
      min_count = arg.min
1623 a8005e17 Michael Hanselmann
    elif arg.min is not None:
1624 a8005e17 Michael Hanselmann
      min_count += arg.min
1625 a8005e17 Michael Hanselmann
1626 a8005e17 Michael Hanselmann
    if max_count is None:
1627 a8005e17 Michael Hanselmann
      max_count = arg.max
1628 a8005e17 Michael Hanselmann
    elif arg.max is not None:
1629 a8005e17 Michael Hanselmann
      max_count += arg.max
1630 a8005e17 Michael Hanselmann
1631 a8005e17 Michael Hanselmann
    if idx == last_idx:
1632 a8005e17 Michael Hanselmann
      check_max = (arg.max is not None)
1633 a8005e17 Michael Hanselmann
1634 a8005e17 Michael Hanselmann
    elif arg.max is None:
1635 a8005e17 Michael Hanselmann
      raise errors.ProgrammerError("Only the last argument can have max=None")
1636 a8005e17 Michael Hanselmann
1637 a8005e17 Michael Hanselmann
  if check_max:
1638 a8005e17 Michael Hanselmann
    # Command with exact number of arguments
1639 a8005e17 Michael Hanselmann
    if (min_count is not None and max_count is not None and
1640 a8005e17 Michael Hanselmann
        min_count == max_count and len(args) != min_count):
1641 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects %d argument(s)", cmd, min_count)
1642 a8005e17 Michael Hanselmann
      return False
1643 a8005e17 Michael Hanselmann
1644 a8005e17 Michael Hanselmann
    # Command with limited number of arguments
1645 a8005e17 Michael Hanselmann
    if max_count is not None and len(args) > max_count:
1646 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects only %d argument(s)",
1647 a8005e17 Michael Hanselmann
               cmd, max_count)
1648 a8005e17 Michael Hanselmann
      return False
1649 a8005e17 Michael Hanselmann
1650 a8005e17 Michael Hanselmann
  # Command with some required arguments
1651 a8005e17 Michael Hanselmann
  if min_count is not None and len(args) < min_count:
1652 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects at least %d argument(s)",
1653 a8005e17 Michael Hanselmann
             cmd, min_count)
1654 a8005e17 Michael Hanselmann
    return False
1655 a8005e17 Michael Hanselmann
1656 a8005e17 Michael Hanselmann
  return True
1657 a8005e17 Michael Hanselmann
1658 a8005e17 Michael Hanselmann
1659 60d49723 Michael Hanselmann
def SplitNodeOption(value):
1660 60d49723 Michael Hanselmann
  """Splits the value of a --node option.
1661 60d49723 Michael Hanselmann

1662 60d49723 Michael Hanselmann
  """
1663 d0c8c01d Iustin Pop
  if value and ":" in value:
1664 d0c8c01d Iustin Pop
    return value.split(":", 1)
1665 60d49723 Michael Hanselmann
  else:
1666 60d49723 Michael Hanselmann
    return (value, None)
1667 60d49723 Michael Hanselmann
1668 60d49723 Michael Hanselmann
1669 07150497 Guido Trotter
def CalculateOSNames(os_name, os_variants):
1670 07150497 Guido Trotter
  """Calculates all the names an OS can be called, according to its variants.
1671 07150497 Guido Trotter

1672 07150497 Guido Trotter
  @type os_name: string
1673 07150497 Guido Trotter
  @param os_name: base name of the os
1674 07150497 Guido Trotter
  @type os_variants: list or None
1675 07150497 Guido Trotter
  @param os_variants: list of supported variants
1676 07150497 Guido Trotter
  @rtype: list
1677 07150497 Guido Trotter
  @return: list of valid names
1678 07150497 Guido Trotter

1679 07150497 Guido Trotter
  """
1680 07150497 Guido Trotter
  if os_variants:
1681 d0c8c01d Iustin Pop
    return ["%s+%s" % (os_name, v) for v in os_variants]
1682 07150497 Guido Trotter
  else:
1683 07150497 Guido Trotter
    return [os_name]
1684 07150497 Guido Trotter
1685 07150497 Guido Trotter
1686 a4ebd726 Michael Hanselmann
def ParseFields(selected, default):
1687 a4ebd726 Michael Hanselmann
  """Parses the values of "--field"-like options.
1688 a4ebd726 Michael Hanselmann

1689 a4ebd726 Michael Hanselmann
  @type selected: string or None
1690 a4ebd726 Michael Hanselmann
  @param selected: User-selected options
1691 a4ebd726 Michael Hanselmann
  @type default: list
1692 a4ebd726 Michael Hanselmann
  @param default: Default fields
1693 a4ebd726 Michael Hanselmann

1694 a4ebd726 Michael Hanselmann
  """
1695 a4ebd726 Michael Hanselmann
  if selected is None:
1696 a4ebd726 Michael Hanselmann
    return default
1697 a4ebd726 Michael Hanselmann
1698 a4ebd726 Michael Hanselmann
  if selected.startswith("+"):
1699 a4ebd726 Michael Hanselmann
    return default + selected[1:].split(",")
1700 a4ebd726 Michael Hanselmann
1701 a4ebd726 Michael Hanselmann
  return selected.split(",")
1702 a4ebd726 Michael Hanselmann
1703 a4ebd726 Michael Hanselmann
1704 e0e916fe Iustin Pop
UsesRPC = rpc.RunWithRPC
1705 4331f6cd Michael Hanselmann
1706 4331f6cd Michael Hanselmann
1707 47988778 Iustin Pop
def AskUser(text, choices=None):
1708 47988778 Iustin Pop
  """Ask the user a question.
1709 a8083063 Iustin Pop

1710 c41eea6e Iustin Pop
  @param text: the question to ask
1711 a8083063 Iustin Pop

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

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

1721 a8083063 Iustin Pop
  """
1722 47988778 Iustin Pop
  if choices is None:
1723 d0c8c01d Iustin Pop
    choices = [("y", True, "Perform the operation"),
1724 d0c8c01d Iustin Pop
               ("n", False, "Do not perform the operation")]
1725 47988778 Iustin Pop
  if not choices or not isinstance(choices, list):
1726 5bbd3f7f Michael Hanselmann
    raise errors.ProgrammerError("Invalid choices argument to AskUser")
1727 47988778 Iustin Pop
  for entry in choices:
1728 d0c8c01d Iustin Pop
    if not isinstance(entry, tuple) or len(entry) < 3 or entry[0] == "?":
1729 5bbd3f7f Michael Hanselmann
      raise errors.ProgrammerError("Invalid choices element to AskUser")
1730 47988778 Iustin Pop
1731 47988778 Iustin Pop
  answer = choices[-1][1]
1732 47988778 Iustin Pop
  new_text = []
1733 47988778 Iustin Pop
  for line in text.splitlines():
1734 47988778 Iustin Pop
    new_text.append(textwrap.fill(line, 70, replace_whitespace=False))
1735 47988778 Iustin Pop
  text = "\n".join(new_text)
1736 a8083063 Iustin Pop
  try:
1737 3023170f Iustin Pop
    f = file("/dev/tty", "a+")
1738 a8083063 Iustin Pop
  except IOError:
1739 47988778 Iustin Pop
    return answer
1740 a8083063 Iustin Pop
  try:
1741 47988778 Iustin Pop
    chars = [entry[0] for entry in choices]
1742 47988778 Iustin Pop
    chars[-1] = "[%s]" % chars[-1]
1743 d0c8c01d Iustin Pop
    chars.append("?")
1744 47988778 Iustin Pop
    maps = dict([(entry[0], entry[1]) for entry in choices])
1745 47988778 Iustin Pop
    while True:
1746 47988778 Iustin Pop
      f.write(text)
1747 d0c8c01d Iustin Pop
      f.write("\n")
1748 47988778 Iustin Pop
      f.write("/".join(chars))
1749 47988778 Iustin Pop
      f.write(": ")
1750 47988778 Iustin Pop
      line = f.readline(2).strip().lower()
1751 47988778 Iustin Pop
      if line in maps:
1752 47988778 Iustin Pop
        answer = maps[line]
1753 47988778 Iustin Pop
        break
1754 d0c8c01d Iustin Pop
      elif line == "?":
1755 47988778 Iustin Pop
        for entry in choices:
1756 47988778 Iustin Pop
          f.write(" %s - %s\n" % (entry[0], entry[2]))
1757 47988778 Iustin Pop
        f.write("\n")
1758 47988778 Iustin Pop
        continue
1759 a8083063 Iustin Pop
  finally:
1760 a8083063 Iustin Pop
    f.close()
1761 a8083063 Iustin Pop
  return answer
1762 a8083063 Iustin Pop
1763 a8083063 Iustin Pop
1764 e9d741b6 Iustin Pop
class JobSubmittedException(Exception):
1765 e9d741b6 Iustin Pop
  """Job was submitted, client should exit.
1766 e9d741b6 Iustin Pop

1767 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1768 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1769 e9d741b6 Iustin Pop

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

1772 e9d741b6 Iustin Pop
  """
1773 e9d741b6 Iustin Pop
1774 e9d741b6 Iustin Pop
1775 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1776 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1777 a8083063 Iustin Pop

1778 0a1e74d9 Iustin Pop
  @type ops: list
1779 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1780 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1781 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1782 0a1e74d9 Iustin Pop
             if None, a new client will be created
1783 a8083063 Iustin Pop

1784 a8083063 Iustin Pop
  """
1785 e2212007 Iustin Pop
  if cl is None:
1786 b33e986b Iustin Pop
    cl = GetClient()
1787 685ee993 Iustin Pop
1788 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1789 0a1e74d9 Iustin Pop
1790 0a1e74d9 Iustin Pop
  return job_id
1791 0a1e74d9 Iustin Pop
1792 0a1e74d9 Iustin Pop
1793 4e338533 Michael Hanselmann
def GenericPollJob(job_id, cbs, report_cbs):
1794 4e338533 Michael Hanselmann
  """Generic job-polling function.
1795 0a1e74d9 Iustin Pop

1796 4e338533 Michael Hanselmann
  @type job_id: number
1797 4e338533 Michael Hanselmann
  @param job_id: Job ID
1798 4e338533 Michael Hanselmann
  @type cbs: Instance of L{JobPollCbBase}
1799 4e338533 Michael Hanselmann
  @param cbs: Data callbacks
1800 4e338533 Michael Hanselmann
  @type report_cbs: Instance of L{JobPollReportCbBase}
1801 4e338533 Michael Hanselmann
  @param report_cbs: Reporting callbacks
1802 0a1e74d9 Iustin Pop

1803 0a1e74d9 Iustin Pop
  """
1804 6c5a7090 Michael Hanselmann
  prev_job_info = None
1805 6c5a7090 Michael Hanselmann
  prev_logmsg_serial = None
1806 6c5a7090 Michael Hanselmann
1807 f4484122 Michael Hanselmann
  status = None
1808 f4484122 Michael Hanselmann
1809 685ee993 Iustin Pop
  while True:
1810 4e338533 Michael Hanselmann
    result = cbs.WaitForJobChangeOnce(job_id, ["status"], prev_job_info,
1811 4e338533 Michael Hanselmann
                                      prev_logmsg_serial)
1812 6c5a7090 Michael Hanselmann
    if not result:
1813 685ee993 Iustin Pop
      # job not found, go away!
1814 0bbe448c Michael Hanselmann
      raise errors.JobLost("Job with id %s lost" % job_id)
1815 4e338533 Michael Hanselmann
1816 4e338533 Michael Hanselmann
    if result == constants.JOB_NOTCHANGED:
1817 4e338533 Michael Hanselmann
      report_cbs.ReportNotChanged(job_id, status)
1818 f4484122 Michael Hanselmann
1819 f4484122 Michael Hanselmann
      # Wait again
1820 f4484122 Michael Hanselmann
      continue
1821 685ee993 Iustin Pop
1822 6c5a7090 Michael Hanselmann
    # Split result, a tuple of (field values, log entries)
1823 6c5a7090 Michael Hanselmann
    (job_info, log_entries) = result
1824 6c5a7090 Michael Hanselmann
    (status, ) = job_info
1825 6c5a7090 Michael Hanselmann
1826 6c5a7090 Michael Hanselmann
    if log_entries:
1827 6c5a7090 Michael Hanselmann
      for log_entry in log_entries:
1828 4e338533 Michael Hanselmann
        (serial, timestamp, log_type, message) = log_entry
1829 4e338533 Michael Hanselmann
        report_cbs.ReportLogMessage(job_id, serial, timestamp,
1830 4e338533 Michael Hanselmann
                                    log_type, message)
1831 6c5a7090 Michael Hanselmann
        prev_logmsg_serial = max(prev_logmsg_serial, serial)
1832 6c5a7090 Michael Hanselmann
1833 0bbe448c Michael Hanselmann
    # TODO: Handle canceled and archived jobs
1834 fbf0262f Michael Hanselmann
    elif status in (constants.JOB_STATUS_SUCCESS,
1835 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_ERROR,
1836 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELING,
1837 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELED):
1838 685ee993 Iustin Pop
      break
1839 6c5a7090 Michael Hanselmann
1840 6c5a7090 Michael Hanselmann
    prev_job_info = job_info
1841 685ee993 Iustin Pop
1842 4e338533 Michael Hanselmann
  jobs = cbs.QueryJobs([job_id], ["status", "opstatus", "opresult"])
1843 0bbe448c Michael Hanselmann
  if not jobs:
1844 0bbe448c Michael Hanselmann
    raise errors.JobLost("Job with id %s lost" % job_id)
1845 685ee993 Iustin Pop
1846 0e050889 Iustin Pop
  status, opstatus, result = jobs[0]
1847 4e338533 Michael Hanselmann
1848 0bbe448c Michael Hanselmann
  if status == constants.JOB_STATUS_SUCCESS:
1849 53c04d04 Iustin Pop
    return result
1850 4e338533 Michael Hanselmann
1851 4e338533 Michael Hanselmann
  if status in (constants.JOB_STATUS_CANCELING, constants.JOB_STATUS_CANCELED):
1852 fbf0262f Michael Hanselmann
    raise errors.OpExecError("Job was canceled")
1853 4e338533 Michael Hanselmann
1854 4e338533 Michael Hanselmann
  has_ok = False
1855 4e338533 Michael Hanselmann
  for idx, (status, msg) in enumerate(zip(opstatus, result)):
1856 4e338533 Michael Hanselmann
    if status == constants.OP_STATUS_SUCCESS:
1857 4e338533 Michael Hanselmann
      has_ok = True
1858 4e338533 Michael Hanselmann
    elif status == constants.OP_STATUS_ERROR:
1859 4e338533 Michael Hanselmann
      errors.MaybeRaise(msg)
1860 4e338533 Michael Hanselmann
1861 4e338533 Michael Hanselmann
      if has_ok:
1862 4e338533 Michael Hanselmann
        raise errors.OpExecError("partial failure (opcode %d): %s" %
1863 4e338533 Michael Hanselmann
                                 (idx, msg))
1864 4e338533 Michael Hanselmann
1865 4e338533 Michael Hanselmann
      raise errors.OpExecError(str(msg))
1866 4e338533 Michael Hanselmann
1867 4e338533 Michael Hanselmann
  # default failure mode
1868 4e338533 Michael Hanselmann
  raise errors.OpExecError(result)
1869 4e338533 Michael Hanselmann
1870 4e338533 Michael Hanselmann
1871 4e338533 Michael Hanselmann
class JobPollCbBase:
1872 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} callbacks.
1873 4e338533 Michael Hanselmann

1874 4e338533 Michael Hanselmann
  """
1875 4e338533 Michael Hanselmann
  def __init__(self):
1876 4e338533 Michael Hanselmann
    """Initializes this class.
1877 4e338533 Michael Hanselmann

1878 4e338533 Michael Hanselmann
    """
1879 4e338533 Michael Hanselmann
1880 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1881 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1882 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1883 4e338533 Michael Hanselmann

1884 4e338533 Michael Hanselmann
    """
1885 4e338533 Michael Hanselmann
    raise NotImplementedError()
1886 4e338533 Michael Hanselmann
1887 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1888 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1889 4e338533 Michael Hanselmann

1890 4e338533 Michael Hanselmann
    @type job_ids: list of numbers
1891 4e338533 Michael Hanselmann
    @param job_ids: Job IDs
1892 4e338533 Michael Hanselmann
    @type fields: list of strings
1893 4e338533 Michael Hanselmann
    @param fields: Fields
1894 4e338533 Michael Hanselmann

1895 4e338533 Michael Hanselmann
    """
1896 4e338533 Michael Hanselmann
    raise NotImplementedError()
1897 4e338533 Michael Hanselmann
1898 4e338533 Michael Hanselmann
1899 4e338533 Michael Hanselmann
class JobPollReportCbBase:
1900 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} reporting callbacks.
1901 4e338533 Michael Hanselmann

1902 4e338533 Michael Hanselmann
  """
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
1908 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1909 4e338533 Michael Hanselmann
    """Handles a log message.
1910 4e338533 Michael Hanselmann

1911 4e338533 Michael Hanselmann
    """
1912 4e338533 Michael Hanselmann
    raise NotImplementedError()
1913 4e338533 Michael Hanselmann
1914 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1915 4e338533 Michael Hanselmann
    """Called for if a job hasn't changed in a while.
1916 4e338533 Michael Hanselmann

1917 4e338533 Michael Hanselmann
    @type job_id: number
1918 4e338533 Michael Hanselmann
    @param job_id: Job ID
1919 4e338533 Michael Hanselmann
    @type status: string or None
1920 4e338533 Michael Hanselmann
    @param status: Job status if available
1921 4e338533 Michael Hanselmann

1922 4e338533 Michael Hanselmann
    """
1923 4e338533 Michael Hanselmann
    raise NotImplementedError()
1924 4e338533 Michael Hanselmann
1925 4e338533 Michael Hanselmann
1926 4e338533 Michael Hanselmann
class _LuxiJobPollCb(JobPollCbBase):
1927 4e338533 Michael Hanselmann
  def __init__(self, cl):
1928 4e338533 Michael Hanselmann
    """Initializes this class.
1929 4e338533 Michael Hanselmann

1930 4e338533 Michael Hanselmann
    """
1931 4e338533 Michael Hanselmann
    JobPollCbBase.__init__(self)
1932 4e338533 Michael Hanselmann
    self.cl = cl
1933 4e338533 Michael Hanselmann
1934 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1935 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1936 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1937 4e338533 Michael Hanselmann

1938 4e338533 Michael Hanselmann
    """
1939 4e338533 Michael Hanselmann
    return self.cl.WaitForJobChangeOnce(job_id, fields,
1940 4e338533 Michael Hanselmann
                                        prev_job_info, prev_log_serial)
1941 4e338533 Michael Hanselmann
1942 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1943 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1944 4e338533 Michael Hanselmann

1945 4e338533 Michael Hanselmann
    """
1946 4e338533 Michael Hanselmann
    return self.cl.QueryJobs(job_ids, fields)
1947 4e338533 Michael Hanselmann
1948 4e338533 Michael Hanselmann
1949 4e338533 Michael Hanselmann
class FeedbackFnJobPollReportCb(JobPollReportCbBase):
1950 4e338533 Michael Hanselmann
  def __init__(self, feedback_fn):
1951 4e338533 Michael Hanselmann
    """Initializes this class.
1952 4e338533 Michael Hanselmann

1953 4e338533 Michael Hanselmann
    """
1954 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1955 4e338533 Michael Hanselmann
1956 4e338533 Michael Hanselmann
    self.feedback_fn = feedback_fn
1957 4e338533 Michael Hanselmann
1958 4e338533 Michael Hanselmann
    assert callable(feedback_fn)
1959 4e338533 Michael Hanselmann
1960 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1961 4e338533 Michael Hanselmann
    """Handles a log message.
1962 4e338533 Michael Hanselmann

1963 4e338533 Michael Hanselmann
    """
1964 4e338533 Michael Hanselmann
    self.feedback_fn((timestamp, log_type, log_msg))
1965 4e338533 Michael Hanselmann
1966 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1967 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1968 4e338533 Michael Hanselmann

1969 4e338533 Michael Hanselmann
    """
1970 4e338533 Michael Hanselmann
    # Ignore
1971 4e338533 Michael Hanselmann
1972 4e338533 Michael Hanselmann
1973 4e338533 Michael Hanselmann
class StdioJobPollReportCb(JobPollReportCbBase):
1974 4e338533 Michael Hanselmann
  def __init__(self):
1975 4e338533 Michael Hanselmann
    """Initializes this class.
1976 4e338533 Michael Hanselmann

1977 4e338533 Michael Hanselmann
    """
1978 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1979 4e338533 Michael Hanselmann
1980 4e338533 Michael Hanselmann
    self.notified_queued = False
1981 4e338533 Michael Hanselmann
    self.notified_waitlock = False
1982 4e338533 Michael Hanselmann
1983 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1984 4e338533 Michael Hanselmann
    """Handles a log message.
1985 4e338533 Michael Hanselmann

1986 4e338533 Michael Hanselmann
    """
1987 4e338533 Michael Hanselmann
    ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)),
1988 8a7f1c61 Michael Hanselmann
             FormatLogMessage(log_type, log_msg))
1989 4e338533 Michael Hanselmann
1990 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1991 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1992 4e338533 Michael Hanselmann

1993 4e338533 Michael Hanselmann
    """
1994 4e338533 Michael Hanselmann
    if status is None:
1995 4e338533 Michael Hanselmann
      return
1996 4e338533 Michael Hanselmann
1997 4e338533 Michael Hanselmann
    if status == constants.JOB_STATUS_QUEUED and not self.notified_queued:
1998 4e338533 Michael Hanselmann
      ToStderr("Job %s is waiting in queue", job_id)
1999 4e338533 Michael Hanselmann
      self.notified_queued = True
2000 4e338533 Michael Hanselmann
2001 47099cd1 Michael Hanselmann
    elif status == constants.JOB_STATUS_WAITING and not self.notified_waitlock:
2002 4e338533 Michael Hanselmann
      ToStderr("Job %s is trying to acquire all necessary locks", job_id)
2003 4e338533 Michael Hanselmann
      self.notified_waitlock = True
2004 4e338533 Michael Hanselmann
2005 4e338533 Michael Hanselmann
2006 8a7f1c61 Michael Hanselmann
def FormatLogMessage(log_type, log_msg):
2007 8a7f1c61 Michael Hanselmann
  """Formats a job message according to its type.
2008 8a7f1c61 Michael Hanselmann

2009 8a7f1c61 Michael Hanselmann
  """
2010 8a7f1c61 Michael Hanselmann
  if log_type != constants.ELOG_MESSAGE:
2011 8a7f1c61 Michael Hanselmann
    log_msg = str(log_msg)
2012 8a7f1c61 Michael Hanselmann
2013 8a7f1c61 Michael Hanselmann
  return utils.SafeEncode(log_msg)
2014 8a7f1c61 Michael Hanselmann
2015 8a7f1c61 Michael Hanselmann
2016 583163a6 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None, reporter=None):
2017 4e338533 Michael Hanselmann
  """Function to poll for the result of a job.
2018 4e338533 Michael Hanselmann

2019 4e338533 Michael Hanselmann
  @type job_id: job identified
2020 4e338533 Michael Hanselmann
  @param job_id: the job to poll for results
2021 4e338533 Michael Hanselmann
  @type cl: luxi.Client
2022 4e338533 Michael Hanselmann
  @param cl: the luxi client to use for communicating with the master;
2023 4e338533 Michael Hanselmann
             if None, a new client will be created
2024 4e338533 Michael Hanselmann

2025 4e338533 Michael Hanselmann
  """
2026 4e338533 Michael Hanselmann
  if cl is None:
2027 4e338533 Michael Hanselmann
    cl = GetClient()
2028 4e338533 Michael Hanselmann
2029 583163a6 Michael Hanselmann
  if reporter is None:
2030 583163a6 Michael Hanselmann
    if feedback_fn:
2031 583163a6 Michael Hanselmann
      reporter = FeedbackFnJobPollReportCb(feedback_fn)
2032 583163a6 Michael Hanselmann
    else:
2033 583163a6 Michael Hanselmann
      reporter = StdioJobPollReportCb()
2034 583163a6 Michael Hanselmann
  elif feedback_fn:
2035 583163a6 Michael Hanselmann
    raise errors.ProgrammerError("Can't specify reporter and feedback function")
2036 4e338533 Michael Hanselmann
2037 4e338533 Michael Hanselmann
  return GenericPollJob(job_id, _LuxiJobPollCb(cl), reporter)
2038 ceab32dd Iustin Pop
2039 ceab32dd Iustin Pop
2040 583163a6 Michael Hanselmann
def SubmitOpCode(op, cl=None, feedback_fn=None, opts=None, reporter=None):
2041 0a1e74d9 Iustin Pop
  """Legacy function to submit an opcode.
2042 0a1e74d9 Iustin Pop

2043 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
2044 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
2045 0a1e74d9 Iustin Pop
  interaction functions.
2046 0a1e74d9 Iustin Pop

2047 0a1e74d9 Iustin Pop
  """
2048 0a1e74d9 Iustin Pop
  if cl is None:
2049 0a1e74d9 Iustin Pop
    cl = GetClient()
2050 0a1e74d9 Iustin Pop
2051 293ba2d8 Iustin Pop
  SetGenericOpcodeOpts([op], opts)
2052 293ba2d8 Iustin Pop
2053 5d297d8a Michael Hanselmann
  job_id = SendJob([op], cl=cl)
2054 0a1e74d9 Iustin Pop
2055 583163a6 Michael Hanselmann
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn,
2056 583163a6 Michael Hanselmann
                       reporter=reporter)
2057 53c04d04 Iustin Pop
2058 53c04d04 Iustin Pop
  return op_results[0]
2059 0a1e74d9 Iustin Pop
2060 0a1e74d9 Iustin Pop
2061 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
2062 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
2063 94428652 Iustin Pop

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

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

2072 94428652 Iustin Pop
  """
2073 94428652 Iustin Pop
  if opts and opts.submit_only:
2074 293ba2d8 Iustin Pop
    job = [op]
2075 293ba2d8 Iustin Pop
    SetGenericOpcodeOpts(job, opts)
2076 293ba2d8 Iustin Pop
    job_id = SendJob(job, cl=cl)
2077 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
2078 94428652 Iustin Pop
  else:
2079 293ba2d8 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
2080 293ba2d8 Iustin Pop
2081 293ba2d8 Iustin Pop
2082 293ba2d8 Iustin Pop
def SetGenericOpcodeOpts(opcode_list, options):
2083 293ba2d8 Iustin Pop
  """Processor for generic options.
2084 293ba2d8 Iustin Pop

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

2088 293ba2d8 Iustin Pop
  @param opcode_list: list of opcodes
2089 293ba2d8 Iustin Pop
  @param options: command line options or None
2090 293ba2d8 Iustin Pop
  @return: None (in-place modification)
2091 293ba2d8 Iustin Pop

2092 293ba2d8 Iustin Pop
  """
2093 293ba2d8 Iustin Pop
  if not options:
2094 293ba2d8 Iustin Pop
    return
2095 293ba2d8 Iustin Pop
  for op in opcode_list:
2096 aa06f8c6 Michael Hanselmann
    op.debug_level = options.debug
2097 a0a6ff34 Iustin Pop
    if hasattr(options, "dry_run"):
2098 a0a6ff34 Iustin Pop
      op.dry_run = options.dry_run
2099 aa06f8c6 Michael Hanselmann
    if getattr(options, "priority", None) is not None:
2100 aa06f8c6 Michael Hanselmann
      op.priority = _PRIONAME_TO_VALUE[options.priority]
2101 94428652 Iustin Pop
2102 94428652 Iustin Pop
2103 42ab9ac4 Iustin Pop
def GetClient(query=False):
2104 42ab9ac4 Iustin Pop
  """Connects to the a luxi socket and returns a client.
2105 42ab9ac4 Iustin Pop

2106 42ab9ac4 Iustin Pop
  @type query: boolean
2107 42ab9ac4 Iustin Pop
  @param query: this signifies that the client will only be
2108 42ab9ac4 Iustin Pop
      used for queries; if the build-time parameter
2109 42ab9ac4 Iustin Pop
      enable-split-queries is enabled, then the client will be
2110 42ab9ac4 Iustin Pop
      connected to the query socket instead of the masterd socket
2111 42ab9ac4 Iustin Pop

2112 42ab9ac4 Iustin Pop
  """
2113 42ab9ac4 Iustin Pop
  if query and constants.ENABLE_SPLIT_QUERY:
2114 ee4a14c0 Michael Hanselmann
    address = pathutils.QUERY_SOCKET
2115 42ab9ac4 Iustin Pop
  else:
2116 42ab9ac4 Iustin Pop
    address = None
2117 af30b2fd Michael Hanselmann
  # TODO: Cache object?
2118 b33e986b Iustin Pop
  try:
2119 42ab9ac4 Iustin Pop
    client = luxi.Client(address=address)
2120 b33e986b Iustin Pop
  except luxi.NoMasterError:
2121 d9a51679 Michael Hanselmann
    ss = ssconf.SimpleStore()
2122 d9a51679 Michael Hanselmann
2123 d9a51679 Michael Hanselmann
    # Try to read ssconf file
2124 d9a51679 Michael Hanselmann
    try:
2125 d9a51679 Michael Hanselmann
      ss.GetMasterNode()
2126 d9a51679 Michael Hanselmann
    except errors.ConfigurationError:
2127 d9a51679 Michael Hanselmann
      raise errors.OpPrereqError("Cluster not initialized or this machine is"
2128 2cfbc784 Iustin Pop
                                 " not part of a cluster",
2129 2cfbc784 Iustin Pop
                                 errors.ECODE_INVAL)
2130 d9a51679 Michael Hanselmann
2131 d9a51679 Michael Hanselmann
    master, myself = ssconf.GetMasterAndMyself(ss=ss)
2132 b33e986b Iustin Pop
    if master != myself:
2133 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
2134 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
2135 2cfbc784 Iustin Pop
                                 master, errors.ECODE_INVAL)
2136 d9a51679 Michael Hanselmann
    raise
2137 b33e986b Iustin Pop
  return client
2138 af30b2fd Michael Hanselmann
2139 af30b2fd Michael Hanselmann
2140 73702ee7 Iustin Pop
def FormatError(err):
2141 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
2142 73702ee7 Iustin Pop

2143 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
2144 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
2145 73702ee7 Iustin Pop
  second, a string describing the error message (not
2146 73702ee7 Iustin Pop
  newline-terminated).
2147 73702ee7 Iustin Pop

2148 73702ee7 Iustin Pop
  """
2149 73702ee7 Iustin Pop
  retcode = 1
2150 73702ee7 Iustin Pop
  obuf = StringIO()
2151 e2e521d0 Iustin Pop
  msg = str(err)
2152 73702ee7 Iustin Pop
  if isinstance(err, errors.ConfigurationError):
2153 e2e521d0 Iustin Pop
    txt = "Corrupt configuration file: %s" % msg
2154 46fbdd04 Iustin Pop
    logging.error(txt)
2155 e2e521d0 Iustin Pop
    obuf.write(txt + "\n")
2156 73702ee7 Iustin Pop
    obuf.write("Aborting.")
2157 73702ee7 Iustin Pop
    retcode = 2
2158 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksAbort):
2159 73702ee7 Iustin Pop
    obuf.write("Failure: hooks execution failed:\n")
2160 73702ee7 Iustin Pop
    for node, script, out in err.args[0]:
2161 73702ee7 Iustin Pop
      if out:
2162 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s, output: %s\n" %
2163 73702ee7 Iustin Pop
                   (node, script, out))
2164 73702ee7 Iustin Pop
      else:
2165 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s (no output)\n" %
2166 73702ee7 Iustin Pop
                   (node, script))
2167 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksFailure):
2168 e2e521d0 Iustin Pop
    obuf.write("Failure: hooks general failure: %s" % msg)
2169 73702ee7 Iustin Pop
  elif isinstance(err, errors.ResolverError):
2170 b705c7a6 Manuel Franceschini
    this_host = netutils.Hostname.GetSysName()
2171 73702ee7 Iustin Pop
    if err.args[0] == this_host:
2172 73702ee7 Iustin Pop
      msg = "Failure: can't resolve my own hostname ('%s')"
2173 73702ee7 Iustin Pop
    else:
2174 73702ee7 Iustin Pop
      msg = "Failure: can't resolve hostname '%s'"
2175 73702ee7 Iustin Pop
    obuf.write(msg % err.args[0])
2176 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpPrereqError):
2177 5c983ee5 Iustin Pop
    if len(err.args) == 2:
2178 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
2179 5ae4945a Iustin Pop
                 " operation:\nerror type: %s, error details:\n%s" %
2180 5c983ee5 Iustin Pop
                 (err.args[1], err.args[0]))
2181 5c983ee5 Iustin Pop
    else:
2182 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
2183 5c983ee5 Iustin Pop
                 " operation:\n%s" % msg)
2184 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpExecError):
2185 e2e521d0 Iustin Pop
    obuf.write("Failure: command execution error:\n%s" % msg)
2186 73702ee7 Iustin Pop
  elif isinstance(err, errors.TagError):
2187 e2e521d0 Iustin Pop
    obuf.write("Failure: invalid tag(s) given:\n%s" % msg)
2188 686d7433 Iustin Pop
  elif isinstance(err, errors.JobQueueDrainError):
2189 686d7433 Iustin Pop
    obuf.write("Failure: the job queue is marked for drain and doesn't"
2190 686d7433 Iustin Pop
               " accept new requests\n")
2191 f87b405e Michael Hanselmann
  elif isinstance(err, errors.JobQueueFull):
2192 f87b405e Michael Hanselmann
    obuf.write("Failure: the job queue is full and doesn't accept new"
2193 f87b405e Michael Hanselmann
               " job submissions until old jobs are archived\n")
2194 a5728081 Guido Trotter
  elif isinstance(err, errors.TypeEnforcementError):
2195 a5728081 Guido Trotter
    obuf.write("Parameter Error: %s" % msg)
2196 c1ce76bb Iustin Pop
  elif isinstance(err, errors.ParameterError):
2197 c1ce76bb Iustin Pop
    obuf.write("Failure: unknown/wrong parameter name '%s'" % msg)
2198 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.NoMasterError):
2199 03a8dbdc Iustin Pop
    obuf.write("Cannot communicate with the master daemon.\nIs it running"
2200 082c5adb Michael Hanselmann
               " and listening for connections?")
2201 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.TimeoutError):
2202 cd4c86a8 Michael Hanselmann
    obuf.write("Timeout while talking to the master daemon. Jobs might have"
2203 cd4c86a8 Michael Hanselmann
               " been submitted and will continue to run even if the call"
2204 cd4c86a8 Michael Hanselmann
               " timed out. Useful commands in this situation are \"gnt-job"
2205 cd4c86a8 Michael Hanselmann
               " list\", \"gnt-job cancel\" and \"gnt-job watch\". Error:\n")
2206 cd4c86a8 Michael Hanselmann
    obuf.write(msg)
2207 5a1c22fe Iustin Pop
  elif isinstance(err, luxi.PermissionError):
2208 5a1c22fe Iustin Pop
    obuf.write("It seems you don't have permissions to connect to the"
2209 5a1c22fe Iustin Pop
               " master daemon.\nPlease retry as a different user.")
2210 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.ProtocolError):
2211 03a8dbdc Iustin Pop
    obuf.write("Unhandled protocol error while talking to the master daemon:\n"
2212 03a8dbdc Iustin Pop
               "%s" % msg)
2213 91c622a8 Iustin Pop
  elif isinstance(err, errors.JobLost):
2214 91c622a8 Iustin Pop
    obuf.write("Error checking job status: %s" % msg)
2215 cb1e6c3c Michael Hanselmann
  elif isinstance(err, errors.QueryFilterParseError):
2216 cb1e6c3c Michael Hanselmann
    obuf.write("Error while parsing query filter: %s\n" % err.args[0])
2217 cb1e6c3c Michael Hanselmann
    obuf.write("\n".join(err.GetDetails()))
2218 797506fc Michael Hanselmann
  elif isinstance(err, errors.GenericError):
2219 797506fc Michael Hanselmann
    obuf.write("Unhandled Ganeti error: %s" % msg)
2220 e9d741b6 Iustin Pop
  elif isinstance(err, JobSubmittedException):
2221 e9d741b6 Iustin Pop
    obuf.write("JobID: %s\n" % err.args[0])
2222 e9d741b6 Iustin Pop
    retcode = 0
2223 73702ee7 Iustin Pop
  else:
2224 e2e521d0 Iustin Pop
    obuf.write("Unhandled exception: %s" % msg)
2225 d0c8c01d Iustin Pop
  return retcode, obuf.getvalue().rstrip("\n")
2226 73702ee7 Iustin Pop
2227 73702ee7 Iustin Pop
2228 ef9fa5b9 René Nussbaumer
def GenericMain(commands, override=None, aliases=None,
2229 ef9fa5b9 René Nussbaumer
                env_override=frozenset()):
2230 a8083063 Iustin Pop
  """Generic main function for all the gnt-* commands.
2231 a8083063 Iustin Pop

2232 ef9fa5b9 René Nussbaumer
  @param commands: a dictionary with a special structure, see the design doc
2233 ef9fa5b9 René Nussbaumer
                   for command line handling.
2234 ef9fa5b9 René Nussbaumer
  @param override: if not None, we expect a dictionary with keys that will
2235 ef9fa5b9 René Nussbaumer
                   override command line options; this can be used to pass
2236 ef9fa5b9 René Nussbaumer
                   options from the scripts to generic functions
2237 ef9fa5b9 René Nussbaumer
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
2238 ef9fa5b9 René Nussbaumer
  @param env_override: list of environment names which are allowed to submit
2239 ef9fa5b9 René Nussbaumer
                       default args for commands
2240 a8083063 Iustin Pop

2241 a8083063 Iustin Pop
  """
2242 a8083063 Iustin Pop
  # save the program name and the entire command line for later logging
2243 a8083063 Iustin Pop
  if sys.argv:
2244 c1f19851 Michael Hanselmann
    binary = os.path.basename(sys.argv[0])
2245 c1f19851 Michael Hanselmann
    if not binary:
2246 c1f19851 Michael Hanselmann
      binary = sys.argv[0]
2247 c1f19851 Michael Hanselmann
2248 a8083063 Iustin Pop
    if len(sys.argv) >= 2:
2249 c1f19851 Michael Hanselmann
      logname = utils.ShellQuoteArgs([binary, sys.argv[1]])
2250 a8083063 Iustin Pop
    else:
2251 c1f19851 Michael Hanselmann
      logname = binary
2252 c1f19851 Michael Hanselmann
2253 c1f19851 Michael Hanselmann
    cmdline = utils.ShellQuoteArgs([binary] + sys.argv[1:])
2254 a8083063 Iustin Pop
  else:
2255 a8083063 Iustin Pop
    binary = "<unknown program>"
2256 c1f19851 Michael Hanselmann
    cmdline = "<unknown>"
2257 a8083063 Iustin Pop
2258 de47cf8f Guido Trotter
  if aliases is None:
2259 de47cf8f Guido Trotter
    aliases = {}
2260 de47cf8f Guido Trotter
2261 3126878d Guido Trotter
  try:
2262 d971402f Michael Hanselmann
    (func, options, args) = _ParseArgs(binary, sys.argv, commands, aliases,
2263 d971402f Michael Hanselmann
                                       env_override)
2264 d971402f Michael Hanselmann
  except _ShowVersion:
2265 d971402f Michael Hanselmann
    ToStdout("%s (ganeti %s) %s", binary, constants.VCS_VERSION,
2266 d971402f Michael Hanselmann
             constants.RELEASE_VERSION)
2267 d971402f Michael Hanselmann
    return constants.EXIT_SUCCESS
2268 d971402f Michael Hanselmann
  except _ShowUsage, err:
2269 d971402f Michael Hanselmann
    for line in _FormatUsage(binary, commands):
2270 d971402f Michael Hanselmann
      ToStdout(line)
2271 d971402f Michael Hanselmann
2272 d971402f Michael Hanselmann
    if err.exit_error:
2273 d971402f Michael Hanselmann
      return constants.EXIT_FAILURE
2274 d971402f Michael Hanselmann
    else:
2275 d971402f Michael Hanselmann
      return constants.EXIT_SUCCESS
2276 3126878d Guido Trotter
  except errors.ParameterError, err:
2277 3126878d Guido Trotter
    result, err_msg = FormatError(err)
2278 3126878d Guido Trotter
    ToStderr(err_msg)
2279 3126878d Guido Trotter
    return 1
2280 3126878d Guido Trotter
2281 a8083063 Iustin Pop
  if func is None: # parse error
2282 a8083063 Iustin Pop
    return 1
2283 a8083063 Iustin Pop
2284 334d1483 Iustin Pop
  if override is not None:
2285 334d1483 Iustin Pop
    for key, val in override.iteritems():
2286 334d1483 Iustin Pop
      setattr(options, key, val)
2287 334d1483 Iustin Pop
2288 ee4a14c0 Michael Hanselmann
  utils.SetupLogging(pathutils.LOG_COMMANDS, logname, debug=options.debug,
2289 cfcc79c6 Michael Hanselmann
                     stderr_logging=True)
2290 a8083063 Iustin Pop
2291 c1f19851 Michael Hanselmann
  logging.info("Command line: %s", cmdline)
2292 a8083063 Iustin Pop
2293 a8083063 Iustin Pop
  try:
2294 a4af651e Iustin Pop
    result = func(options, args)
2295 d8353c3a Iustin Pop
  except (errors.GenericError, luxi.ProtocolError,
2296 d8353c3a Iustin Pop
          JobSubmittedException), err:
2297 a4af651e Iustin Pop
    result, err_msg = FormatError(err)
2298 5bbd3f7f Michael Hanselmann
    logging.exception("Error during command processing")
2299 46fbdd04 Iustin Pop
    ToStderr(err_msg)
2300 8a53b55f Iustin Pop
  except KeyboardInterrupt:
2301 8a53b55f Iustin Pop
    result = constants.EXIT_FAILURE
2302 8a53b55f Iustin Pop
    ToStderr("Aborted. Note that if the operation created any jobs, they"
2303 8a53b55f Iustin Pop
             " might have been submitted and"
2304 8a53b55f Iustin Pop
             " will continue to run in the background.")
2305 225e2544 Iustin Pop
  except IOError, err:
2306 225e2544 Iustin Pop
    if err.errno == errno.EPIPE:
2307 225e2544 Iustin Pop
      # our terminal went away, we'll exit
2308 225e2544 Iustin Pop
      sys.exit(constants.EXIT_FAILURE)
2309 225e2544 Iustin Pop
    else:
2310 225e2544 Iustin Pop
      raise
2311 a8083063 Iustin Pop
2312 a8083063 Iustin Pop
  return result
2313 137161c9 Michael Hanselmann
2314 137161c9 Michael Hanselmann
2315 845c79d8 Michael Hanselmann
def ParseNicOption(optvalue):
2316 845c79d8 Michael Hanselmann
  """Parses the value of the --net option(s).
2317 845c79d8 Michael Hanselmann

2318 845c79d8 Michael Hanselmann
  """
2319 845c79d8 Michael Hanselmann
  try:
2320 845c79d8 Michael Hanselmann
    nic_max = max(int(nidx[0]) + 1 for nidx in optvalue)
2321 845c79d8 Michael Hanselmann
  except (TypeError, ValueError), err:
2322 2cfbc784 Iustin Pop
    raise errors.OpPrereqError("Invalid NIC index passed: %s" % str(err),
2323 2cfbc784 Iustin Pop
                               errors.ECODE_INVAL)
2324 845c79d8 Michael Hanselmann
2325 845c79d8 Michael Hanselmann
  nics = [{}] * nic_max
2326 845c79d8 Michael Hanselmann
  for nidx, ndict in optvalue:
2327 845c79d8 Michael Hanselmann
    nidx = int(nidx)
2328 845c79d8 Michael Hanselmann
2329 845c79d8 Michael Hanselmann
    if not isinstance(ndict, dict):
2330 845c79d8 Michael Hanselmann
      raise errors.OpPrereqError("Invalid nic/%d value: expected dict,"
2331 2cfbc784 Iustin Pop
                                 " got %s" % (nidx, ndict), errors.ECODE_INVAL)
2332 845c79d8 Michael Hanselmann
2333 845c79d8 Michael Hanselmann
    utils.ForceDictType(ndict, constants.INIC_PARAMS_TYPES)
2334 845c79d8 Michael Hanselmann
2335 845c79d8 Michael Hanselmann
    nics[nidx] = ndict
2336 845c79d8 Michael Hanselmann
2337 845c79d8 Michael Hanselmann
  return nics
2338 845c79d8 Michael Hanselmann
2339 845c79d8 Michael Hanselmann
2340 d77490c5 Iustin Pop
def GenericInstanceCreate(mode, opts, args):
2341 d77490c5 Iustin Pop
  """Add an instance to the cluster via either creation or import.
2342 d77490c5 Iustin Pop

2343 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
2344 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
2345 d77490c5 Iustin Pop
  @type args: list
2346 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
2347 d77490c5 Iustin Pop
  @rtype: int
2348 d77490c5 Iustin Pop
  @return: the desired exit code
2349 d77490c5 Iustin Pop

2350 d77490c5 Iustin Pop
  """
2351 d77490c5 Iustin Pop
  instance = args[0]
2352 d77490c5 Iustin Pop
2353 d77490c5 Iustin Pop
  (pnode, snode) = SplitNodeOption(opts.node)
2354 d77490c5 Iustin Pop
2355 d77490c5 Iustin Pop
  hypervisor = None
2356 d77490c5 Iustin Pop
  hvparams = {}
2357 d77490c5 Iustin Pop
  if opts.hypervisor:
2358 d77490c5 Iustin Pop
    hypervisor, hvparams = opts.hypervisor
2359 d77490c5 Iustin Pop
2360 d77490c5 Iustin Pop
  if opts.nics:
2361 845c79d8 Michael Hanselmann
    nics = ParseNicOption(opts.nics)
2362 d77490c5 Iustin Pop
  elif opts.no_nics:
2363 d77490c5 Iustin Pop
    # no nics
2364 d77490c5 Iustin Pop
    nics = []
2365 0af0f641 Iustin Pop
  elif mode == constants.INSTANCE_CREATE:
2366 d77490c5 Iustin Pop
    # default of one nic, all auto
2367 d77490c5 Iustin Pop
    nics = [{}]
2368 0af0f641 Iustin Pop
  else:
2369 0af0f641 Iustin Pop
    # mode == import
2370 0af0f641 Iustin Pop
    nics = []
2371 d77490c5 Iustin Pop
2372 d77490c5 Iustin Pop
  if opts.disk_template == constants.DT_DISKLESS:
2373 d77490c5 Iustin Pop
    if opts.disks or opts.sd_size is not None:
2374 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Diskless instance but disk"
2375 2cfbc784 Iustin Pop
                                 " information passed", errors.ECODE_INVAL)
2376 d77490c5 Iustin Pop
    disks = []
2377 d77490c5 Iustin Pop
  else:
2378 9b12ed0f Iustin Pop
    if (not opts.disks and not opts.sd_size
2379 9b12ed0f Iustin Pop
        and mode == constants.INSTANCE_CREATE):
2380 2cfbc784 Iustin Pop
      raise errors.OpPrereqError("No disk information specified",
2381 2cfbc784 Iustin Pop
                                 errors.ECODE_INVAL)
2382 d77490c5 Iustin Pop
    if opts.disks and opts.sd_size is not None:
2383 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Please use either the '--disk' or"
2384 2cfbc784 Iustin Pop
                                 " '-s' option", errors.ECODE_INVAL)
2385 d77490c5 Iustin Pop
    if opts.sd_size is not None:
2386 ccfa86ba Michael Hanselmann
      opts.disks = [(0, {constants.IDISK_SIZE: opts.sd_size})]
2387 9b12ed0f Iustin Pop
2388 9b12ed0f Iustin Pop
    if opts.disks:
2389 9b12ed0f Iustin Pop
      try:
2390 9b12ed0f Iustin Pop
        disk_max = max(int(didx[0]) + 1 for didx in opts.disks)
2391 9b12ed0f Iustin Pop
      except ValueError, err:
2392 2cfbc784 Iustin Pop
        raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err),
2393 2cfbc784 Iustin Pop
                                   errors.ECODE_INVAL)
2394 9b12ed0f Iustin Pop
      disks = [{}] * disk_max
2395 9b12ed0f Iustin Pop
    else:
2396 9b12ed0f Iustin Pop
      disks = []
2397 d77490c5 Iustin Pop
    for didx, ddict in opts.disks:
2398 d77490c5 Iustin Pop
      didx = int(didx)
2399 d77490c5 Iustin Pop
      if not isinstance(ddict, dict):
2400 d77490c5 Iustin Pop
        msg = "Invalid disk/%d value: expected dict, got %s" % (didx, ddict)
2401 2cfbc784 Iustin Pop
        raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
2402 ccfa86ba Michael Hanselmann
      elif constants.IDISK_SIZE in ddict:
2403 ccfa86ba Michael Hanselmann
        if constants.IDISK_ADOPT in ddict:
2404 5029db65 Iustin Pop
          raise errors.OpPrereqError("Only one of 'size' and 'adopt' allowed"
2405 2cfbc784 Iustin Pop
                                     " (disk %d)" % didx, errors.ECODE_INVAL)
2406 5029db65 Iustin Pop
        try:
2407 ccfa86ba Michael Hanselmann
          ddict[constants.IDISK_SIZE] = \
2408 ccfa86ba Michael Hanselmann
            utils.ParseUnit(ddict[constants.IDISK_SIZE])
2409 5029db65 Iustin Pop
        except ValueError, err:
2410 5029db65 Iustin Pop
          raise errors.OpPrereqError("Invalid disk size for disk %d: %s" %
2411 2cfbc784 Iustin Pop
                                     (didx, err), errors.ECODE_INVAL)
2412 ccfa86ba Michael Hanselmann
      elif constants.IDISK_ADOPT in ddict:
2413 5029db65 Iustin Pop
        if mode == constants.INSTANCE_IMPORT:
2414 5029db65 Iustin Pop
          raise errors.OpPrereqError("Disk adoption not allowed for instance"
2415 2cfbc784 Iustin Pop
                                     " import", errors.ECODE_INVAL)
2416 ccfa86ba Michael Hanselmann
        ddict[constants.IDISK_SIZE] = 0
2417 5029db65 Iustin Pop
      else:
2418 5029db65 Iustin Pop
        raise errors.OpPrereqError("Missing size or adoption source for"
2419 2cfbc784 Iustin Pop
                                   " disk %d" % didx, errors.ECODE_INVAL)
2420 d77490c5 Iustin Pop
      disks[didx] = ddict
2421 d77490c5 Iustin Pop
2422 a57981c5 Apollon Oikonomopoulos
  if opts.tags is not None:
2423 0f8810df Michael Hanselmann
    tags = opts.tags.split(",")
2424 a57981c5 Apollon Oikonomopoulos
  else:
2425 a57981c5 Apollon Oikonomopoulos
    tags = []
2426 a57981c5 Apollon Oikonomopoulos
2427 b2e233a5 Guido Trotter
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_COMPAT)
2428 d77490c5 Iustin Pop
  utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
2429 d77490c5 Iustin Pop
2430 d77490c5 Iustin Pop
  if mode == constants.INSTANCE_CREATE:
2431 d77490c5 Iustin Pop
    start = opts.start
2432 d77490c5 Iustin Pop
    os_type = opts.os
2433 1ee8e01a Guido Trotter
    force_variant = opts.force_variant
2434 d77490c5 Iustin Pop
    src_node = None
2435 d77490c5 Iustin Pop
    src_path = None
2436 25a8792c Iustin Pop
    no_install = opts.no_install
2437 e588764d Iustin Pop
    identify_defaults = False
2438 d77490c5 Iustin Pop
  elif mode == constants.INSTANCE_IMPORT:
2439 d77490c5 Iustin Pop
    start = False
2440 d77490c5 Iustin Pop
    os_type = None
2441 1ee8e01a Guido Trotter
    force_variant = False
2442 d77490c5 Iustin Pop
    src_node = opts.src_node
2443 d77490c5 Iustin Pop
    src_path = opts.src_dir
2444 25a8792c Iustin Pop
    no_install = None
2445 e588764d Iustin Pop
    identify_defaults = opts.identify_defaults
2446 d77490c5 Iustin Pop
  else:
2447 d77490c5 Iustin Pop
    raise errors.ProgrammerError("Invalid creation mode %s" % mode)
2448 d77490c5 Iustin Pop
2449 e1530b10 Iustin Pop
  op = opcodes.OpInstanceCreate(instance_name=instance,
2450 d77490c5 Iustin Pop
                                disks=disks,
2451 d77490c5 Iustin Pop
                                disk_template=opts.disk_template,
2452 d77490c5 Iustin Pop
                                nics=nics,
2453 d77490c5 Iustin Pop
                                pnode=pnode, snode=snode,
2454 d77490c5 Iustin Pop
                                ip_check=opts.ip_check,
2455 460d22be Iustin Pop
                                name_check=opts.name_check,
2456 d77490c5 Iustin Pop
                                wait_for_sync=opts.wait_for_sync,
2457 d77490c5 Iustin Pop
                                file_storage_dir=opts.file_storage_dir,
2458 d77490c5 Iustin Pop
                                file_driver=opts.file_driver,
2459 d77490c5 Iustin Pop
                                iallocator=opts.iallocator,
2460 d77490c5 Iustin Pop
                                hypervisor=hypervisor,
2461 d77490c5 Iustin Pop
                                hvparams=hvparams,
2462 d77490c5 Iustin Pop
                                beparams=opts.beparams,
2463 062a7100 Iustin Pop
                                osparams=opts.osparams,
2464 d77490c5 Iustin Pop
                                mode=mode,
2465 d77490c5 Iustin Pop
                                start=start,
2466 d77490c5 Iustin Pop
                                os_type=os_type,
2467 1ee8e01a Guido Trotter
                                force_variant=force_variant,
2468 d77490c5 Iustin Pop
                                src_node=src_node,
2469 25a8792c Iustin Pop
                                src_path=src_path,
2470 a57981c5 Apollon Oikonomopoulos
                                tags=tags,
2471 e588764d Iustin Pop
                                no_install=no_install,
2472 10889e0c René Nussbaumer
                                identify_defaults=identify_defaults,
2473 10889e0c René Nussbaumer
                                ignore_ipolicy=opts.ignore_ipolicy)
2474 d77490c5 Iustin Pop
2475 d77490c5 Iustin Pop
  SubmitOrSend(op, opts)
2476 d77490c5 Iustin Pop
  return 0
2477 d77490c5 Iustin Pop
2478 d77490c5 Iustin Pop
2479 7e49b6ce Michael Hanselmann
class _RunWhileClusterStoppedHelper:
2480 7e49b6ce Michael Hanselmann
  """Helper class for L{RunWhileClusterStopped} to simplify state management
2481 7e49b6ce Michael Hanselmann

2482 7e49b6ce Michael Hanselmann
  """
2483 7e49b6ce Michael Hanselmann
  def __init__(self, feedback_fn, cluster_name, master_node, online_nodes):
2484 7e49b6ce Michael Hanselmann
    """Initializes this class.
2485 7e49b6ce Michael Hanselmann

2486 7e49b6ce Michael Hanselmann
    @type feedback_fn: callable
2487 7e49b6ce Michael Hanselmann
    @param feedback_fn: Feedback function
2488 7e49b6ce Michael Hanselmann
    @type cluster_name: string
2489 7e49b6ce Michael Hanselmann
    @param cluster_name: Cluster name
2490 7e49b6ce Michael Hanselmann
    @type master_node: string
2491 7e49b6ce Michael Hanselmann
    @param master_node Master node name
2492 7e49b6ce Michael Hanselmann
    @type online_nodes: list
2493 7e49b6ce Michael Hanselmann
    @param online_nodes: List of names of online nodes
2494 7e49b6ce Michael Hanselmann

2495 7e49b6ce Michael Hanselmann
    """
2496 7e49b6ce Michael Hanselmann
    self.feedback_fn = feedback_fn
2497 7e49b6ce Michael Hanselmann
    self.cluster_name = cluster_name
2498 7e49b6ce Michael Hanselmann
    self.master_node = master_node
2499 7e49b6ce Michael Hanselmann
    self.online_nodes = online_nodes
2500 7e49b6ce Michael Hanselmann
2501 7e49b6ce Michael Hanselmann
    self.ssh = ssh.SshRunner(self.cluster_name)
2502 7e49b6ce Michael Hanselmann
2503 7e49b6ce Michael Hanselmann
    self.nonmaster_nodes = [name for name in online_nodes
2504 7e49b6ce Michael Hanselmann
                            if name != master_node]
2505 7e49b6ce Michael Hanselmann
2506 7e49b6ce Michael Hanselmann
    assert self.master_node not in self.nonmaster_nodes
2507 7e49b6ce Michael Hanselmann
2508 7e49b6ce Michael Hanselmann
  def _RunCmd(self, node_name, cmd):
2509 7e49b6ce Michael Hanselmann
    """Runs a command on the local or a remote machine.
2510 7e49b6ce Michael Hanselmann

2511 7e49b6ce Michael Hanselmann
    @type node_name: string
2512 7e49b6ce Michael Hanselmann
    @param node_name: Machine name
2513 7e49b6ce Michael Hanselmann
    @type cmd: list
2514 7e49b6ce Michael Hanselmann
    @param cmd: Command
2515 7e49b6ce Michael Hanselmann

2516 7e49b6ce Michael Hanselmann
    """
2517 7e49b6ce Michael Hanselmann
    if node_name is None or node_name == self.master_node:
2518 7e49b6ce Michael Hanselmann
      # No need to use SSH
2519 7e49b6ce Michael Hanselmann
      result = utils.RunCmd(cmd)
2520 7e49b6ce Michael Hanselmann
    else:
2521 052783ff Michael Hanselmann
      result = self.ssh.Run(node_name, constants.SSH_LOGIN_USER,
2522 052783ff Michael Hanselmann
                            utils.ShellQuoteArgs(cmd))
2523 7e49b6ce Michael Hanselmann
2524 7e49b6ce Michael Hanselmann
    if result.failed:
2525 7e49b6ce Michael Hanselmann
      errmsg = ["Failed to run command %s" % result.cmd]
2526 7e49b6ce Michael Hanselmann
      if node_name:
2527 7e49b6ce Michael Hanselmann
        errmsg.append("on node %s" % node_name)
2528 7e49b6ce Michael Hanselmann
      errmsg.append(": exitcode %s and error %s" %
2529 7e49b6ce Michael Hanselmann
                    (result.exit_code, result.output))
2530 7e49b6ce Michael Hanselmann
      raise errors.OpExecError(" ".join(errmsg))
2531 7e49b6ce Michael Hanselmann
2532 7e49b6ce Michael Hanselmann
  def Call(self, fn, *args):
2533 7e49b6ce Michael Hanselmann
    """Call function while all daemons are stopped.
2534 7e49b6ce Michael Hanselmann

2535 7e49b6ce Michael Hanselmann
    @type fn: callable
2536 7e49b6ce Michael Hanselmann
    @param fn: Function to be called
2537 7e49b6ce Michael Hanselmann

2538 7e49b6ce Michael Hanselmann
    """
2539 7e49b6ce Michael Hanselmann
    # Pause watcher by acquiring an exclusive lock on watcher state file
2540 7e49b6ce Michael Hanselmann
    self.feedback_fn("Blocking watcher")
2541 ee4a14c0 Michael Hanselmann
    watcher_block = utils.FileLock.Open(pathutils.WATCHER_LOCK_FILE)
2542 7e49b6ce Michael Hanselmann
    try:
2543 7e49b6ce Michael Hanselmann
      # TODO: Currently, this just blocks. There's no timeout.
2544 7e49b6ce Michael Hanselmann
      # TODO: Should it be a shared lock?
2545 7e49b6ce Michael Hanselmann
      watcher_block.Exclusive(blocking=True)
2546 7e49b6ce Michael Hanselmann
2547 7e49b6ce Michael Hanselmann
      # Stop master daemons, so that no new jobs can come in and all running
2548 7e49b6ce Michael Hanselmann
      # ones are finished
2549 7e49b6ce Michael Hanselmann
      self.feedback_fn("Stopping master daemons")
2550 ee4a14c0 Michael Hanselmann
      self._RunCmd(None, [pathutils.DAEMON_UTIL, "stop-master"])
2551 7e49b6ce Michael Hanselmann
      try:
2552 7e49b6ce Michael Hanselmann
        # Stop daemons on all nodes
2553 7e49b6ce Michael Hanselmann
        for node_name in self.online_nodes:
2554 7e49b6ce Michael Hanselmann
          self.feedback_fn("Stopping daemons on %s" % node_name)
2555 ee4a14c0 Michael Hanselmann
          self._RunCmd(node_name, [pathutils.DAEMON_UTIL, "stop-all"])
2556 7e49b6ce Michael Hanselmann
2557 7e49b6ce Michael Hanselmann
        # All daemons are shut down now
2558 7e49b6ce Michael Hanselmann
        try:
2559 7e49b6ce Michael Hanselmann
          return fn(self, *args)
2560 d512e84b Michael Hanselmann
        except Exception, err:
2561 d512e84b Michael Hanselmann
          _, errmsg = FormatError(err)
2562 7e49b6ce Michael Hanselmann
          logging.exception("Caught exception")
2563 d512e84b Michael Hanselmann
          self.feedback_fn(errmsg)
2564 7e49b6ce Michael Hanselmann
          raise
2565 7e49b6ce Michael Hanselmann
      finally:
2566 7e49b6ce Michael Hanselmann
        # Start cluster again, master node last
2567 7e49b6ce Michael Hanselmann
        for node_name in self.nonmaster_nodes + [self.master_node]:
2568 7e49b6ce Michael Hanselmann
          self.feedback_fn("Starting daemons on %s" % node_name)
2569 ee4a14c0 Michael Hanselmann
          self._RunCmd(node_name, [pathutils.DAEMON_UTIL, "start-all"])
2570 7e49b6ce Michael Hanselmann
    finally:
2571 7e49b6ce Michael Hanselmann
      # Resume watcher
2572 7e49b6ce Michael Hanselmann
      watcher_block.Close()
2573 7e49b6ce Michael Hanselmann
2574 7e49b6ce Michael Hanselmann
2575 7e49b6ce Michael Hanselmann
def RunWhileClusterStopped(feedback_fn, fn, *args):
2576 7e49b6ce Michael Hanselmann
  """Calls a function while all cluster daemons are stopped.
2577 7e49b6ce Michael Hanselmann

2578 7e49b6ce Michael Hanselmann
  @type feedback_fn: callable
2579 7e49b6ce Michael Hanselmann
  @param feedback_fn: Feedback function
2580 7e49b6ce Michael Hanselmann
  @type fn: callable
2581 7e49b6ce Michael Hanselmann
  @param fn: Function to be called when daemons are stopped
2582 7e49b6ce Michael Hanselmann

2583 7e49b6ce Michael Hanselmann
  """
2584 7e49b6ce Michael Hanselmann
  feedback_fn("Gathering cluster information")
2585 7e49b6ce Michael Hanselmann
2586 7e49b6ce Michael Hanselmann
  # This ensures we're running on the master daemon
2587 7e49b6ce Michael Hanselmann
  cl = GetClient()
2588 7e49b6ce Michael Hanselmann
2589 7e49b6ce Michael Hanselmann
  (cluster_name, master_node) = \
2590 7e49b6ce Michael Hanselmann
    cl.QueryConfigValues(["cluster_name", "master_node"])
2591 7e49b6ce Michael Hanselmann
2592 7e49b6ce Michael Hanselmann
  online_nodes = GetOnlineNodes([], cl=cl)
2593 7e49b6ce Michael Hanselmann
2594 7e49b6ce Michael Hanselmann
  # Don't keep a reference to the client. The master daemon will go away.
2595 7e49b6ce Michael Hanselmann
  del cl
2596 7e49b6ce Michael Hanselmann
2597 7e49b6ce Michael Hanselmann
  assert master_node in online_nodes
2598 7e49b6ce Michael Hanselmann
2599 7e49b6ce Michael Hanselmann
  return _RunWhileClusterStoppedHelper(feedback_fn, cluster_name, master_node,
2600 7e49b6ce Michael Hanselmann
                                       online_nodes).Call(fn, *args)
2601 7e49b6ce Michael Hanselmann
2602 7e49b6ce Michael Hanselmann
2603 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
2604 9fbfbb7b Iustin Pop
                  numfields=None, unitfields=None,
2605 9fbfbb7b Iustin Pop
                  units=None):
2606 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
2607 137161c9 Michael Hanselmann

2608 9fbfbb7b Iustin Pop
  @type headers: dict
2609 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
2610 9fbfbb7b Iustin Pop
      the table
2611 9fbfbb7b Iustin Pop
  @type fields: list
2612 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
2613 9fbfbb7b Iustin Pop
      the data field
2614 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
2615 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
2616 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
2617 9fbfbb7b Iustin Pop
      each field
2618 9fbfbb7b Iustin Pop
  @type data: list
2619 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
2620 9fbfbb7b Iustin Pop
  @type numfields: list
2621 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
2622 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
2623 9fbfbb7b Iustin Pop
  @type unitfields: list
2624 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
2625 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
2626 9fbfbb7b Iustin Pop
  @type units: string or None
2627 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
2628 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
2629 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
2630 137161c9 Michael Hanselmann

2631 137161c9 Michael Hanselmann
  """
2632 9fbfbb7b Iustin Pop
  if units is None:
2633 9fbfbb7b Iustin Pop
    if separator:
2634 9fbfbb7b Iustin Pop
      units = "m"
2635 9fbfbb7b Iustin Pop
    else:
2636 9fbfbb7b Iustin Pop
      units = "h"
2637 9fbfbb7b Iustin Pop
2638 137161c9 Michael Hanselmann
  if numfields is None:
2639 137161c9 Michael Hanselmann
    numfields = []
2640 137161c9 Michael Hanselmann
  if unitfields is None:
2641 137161c9 Michael Hanselmann
    unitfields = []
2642 137161c9 Michael Hanselmann
2643 b459a848 Andrea Spadaccini
  numfields = utils.FieldSet(*numfields)   # pylint: disable=W0142
2644 b459a848 Andrea Spadaccini
  unitfields = utils.FieldSet(*unitfields) # pylint: disable=W0142
2645 00430f8e Iustin Pop
2646 137161c9 Michael Hanselmann
  format_fields = []
2647 137161c9 Michael Hanselmann
  for field in fields:
2648 01ca31ae Iustin Pop
    if headers and field not in headers:
2649 ea5a5b74 Guido Trotter
      # TODO: handle better unknown fields (either revert to old
2650 71c1af58 Iustin Pop
      # style of raising exception, or deal more intelligently with
2651 71c1af58 Iustin Pop
      # variable fields)
2652 71c1af58 Iustin Pop
      headers[field] = field
2653 137161c9 Michael Hanselmann
    if separator is not None:
2654 137161c9 Michael Hanselmann
      format_fields.append("%s")
2655 00430f8e Iustin Pop
    elif numfields.Matches(field):
2656 137161c9 Michael Hanselmann
      format_fields.append("%*s")
2657 137161c9 Michael Hanselmann
    else:
2658 137161c9 Michael Hanselmann
      format_fields.append("%-*s")
2659 137161c9 Michael Hanselmann
2660 137161c9 Michael Hanselmann
  if separator is None:
2661 137161c9 Michael Hanselmann
    mlens = [0 for name in fields]
2662 d0c8c01d Iustin Pop
    format_str = " ".join(format_fields)
2663 137161c9 Michael Hanselmann
  else:
2664 c04bc777 Iustin Pop
    format_str = separator.replace("%", "%%").join(format_fields)
2665 137161c9 Michael Hanselmann
2666 137161c9 Michael Hanselmann
  for row in data:
2667 dcbd6288 Guido Trotter
    if row is None:
2668 dcbd6288 Guido Trotter
      continue
2669 137161c9 Michael Hanselmann
    for idx, val in enumerate(row):
2670 00430f8e Iustin Pop
      if unitfields.Matches(fields[idx]):
2671 137161c9 Michael Hanselmann
        try:
2672 137161c9 Michael Hanselmann
          val = int(val)
2673 691744c4 Iustin Pop
        except (TypeError, ValueError):
2674 137161c9 Michael Hanselmann
          pass
2675 137161c9 Michael Hanselmann
        else:
2676 9fbfbb7b Iustin Pop
          val = row[idx] = utils.FormatUnit(val, units)
2677 01ca31ae Iustin Pop
      val = row[idx] = str(val)
2678 137161c9 Michael Hanselmann
      if separator is None:
2679 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(val))
2680 137161c9 Michael Hanselmann
2681 16be8703 Iustin Pop
  result = []
2682 137161c9 Michael Hanselmann
  if headers:
2683 137161c9 Michael Hanselmann
    args = []
2684 137161c9 Michael Hanselmann
    for idx, name in enumerate(fields):
2685 137161c9 Michael Hanselmann
      hdr = headers[name]
2686 137161c9 Michael Hanselmann
      if separator is None:
2687 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(hdr))
2688 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2689 137161c9 Michael Hanselmann
      args.append(hdr)
2690 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2691 137161c9 Michael Hanselmann
2692 ec39d63c Michael Hanselmann
  if separator is None:
2693 ec39d63c Michael Hanselmann
    assert len(mlens) == len(fields)
2694 ec39d63c Michael Hanselmann
2695 ec39d63c Michael Hanselmann
    if fields and not numfields.Matches(fields[-1]):
2696 ec39d63c Michael Hanselmann
      mlens[-1] = 0
2697 ec39d63c Michael Hanselmann
2698 137161c9 Michael Hanselmann
  for line in data:
2699 137161c9 Michael Hanselmann
    args = []
2700 dcbd6288 Guido Trotter
    if line is None:
2701 d0c8c01d Iustin Pop
      line = ["-" for _ in fields]
2702 f1501b3f Michael Hanselmann
    for idx in range(len(fields)):
2703 137161c9 Michael Hanselmann
      if separator is None:
2704 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2705 137161c9 Michael Hanselmann
      args.append(line[idx])
2706 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2707 16be8703 Iustin Pop
2708 16be8703 Iustin Pop
  return result
2709 3386e7a9 Iustin Pop
2710 3386e7a9 Iustin Pop
2711 ee3aedff Michael Hanselmann
def _FormatBool(value):
2712 ee3aedff Michael Hanselmann
  """Formats a boolean value as a string.
2713 ee3aedff Michael Hanselmann

2714 ee3aedff Michael Hanselmann
  """
2715 ee3aedff Michael Hanselmann
  if value:
2716 ee3aedff Michael Hanselmann
    return "Y"
2717 ee3aedff Michael Hanselmann
  return "N"
2718 ee3aedff Michael Hanselmann
2719 ee3aedff Michael Hanselmann
2720 ee3aedff Michael Hanselmann
#: Default formatting for query results; (callback, align right)
2721 ee3aedff Michael Hanselmann
_DEFAULT_FORMAT_QUERY = {
2722 ee3aedff Michael Hanselmann
  constants.QFT_TEXT: (str, False),
2723 ee3aedff Michael Hanselmann
  constants.QFT_BOOL: (_FormatBool, False),
2724 ee3aedff Michael Hanselmann
  constants.QFT_NUMBER: (str, True),
2725 ee3aedff Michael Hanselmann
  constants.QFT_TIMESTAMP: (utils.FormatTime, False),
2726 ee3aedff Michael Hanselmann
  constants.QFT_OTHER: (str, False),
2727 ee3aedff Michael Hanselmann
  constants.QFT_UNKNOWN: (str, False),
2728 ee3aedff Michael Hanselmann
  }
2729 ee3aedff Michael Hanselmann
2730 ee3aedff Michael Hanselmann
2731 ee3aedff Michael Hanselmann
def _GetColumnFormatter(fdef, override, unit):
2732 ee3aedff Michael Hanselmann
  """Returns formatting function for a field.
2733 ee3aedff Michael Hanselmann

2734 ee3aedff Michael Hanselmann
  @type fdef: L{objects.QueryFieldDefinition}
2735 ee3aedff Michael Hanselmann
  @type override: dict
2736 ee3aedff Michael Hanselmann
  @param override: Dictionary for overriding field formatting functions,
2737 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2738 ee3aedff Michael Hanselmann
  @type unit: string
2739 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT}
2740 ee3aedff Michael Hanselmann
  @rtype: tuple; (callable, bool)
2741 ee3aedff Michael Hanselmann
  @return: Returns the function to format a value (takes one parameter) and a
2742 ee3aedff Michael Hanselmann
    boolean for aligning the value on the right-hand side
2743 ee3aedff Michael Hanselmann

2744 ee3aedff Michael Hanselmann
  """
2745 ee3aedff Michael Hanselmann
  fmt = override.get(fdef.name, None)
2746 ee3aedff Michael Hanselmann
  if fmt is not None:
2747 ee3aedff Michael Hanselmann
    return fmt
2748 ee3aedff Michael Hanselmann
2749 ee3aedff Michael Hanselmann
  assert constants.QFT_UNIT not in _DEFAULT_FORMAT_QUERY
2750 ee3aedff Michael Hanselmann
2751 ee3aedff Michael Hanselmann
  if fdef.kind == constants.QFT_UNIT:
2752 ee3aedff Michael Hanselmann
    # Can't keep this information in the static dictionary
2753 ee3aedff Michael Hanselmann
    return (lambda value: utils.FormatUnit(value, unit), True)
2754 ee3aedff Michael Hanselmann
2755 ee3aedff Michael Hanselmann
  fmt = _DEFAULT_FORMAT_QUERY.get(fdef.kind, None)
2756 ee3aedff Michael Hanselmann
  if fmt is not None:
2757 ee3aedff Michael Hanselmann
    return fmt
2758 ee3aedff Michael Hanselmann
2759 ee3aedff Michael Hanselmann
  raise NotImplementedError("Can't format column type '%s'" % fdef.kind)
2760 ee3aedff Michael Hanselmann
2761 ee3aedff Michael Hanselmann
2762 ee3aedff Michael Hanselmann
class _QueryColumnFormatter:
2763 ee3aedff Michael Hanselmann
  """Callable class for formatting fields of a query.
2764 ee3aedff Michael Hanselmann

2765 ee3aedff Michael Hanselmann
  """
2766 f0b1bafe Iustin Pop
  def __init__(self, fn, status_fn, verbose):
2767 ee3aedff Michael Hanselmann
    """Initializes this class.
2768 ee3aedff Michael Hanselmann

2769 ee3aedff Michael Hanselmann
    @type fn: callable
2770 ee3aedff Michael Hanselmann
    @param fn: Formatting function
2771 ee3aedff Michael Hanselmann
    @type status_fn: callable
2772 ee3aedff Michael Hanselmann
    @param status_fn: Function to report fields' status
2773 f0b1bafe Iustin Pop
    @type verbose: boolean
2774 f0b1bafe Iustin Pop
    @param verbose: whether to use verbose field descriptions or not
2775 ee3aedff Michael Hanselmann

2776 ee3aedff Michael Hanselmann
    """
2777 ee3aedff Michael Hanselmann
    self._fn = fn
2778 ee3aedff Michael Hanselmann
    self._status_fn = status_fn
2779 cbfa4f0f Michael Hanselmann
    self._verbose = verbose
2780 ee3aedff Michael Hanselmann
2781 ee3aedff Michael Hanselmann
  def __call__(self, data):
2782 ee3aedff Michael Hanselmann
    """Returns a field's string representation.
2783 ee3aedff Michael Hanselmann

2784 ee3aedff Michael Hanselmann
    """
2785 ee3aedff Michael Hanselmann
    (status, value) = data
2786 ee3aedff Michael Hanselmann
2787 ee3aedff Michael Hanselmann
    # Report status
2788 ee3aedff Michael Hanselmann
    self._status_fn(status)
2789 ee3aedff Michael Hanselmann
2790 cfb084ae René Nussbaumer
    if status == constants.RS_NORMAL:
2791 ee3aedff Michael Hanselmann
      return self._fn(value)
2792 ee3aedff Michael Hanselmann
2793 ee3aedff Michael Hanselmann
    assert value is None, \
2794 ee3aedff Michael Hanselmann
           "Found value %r for abnormal status %s" % (value, status)
2795 ee3aedff Michael Hanselmann
2796 f2c6673d Michael Hanselmann
    return FormatResultError(status, self._verbose)
2797 ee3aedff Michael Hanselmann
2798 ee3aedff Michael Hanselmann
2799 f2c6673d Michael Hanselmann
def FormatResultError(status, verbose):
2800 ae95e419 René Nussbaumer
  """Formats result status other than L{constants.RS_NORMAL}.
2801 ee3aedff Michael Hanselmann

2802 ae95e419 René Nussbaumer
  @param status: The result status
2803 f2c6673d Michael Hanselmann
  @type verbose: boolean
2804 f2c6673d Michael Hanselmann
  @param verbose: Whether to return the verbose text
2805 ae95e419 René Nussbaumer
  @return: Text of result status
2806 a6070ef7 Michael Hanselmann

2807 ae95e419 René Nussbaumer
  """
2808 ae95e419 René Nussbaumer
  assert status != constants.RS_NORMAL, \
2809 cbfa4f0f Michael Hanselmann
         "FormatResultError called with status equal to constants.RS_NORMAL"
2810 ae95e419 René Nussbaumer
  try:
2811 cbfa4f0f Michael Hanselmann
    (verbose_text, normal_text) = constants.RSS_DESCRIPTION[status]
2812 ae95e419 René Nussbaumer
  except KeyError:
2813 ee3aedff Michael Hanselmann
    raise NotImplementedError("Unknown status %s" % status)
2814 cbfa4f0f Michael Hanselmann
  else:
2815 cbfa4f0f Michael Hanselmann
    if verbose:
2816 cbfa4f0f Michael Hanselmann
      return verbose_text
2817 cbfa4f0f Michael Hanselmann
    return normal_text
2818 ee3aedff Michael Hanselmann
2819 ee3aedff Michael Hanselmann
2820 ee3aedff Michael Hanselmann
def FormatQueryResult(result, unit=None, format_override=None, separator=None,
2821 f0b1bafe Iustin Pop
                      header=False, verbose=False):
2822 ee3aedff Michael Hanselmann
  """Formats data in L{objects.QueryResponse}.
2823 ee3aedff Michael Hanselmann

2824 ee3aedff Michael Hanselmann
  @type result: L{objects.QueryResponse}
2825 ee3aedff Michael Hanselmann
  @param result: result of query operation
2826 ee3aedff Michael Hanselmann
  @type unit: string
2827 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT},
2828 18009c1e Iustin Pop
    see L{utils.text.FormatUnit}
2829 ee3aedff Michael Hanselmann
  @type format_override: dict
2830 ee3aedff Michael Hanselmann
  @param format_override: Dictionary for overriding field formatting functions,
2831 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2832 ee3aedff Michael Hanselmann
  @type separator: string or None
2833 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2834 ee3aedff Michael Hanselmann
  @type header: bool
2835 ee3aedff Michael Hanselmann
  @param header: Whether to output header row
2836 f0b1bafe Iustin Pop
  @type verbose: boolean
2837 f0b1bafe Iustin Pop
  @param verbose: whether to use verbose field descriptions or not
2838 ee3aedff Michael Hanselmann

2839 ee3aedff Michael Hanselmann
  """
2840 ee3aedff Michael Hanselmann
  if unit is None:
2841 ee3aedff Michael Hanselmann
    if separator:
2842 ee3aedff Michael Hanselmann
      unit = "m"
2843 ee3aedff Michael Hanselmann
    else:
2844 ee3aedff Michael Hanselmann
      unit = "h"
2845 ee3aedff Michael Hanselmann
2846 ee3aedff Michael Hanselmann
  if format_override is None:
2847 ee3aedff Michael Hanselmann
    format_override = {}
2848 ee3aedff Michael Hanselmann
2849 cfb084ae René Nussbaumer
  stats = dict.fromkeys(constants.RS_ALL, 0)
2850 ee3aedff Michael Hanselmann
2851 ee3aedff Michael Hanselmann
  def _RecordStatus(status):
2852 ee3aedff Michael Hanselmann
    if status in stats:
2853 ee3aedff Michael Hanselmann
      stats[status] += 1
2854 ee3aedff Michael Hanselmann
2855 ee3aedff Michael Hanselmann
  columns = []
2856 ee3aedff Michael Hanselmann
  for fdef in result.fields:
2857 ee3aedff Michael Hanselmann
    assert fdef.title and fdef.name
2858 ee3aedff Michael Hanselmann
    (fn, align_right) = _GetColumnFormatter(fdef, format_override, unit)
2859 ee3aedff Michael Hanselmann
    columns.append(TableColumn(fdef.title,
2860 f0b1bafe Iustin Pop
                               _QueryColumnFormatter(fn, _RecordStatus,
2861 f0b1bafe Iustin Pop
                                                     verbose),
2862 ee3aedff Michael Hanselmann
                               align_right))
2863 ee3aedff Michael Hanselmann
2864 ee3aedff Michael Hanselmann
  table = FormatTable(result.data, columns, header, separator)
2865 ee3aedff Michael Hanselmann
2866 ee3aedff Michael Hanselmann
  # Collect statistics
2867 cfb084ae René Nussbaumer
  assert len(stats) == len(constants.RS_ALL)
2868 ee3aedff Michael Hanselmann
  assert compat.all(count >= 0 for count in stats.values())
2869 ee3aedff Michael Hanselmann
2870 ee3aedff Michael Hanselmann
  # Determine overall status. If there was no data, unknown fields must be
2871 ee3aedff Michael Hanselmann
  # detected via the field definitions.
2872 cfb084ae René Nussbaumer
  if (stats[constants.RS_UNKNOWN] or
2873 ee3aedff Michael Hanselmann
      (not result.data and _GetUnknownFields(result.fields))):
2874 ee3aedff Michael Hanselmann
    status = QR_UNKNOWN
2875 ee3aedff Michael Hanselmann
  elif compat.any(count > 0 for key, count in stats.items()
2876 cfb084ae René Nussbaumer
                  if key != constants.RS_NORMAL):
2877 ee3aedff Michael Hanselmann
    status = QR_INCOMPLETE
2878 ee3aedff Michael Hanselmann
  else:
2879 ee3aedff Michael Hanselmann
    status = QR_NORMAL
2880 ee3aedff Michael Hanselmann
2881 ee3aedff Michael Hanselmann
  return (status, table)
2882 ee3aedff Michael Hanselmann
2883 ee3aedff Michael Hanselmann
2884 ee3aedff Michael Hanselmann
def _GetUnknownFields(fdefs):
2885 ee3aedff Michael Hanselmann
  """Returns list of unknown fields included in C{fdefs}.
2886 ee3aedff Michael Hanselmann

2887 ee3aedff Michael Hanselmann
  @type fdefs: list of L{objects.QueryFieldDefinition}
2888 ee3aedff Michael Hanselmann

2889 ee3aedff Michael Hanselmann
  """
2890 ee3aedff Michael Hanselmann
  return [fdef for fdef in fdefs
2891 ee3aedff Michael Hanselmann
          if fdef.kind == constants.QFT_UNKNOWN]
2892 ee3aedff Michael Hanselmann
2893 ee3aedff Michael Hanselmann
2894 ee3aedff Michael Hanselmann
def _WarnUnknownFields(fdefs):
2895 ee3aedff Michael Hanselmann
  """Prints a warning to stderr if a query included unknown fields.
2896 ee3aedff Michael Hanselmann

2897 ee3aedff Michael Hanselmann
  @type fdefs: list of L{objects.QueryFieldDefinition}
2898 ee3aedff Michael Hanselmann

2899 ee3aedff Michael Hanselmann
  """
2900 ee3aedff Michael Hanselmann
  unknown = _GetUnknownFields(fdefs)
2901 ee3aedff Michael Hanselmann
  if unknown:
2902 ee3aedff Michael Hanselmann
    ToStderr("Warning: Queried for unknown fields %s",
2903 ee3aedff Michael Hanselmann
             utils.CommaJoin(fdef.name for fdef in unknown))
2904 ee3aedff Michael Hanselmann
    return True
2905 ee3aedff Michael Hanselmann
2906 ee3aedff Michael Hanselmann
  return False
2907 ee3aedff Michael Hanselmann
2908 ee3aedff Michael Hanselmann
2909 ee3aedff Michael Hanselmann
def GenericList(resource, fields, names, unit, separator, header, cl=None,
2910 03ec545a Michael Hanselmann
                format_override=None, verbose=False, force_filter=False,
2911 6f287cf3 Iustin Pop
                namefield=None, qfilter=None, isnumeric=False):
2912 ee3aedff Michael Hanselmann
  """Generic implementation for listing all items of a resource.
2913 ee3aedff Michael Hanselmann

2914 abd66bf8 Michael Hanselmann
  @param resource: One of L{constants.QR_VIA_LUXI}
2915 ee3aedff Michael Hanselmann
  @type fields: list of strings
2916 ee3aedff Michael Hanselmann
  @param fields: List of fields to query for
2917 ee3aedff Michael Hanselmann
  @type names: list of strings
2918 ee3aedff Michael Hanselmann
  @param names: Names of items to query for
2919 ee3aedff Michael Hanselmann
  @type unit: string or None
2920 ee3aedff Michael Hanselmann
  @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT} or
2921 ee3aedff Michael Hanselmann
    None for automatic choice (human-readable for non-separator usage,
2922 ee3aedff Michael Hanselmann
    otherwise megabytes); this is a one-letter string
2923 ee3aedff Michael Hanselmann
  @type separator: string or None
2924 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2925 ee3aedff Michael Hanselmann
  @type header: bool
2926 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2927 2928de47 Michael Hanselmann
  @type force_filter: bool
2928 2928de47 Michael Hanselmann
  @param force_filter: Whether to always treat names as filter
2929 ee3aedff Michael Hanselmann
  @type format_override: dict
2930 ee3aedff Michael Hanselmann
  @param format_override: Dictionary for overriding field formatting functions,
2931 ee3aedff Michael Hanselmann
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2932 f0b1bafe Iustin Pop
  @type verbose: boolean
2933 f0b1bafe Iustin Pop
  @param verbose: whether to use verbose field descriptions or not
2934 03ec545a Michael Hanselmann
  @type namefield: string
2935 03ec545a Michael Hanselmann
  @param namefield: Name of field to use for simple filters (see
2936 03ec545a Michael Hanselmann
    L{qlang.MakeFilter} for details)
2937 f037e9d7 Michael Hanselmann
  @type qfilter: list or None
2938 f037e9d7 Michael Hanselmann
  @param qfilter: Query filter (in addition to names)
2939 6f287cf3 Iustin Pop
  @param isnumeric: bool
2940 6f287cf3 Iustin Pop
  @param isnumeric: Whether the namefield's type is numeric, and therefore
2941 6f287cf3 Iustin Pop
    any simple filters built by namefield should use integer values to
2942 6f287cf3 Iustin Pop
    reflect that
2943 ee3aedff Michael Hanselmann

2944 ee3aedff Michael Hanselmann
  """
2945 ee3aedff Michael Hanselmann
  if not names:
2946 ee3aedff Michael Hanselmann
    names = None
2947 ee3aedff Michael Hanselmann
2948 6f287cf3 Iustin Pop
  namefilter = qlang.MakeFilter(names, force_filter, namefield=namefield,
2949 6f287cf3 Iustin Pop
                                isnumeric=isnumeric)
2950 f037e9d7 Michael Hanselmann
2951 f037e9d7 Michael Hanselmann
  if qfilter is None:
2952 f037e9d7 Michael Hanselmann
    qfilter = namefilter
2953 f037e9d7 Michael Hanselmann
  elif namefilter is not None:
2954 f037e9d7 Michael Hanselmann
    qfilter = [qlang.OP_AND, namefilter, qfilter]
2955 2928de47 Michael Hanselmann
2956 727274dd Iustin Pop
  if cl is None:
2957 727274dd Iustin Pop
    cl = GetClient()
2958 727274dd Iustin Pop
2959 2e5c33db Iustin Pop
  response = cl.Query(resource, fields, qfilter)
2960 ee3aedff Michael Hanselmann
2961 ee3aedff Michael Hanselmann
  found_unknown = _WarnUnknownFields(response.fields)
2962 ee3aedff Michael Hanselmann
2963 ee3aedff Michael Hanselmann
  (status, data) = FormatQueryResult(response, unit=unit, separator=separator,
2964 ee3aedff Michael Hanselmann
                                     header=header,
2965 f0b1bafe Iustin Pop
                                     format_override=format_override,
2966 f0b1bafe Iustin Pop
                                     verbose=verbose)
2967 ee3aedff Michael Hanselmann
2968 ee3aedff Michael Hanselmann
  for line in data:
2969 ee3aedff Michael Hanselmann
    ToStdout(line)
2970 ee3aedff Michael Hanselmann
2971 ee3aedff Michael Hanselmann
  assert ((found_unknown and status == QR_UNKNOWN) or
2972 ee3aedff Michael Hanselmann
          (not found_unknown and status != QR_UNKNOWN))
2973 ee3aedff Michael Hanselmann
2974 ee3aedff Michael Hanselmann
  if status == QR_UNKNOWN:
2975 ee3aedff Michael Hanselmann
    return constants.EXIT_UNKNOWN_FIELD
2976 ee3aedff Michael Hanselmann
2977 ee3aedff Michael Hanselmann
  # TODO: Should the list command fail if not all data could be collected?
2978 ee3aedff Michael Hanselmann
  return constants.EXIT_SUCCESS
2979 ee3aedff Michael Hanselmann
2980 ee3aedff Michael Hanselmann
2981 ee3aedff Michael Hanselmann
def GenericListFields(resource, fields, separator, header, cl=None):
2982 ee3aedff Michael Hanselmann
  """Generic implementation for listing fields for a resource.
2983 ee3aedff Michael Hanselmann

2984 abd66bf8 Michael Hanselmann
  @param resource: One of L{constants.QR_VIA_LUXI}
2985 ee3aedff Michael Hanselmann
  @type fields: list of strings
2986 ee3aedff Michael Hanselmann
  @param fields: List of fields to query for
2987 ee3aedff Michael Hanselmann
  @type separator: string or None
2988 ee3aedff Michael Hanselmann
  @param separator: String used to separate fields
2989 ee3aedff Michael Hanselmann
  @type header: bool
2990 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
2991 ee3aedff Michael Hanselmann

2992 ee3aedff Michael Hanselmann
  """
2993 ee3aedff Michael Hanselmann
  if cl is None:
2994 ee3aedff Michael Hanselmann
    cl = GetClient()
2995 ee3aedff Michael Hanselmann
2996 ee3aedff Michael Hanselmann
  if not fields:
2997 ee3aedff Michael Hanselmann
    fields = None
2998 ee3aedff Michael Hanselmann
2999 ee3aedff Michael Hanselmann
  response = cl.QueryFields(resource, fields)
3000 ee3aedff Michael Hanselmann
3001 ee3aedff Michael Hanselmann
  found_unknown = _WarnUnknownFields(response.fields)
3002 ee3aedff Michael Hanselmann
3003 ee3aedff Michael Hanselmann
  columns = [
3004 ee3aedff Michael Hanselmann
    TableColumn("Name", str, False),
3005 ee3aedff Michael Hanselmann
    TableColumn("Title", str, False),
3006 ea1440c1 Michael Hanselmann
    TableColumn("Description", str, False),
3007 ee3aedff Michael Hanselmann
    ]
3008 ee3aedff Michael Hanselmann
3009 ea1440c1 Michael Hanselmann
  rows = [[fdef.name, fdef.title, fdef.doc] for fdef in response.fields]
3010 ee3aedff Michael Hanselmann
3011 ee3aedff Michael Hanselmann
  for line in FormatTable(rows, columns, header, separator):
3012 ee3aedff Michael Hanselmann
    ToStdout(line)
3013 ee3aedff Michael Hanselmann
3014 ee3aedff Michael Hanselmann
  if found_unknown:
3015 ee3aedff Michael Hanselmann
    return constants.EXIT_UNKNOWN_FIELD
3016 ee3aedff Michael Hanselmann
3017 ee3aedff Michael Hanselmann
  return constants.EXIT_SUCCESS
3018 ee3aedff Michael Hanselmann
3019 ee3aedff Michael Hanselmann
3020 ee3aedff Michael Hanselmann
class TableColumn:
3021 ee3aedff Michael Hanselmann
  """Describes a column for L{FormatTable}.
3022 ee3aedff Michael Hanselmann

3023 ee3aedff Michael Hanselmann
  """
3024 ee3aedff Michael Hanselmann
  def __init__(self, title, fn, align_right):
3025 ee3aedff Michael Hanselmann
    """Initializes this class.
3026 ee3aedff Michael Hanselmann

3027 ee3aedff Michael Hanselmann
    @type title: string
3028 ee3aedff Michael Hanselmann
    @param title: Column title
3029 ee3aedff Michael Hanselmann
    @type fn: callable
3030 ee3aedff Michael Hanselmann
    @param fn: Formatting function
3031 ee3aedff Michael Hanselmann
    @type align_right: bool
3032 ee3aedff Michael Hanselmann
    @param align_right: Whether to align values on the right-hand side
3033 ee3aedff Michael Hanselmann

3034 ee3aedff Michael Hanselmann
    """
3035 ee3aedff Michael Hanselmann
    self.title = title
3036 ee3aedff Michael Hanselmann
    self.format = fn
3037 ee3aedff Michael Hanselmann
    self.align_right = align_right
3038 ee3aedff Michael Hanselmann
3039 ee3aedff Michael Hanselmann
3040 ee3aedff Michael Hanselmann
def _GetColFormatString(width, align_right):
3041 ee3aedff Michael Hanselmann
  """Returns the format string for a field.
3042 ee3aedff Michael Hanselmann

3043 ee3aedff Michael Hanselmann
  """
3044 ee3aedff Michael Hanselmann
  if align_right:
3045 ee3aedff Michael Hanselmann
    sign = ""
3046 ee3aedff Michael Hanselmann
  else:
3047 ee3aedff Michael Hanselmann
    sign = "-"
3048 ee3aedff Michael Hanselmann
3049 ee3aedff Michael Hanselmann
  return "%%%s%ss" % (sign, width)
3050 ee3aedff Michael Hanselmann
3051 ee3aedff Michael Hanselmann
3052 ee3aedff Michael Hanselmann
def FormatTable(rows, columns, header, separator):
3053 ee3aedff Michael Hanselmann
  """Formats data as a table.
3054 ee3aedff Michael Hanselmann

3055 ee3aedff Michael Hanselmann
  @type rows: list of lists
3056 ee3aedff Michael Hanselmann
  @param rows: Row data, one list per row
3057 ee3aedff Michael Hanselmann
  @type columns: list of L{TableColumn}
3058 ee3aedff Michael Hanselmann
  @param columns: Column descriptions
3059 ee3aedff Michael Hanselmann
  @type header: bool
3060 ee3aedff Michael Hanselmann
  @param header: Whether to show header row
3061 ee3aedff Michael Hanselmann
  @type separator: string or None
3062 ee3aedff Michael Hanselmann
  @param separator: String used to separate columns
3063 ee3aedff Michael Hanselmann

3064 ee3aedff Michael Hanselmann
  """
3065 ee3aedff Michael Hanselmann
  if header:
3066 ee3aedff Michael Hanselmann
    data = [[col.title for col in columns]]
3067 ee3aedff Michael Hanselmann
    colwidth = [len(col.title) for col in columns]
3068 ee3aedff Michael Hanselmann
  else:
3069 ee3aedff Michael Hanselmann
    data = []
3070 ee3aedff Michael Hanselmann
    colwidth = [0 for _ in columns]
3071 ee3aedff Michael Hanselmann
3072 ee3aedff Michael Hanselmann
  # Format row data
3073 ee3aedff Michael Hanselmann
  for row in rows:
3074 ee3aedff Michael Hanselmann
    assert len(row) == len(columns)
3075 ee3aedff Michael Hanselmann
3076 ee3aedff Michael Hanselmann
    formatted = [col.format(value) for value, col in zip(row, columns)]
3077 ee3aedff Michael Hanselmann
3078 ee3aedff Michael Hanselmann
    if separator is None:
3079 ee3aedff Michael Hanselmann
      # Update column widths
3080 ee3aedff Michael Hanselmann
      for idx, (oldwidth, value) in enumerate(zip(colwidth, formatted)):
3081 ee3aedff Michael Hanselmann
        # Modifying a list's items while iterating is fine
3082 ee3aedff Michael Hanselmann
        colwidth[idx] = max(oldwidth, len(value))
3083 ee3aedff Michael Hanselmann
3084 ee3aedff Michael Hanselmann
    data.append(formatted)
3085 ee3aedff Michael Hanselmann
3086 ee3aedff Michael Hanselmann
  if separator is not None:
3087 ee3aedff Michael Hanselmann
    # Return early if a separator is used
3088 ee3aedff Michael Hanselmann
    return [separator.join(row) for row in data]
3089 ee3aedff Michael Hanselmann
3090 ee3aedff Michael Hanselmann
  if columns and not columns[-1].align_right:
3091 ee3aedff Michael Hanselmann
    # Avoid unnecessary spaces at end of line
3092 ee3aedff Michael Hanselmann
    colwidth[-1] = 0
3093 ee3aedff Michael Hanselmann
3094 ee3aedff Michael Hanselmann
  # Build format string
3095 ee3aedff Michael Hanselmann
  fmt = " ".join([_GetColFormatString(width, col.align_right)
3096 ee3aedff Michael Hanselmann
                  for col, width in zip(columns, colwidth)])
3097 ee3aedff Michael Hanselmann
3098 ee3aedff Michael Hanselmann
  return [fmt % tuple(row) for row in data]
3099 ee3aedff Michael Hanselmann
3100 ee3aedff Michael Hanselmann
3101 3386e7a9 Iustin Pop
def FormatTimestamp(ts):
3102 3386e7a9 Iustin Pop
  """Formats a given timestamp.
3103 3386e7a9 Iustin Pop

3104 3386e7a9 Iustin Pop
  @type ts: timestamp
3105 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
3106 3386e7a9 Iustin Pop

3107 3386e7a9 Iustin Pop
  @rtype: string
3108 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
3109 3386e7a9 Iustin Pop

3110 3386e7a9 Iustin Pop
  """
3111 e687ec01 Michael Hanselmann
  if not isinstance(ts, (tuple, list)) or len(ts) != 2:
3112 d0c8c01d Iustin Pop
    return "?"
3113 26a72a48 Michael Hanselmann
3114 26a72a48 Michael Hanselmann
  (sec, usecs) = ts
3115 26a72a48 Michael Hanselmann
  return utils.FormatTime(sec, usecs=usecs)
3116 2241e2b9 Iustin Pop
3117 2241e2b9 Iustin Pop
3118 2241e2b9 Iustin Pop
def ParseTimespec(value):
3119 2241e2b9 Iustin Pop
  """Parse a time specification.
3120 2241e2b9 Iustin Pop

3121 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
3122 2241e2b9 Iustin Pop

3123 2241e2b9 Iustin Pop
    - s: seconds
3124 2241e2b9 Iustin Pop
    - m: minutes
3125 2241e2b9 Iustin Pop
    - h: hours
3126 2241e2b9 Iustin Pop
    - d: day
3127 2241e2b9 Iustin Pop
    - w: weeks
3128 2241e2b9 Iustin Pop

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

3131 2241e2b9 Iustin Pop
  """
3132 2241e2b9 Iustin Pop
  value = str(value)
3133 2241e2b9 Iustin Pop
  if not value:
3134 2cfbc784 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed",
3135 2cfbc784 Iustin Pop
                               errors.ECODE_INVAL)
3136 2241e2b9 Iustin Pop
  suffix_map = {
3137 d0c8c01d Iustin Pop
    "s": 1,
3138 d0c8c01d Iustin Pop
    "m": 60,
3139 d0c8c01d Iustin Pop
    "h": 3600,
3140 d0c8c01d Iustin Pop
    "d": 86400,
3141 d0c8c01d Iustin Pop
    "w": 604800,
3142 2241e2b9 Iustin Pop
    }
3143 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
3144 2241e2b9 Iustin Pop
    try:
3145 2241e2b9 Iustin Pop
      value = int(value)
3146 691744c4 Iustin Pop
    except (TypeError, ValueError):
3147 2cfbc784 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value,
3148 2cfbc784 Iustin Pop
                                 errors.ECODE_INVAL)
3149 2241e2b9 Iustin Pop
  else:
3150 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
3151 2241e2b9 Iustin Pop
    value = value[:-1]
3152 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
3153 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
3154 2cfbc784 Iustin Pop
                                 " suffix passed)", errors.ECODE_INVAL)
3155 2241e2b9 Iustin Pop
    try:
3156 2241e2b9 Iustin Pop
      value = int(value) * multiplier
3157 691744c4 Iustin Pop
    except (TypeError, ValueError):
3158 2cfbc784 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value,
3159 2cfbc784 Iustin Pop
                                 errors.ECODE_INVAL)
3160 2241e2b9 Iustin Pop
  return value
3161 46fbdd04 Iustin Pop
3162 46fbdd04 Iustin Pop
3163 e9e26bb3 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False, secondary_ips=False,
3164 05484a24 Michael Hanselmann
                   filter_master=False, nodegroup=None):
3165 4040a784 Iustin Pop
  """Returns the names of online nodes.
3166 4040a784 Iustin Pop

3167 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
3168 4040a784 Iustin Pop
  the online nodes.
3169 4040a784 Iustin Pop

3170 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
3171 4040a784 Iustin Pop
      offline ones)
3172 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
3173 4040a784 Iustin Pop
  @type nowarn: boolean
3174 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
3175 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
3176 4040a784 Iustin Pop
      note is not displayed
3177 e9e26bb3 Iustin Pop
  @type secondary_ips: boolean
3178 e9e26bb3 Iustin Pop
  @param secondary_ips: if True, return the secondary IPs instead of the
3179 e9e26bb3 Iustin Pop
      names, useful for doing network traffic over the replication interface
3180 e9e26bb3 Iustin Pop
      (if any)
3181 e9e26bb3 Iustin Pop
  @type filter_master: boolean
3182 e9e26bb3 Iustin Pop
  @param filter_master: if True, do not return the master node in the list
3183 e9e26bb3 Iustin Pop
      (useful in coordination with secondary_ips where we cannot check our
3184 e9e26bb3 Iustin Pop
      node name against the list)
3185 05484a24 Michael Hanselmann
  @type nodegroup: string
3186 05484a24 Michael Hanselmann
  @param nodegroup: If set, only return nodes in this node group
3187 4040a784 Iustin Pop

3188 4040a784 Iustin Pop
  """
3189 4040a784 Iustin Pop
  if cl is None:
3190 4040a784 Iustin Pop
    cl = GetClient()
3191 4040a784 Iustin Pop
3192 2e5c33db Iustin Pop
  qfilter = []
3193 05484a24 Michael Hanselmann
3194 05484a24 Michael Hanselmann
  if nodes:
3195 2e5c33db Iustin Pop
    qfilter.append(qlang.MakeSimpleFilter("name", nodes))
3196 05484a24 Michael Hanselmann
3197 05484a24 Michael Hanselmann
  if nodegroup is not None:
3198 2e5c33db Iustin Pop
    qfilter.append([qlang.OP_OR, [qlang.OP_EQUAL, "group", nodegroup],
3199 05484a24 Michael Hanselmann
                                 [qlang.OP_EQUAL, "group.uuid", nodegroup]])
3200 e9e26bb3 Iustin Pop
3201 e9e26bb3 Iustin Pop
  if filter_master:
3202 2e5c33db Iustin Pop
    qfilter.append([qlang.OP_NOT, [qlang.OP_TRUE, "master"]])
3203 05484a24 Michael Hanselmann
3204 2e5c33db Iustin Pop
  if qfilter:
3205 2e5c33db Iustin Pop
    if len(qfilter) > 1:
3206 2e5c33db Iustin Pop
      final_filter = [qlang.OP_AND] + qfilter
3207 05484a24 Michael Hanselmann
    else:
3208 2e5c33db Iustin Pop
      assert len(qfilter) == 1
3209 2e5c33db Iustin Pop
      final_filter = qfilter[0]
3210 e9e26bb3 Iustin Pop
  else:
3211 05484a24 Michael Hanselmann
    final_filter = None
3212 05484a24 Michael Hanselmann
3213 05484a24 Michael Hanselmann
  result = cl.Query(constants.QR_NODE, ["name", "offline", "sip"], final_filter)
3214 05484a24 Michael Hanselmann
3215 05484a24 Michael Hanselmann
  def _IsOffline(row):
3216 05484a24 Michael Hanselmann
    (_, (_, offline), _) = row
3217 05484a24 Michael Hanselmann
    return offline
3218 05484a24 Michael Hanselmann
3219 05484a24 Michael Hanselmann
  def _GetName(row):
3220 05484a24 Michael Hanselmann
    ((_, name), _, _) = row
3221 05484a24 Michael Hanselmann
    return name
3222 05484a24 Michael Hanselmann
3223 05484a24 Michael Hanselmann
  def _GetSip(row):
3224 05484a24 Michael Hanselmann
    (_, _, (_, sip)) = row
3225 05484a24 Michael Hanselmann
    return sip
3226 05484a24 Michael Hanselmann
3227 05484a24 Michael Hanselmann
  (offline, online) = compat.partition(result.data, _IsOffline)
3228 e9e26bb3 Iustin Pop
3229 4040a784 Iustin Pop
  if offline and not nowarn:
3230 05484a24 Michael Hanselmann
    ToStderr("Note: skipping offline node(s): %s" %
3231 05484a24 Michael Hanselmann
             utils.CommaJoin(map(_GetName, offline)))
3232 05484a24 Michael Hanselmann
3233 05484a24 Michael Hanselmann
  if secondary_ips:
3234 05484a24 Michael Hanselmann
    fn = _GetSip
3235 05484a24 Michael Hanselmann
  else:
3236 05484a24 Michael Hanselmann
    fn = _GetName
3237 05484a24 Michael Hanselmann
3238 05484a24 Michael Hanselmann
  return map(fn, online)
3239 4040a784 Iustin Pop
3240 4040a784 Iustin Pop
3241 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
3242 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
3243 46fbdd04 Iustin Pop

3244 46fbdd04 Iustin Pop
  @type stream: file object
3245 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
3246 46fbdd04 Iustin Pop
  @type txt: str
3247 46fbdd04 Iustin Pop
  @param txt: the message
3248 46fbdd04 Iustin Pop

3249 46fbdd04 Iustin Pop
  """
3250 225e2544 Iustin Pop
  try:
3251 225e2544 Iustin Pop
    if args:
3252 225e2544 Iustin Pop
      args = tuple(args)
3253 225e2544 Iustin Pop
      stream.write(txt % args)
3254 225e2544 Iustin Pop
    else:
3255 225e2544 Iustin Pop
      stream.write(txt)
3256 d0c8c01d Iustin Pop
    stream.write("\n")
3257 225e2544 Iustin Pop
    stream.flush()
3258 225e2544 Iustin Pop
  except IOError, err:
3259 225e2544 Iustin Pop
    if err.errno == errno.EPIPE:
3260 225e2544 Iustin Pop
      # our terminal went away, we'll exit
3261 225e2544 Iustin Pop
      sys.exit(constants.EXIT_FAILURE)
3262 225e2544 Iustin Pop
    else:
3263 225e2544 Iustin Pop
      raise
3264 46fbdd04 Iustin Pop
3265 46fbdd04 Iustin Pop
3266 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
3267 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
3268 46fbdd04 Iustin Pop

3269 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
3270 46fbdd04 Iustin Pop

3271 46fbdd04 Iustin Pop
  @type txt: str
3272 46fbdd04 Iustin Pop
  @param txt: the message
3273 46fbdd04 Iustin Pop

3274 46fbdd04 Iustin Pop
  """
3275 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
3276 46fbdd04 Iustin Pop
3277 46fbdd04 Iustin Pop
3278 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
3279 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
3280 46fbdd04 Iustin Pop

3281 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
3282 46fbdd04 Iustin Pop

3283 46fbdd04 Iustin Pop
  @type txt: str
3284 46fbdd04 Iustin Pop
  @param txt: the message
3285 46fbdd04 Iustin Pop

3286 46fbdd04 Iustin Pop
  """
3287 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
3288 479636a3 Iustin Pop
3289 479636a3 Iustin Pop
3290 479636a3 Iustin Pop
class JobExecutor(object):
3291 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
3292 479636a3 Iustin Pop

3293 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
3294 479636a3 Iustin Pop
  GetResults() calls.
3295 479636a3 Iustin Pop

3296 479636a3 Iustin Pop
  """
3297 919ca415 Iustin Pop
  def __init__(self, cl=None, verbose=True, opts=None, feedback_fn=None):
3298 479636a3 Iustin Pop
    self.queue = []
3299 479636a3 Iustin Pop
    if cl is None:
3300 479636a3 Iustin Pop
      cl = GetClient()
3301 479636a3 Iustin Pop
    self.cl = cl
3302 479636a3 Iustin Pop
    self.verbose = verbose
3303 23b4b983 Iustin Pop
    self.jobs = []
3304 cff5fa7f Iustin Pop
    self.opts = opts
3305 919ca415 Iustin Pop
    self.feedback_fn = feedback_fn
3306 60452edf Michael Hanselmann
    self._counter = itertools.count()
3307 479636a3 Iustin Pop
3308 8d99a8bf Michael Hanselmann
  @staticmethod
3309 8d99a8bf Michael Hanselmann
  def _IfName(name, fmt):
3310 8d99a8bf Michael Hanselmann
    """Helper function for formatting name.
3311 8d99a8bf Michael Hanselmann

3312 8d99a8bf Michael Hanselmann
    """
3313 8d99a8bf Michael Hanselmann
    if name:
3314 8d99a8bf Michael Hanselmann
      return fmt % name
3315 8d99a8bf Michael Hanselmann
3316 8d99a8bf Michael Hanselmann
    return ""
3317 8d99a8bf Michael Hanselmann
3318 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
3319 23b4b983 Iustin Pop
    """Record a job for later submit.
3320 479636a3 Iustin Pop

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

3324 479636a3 Iustin Pop
    """
3325 cff5fa7f Iustin Pop
    SetGenericOpcodeOpts(ops, self.opts)
3326 60452edf Michael Hanselmann
    self.queue.append((self._counter.next(), name, ops))
3327 23b4b983 Iustin Pop
3328 8d99a8bf Michael Hanselmann
  def AddJobId(self, name, status, job_id):
3329 8d99a8bf Michael Hanselmann
    """Adds a job ID to the internal queue.
3330 8d99a8bf Michael Hanselmann

3331 8d99a8bf Michael Hanselmann
    """
3332 8d99a8bf Michael Hanselmann
    self.jobs.append((self._counter.next(), status, job_id, name))
3333 8d99a8bf Michael Hanselmann
3334 66ecc479 Guido Trotter
  def SubmitPending(self, each=False):
3335 23b4b983 Iustin Pop
    """Submit all pending jobs.
3336 23b4b983 Iustin Pop

3337 23b4b983 Iustin Pop
    """
3338 66ecc479 Guido Trotter
    if each:
3339 66ecc479 Guido Trotter
      results = []
3340 60452edf Michael Hanselmann
      for (_, _, ops) in self.queue:
3341 66ecc479 Guido Trotter
        # SubmitJob will remove the success status, but raise an exception if
3342 66ecc479 Guido Trotter
        # the submission fails, so we'll notice that anyway.
3343 519fafa1 Andrea Spadaccini
        results.append([True, self.cl.SubmitJob(ops)[0]])
3344 66ecc479 Guido Trotter
    else:
3345 60452edf Michael Hanselmann
      results = self.cl.SubmitManyJobs([ops for (_, _, ops) in self.queue])
3346 60452edf Michael Hanselmann
    for ((status, data), (idx, name, _)) in zip(results, self.queue):
3347 5299e61f Iustin Pop
      self.jobs.append((idx, status, data, name))
3348 5299e61f Iustin Pop
3349 5299e61f Iustin Pop
  def _ChooseJob(self):
3350 5299e61f Iustin Pop
    """Choose a non-waiting/queued job to poll next.
3351 5299e61f Iustin Pop

3352 5299e61f Iustin Pop
    """
3353 5299e61f Iustin Pop
    assert self.jobs, "_ChooseJob called with empty job list"
3354 5299e61f Iustin Pop
3355 11705e3d Iustin Pop
    result = self.cl.QueryJobs([i[2] for i in self.jobs[:_CHOOSE_BATCH]],
3356 11705e3d Iustin Pop
                               ["status"])
3357 5299e61f Iustin Pop
    assert result
3358 5299e61f Iustin Pop
3359 5299e61f Iustin Pop
    for job_data, status in zip(self.jobs, result):
3360 91c622a8 Iustin Pop
      if (isinstance(status, list) and status and
3361 91c622a8 Iustin Pop
          status[0] in (constants.JOB_STATUS_QUEUED,
3362 47099cd1 Michael Hanselmann
                        constants.JOB_STATUS_WAITING,
3363 91c622a8 Iustin Pop
                        constants.JOB_STATUS_CANCELING)):
3364 91c622a8 Iustin Pop
        # job is still present and waiting
3365 5299e61f Iustin Pop
        continue
3366 91c622a8 Iustin Pop
      # good candidate found (either running job or lost job)
3367 5299e61f Iustin Pop
      self.jobs.remove(job_data)
3368 5299e61f Iustin Pop
      return job_data
3369 5299e61f Iustin Pop
3370 5299e61f Iustin Pop
    # no job found
3371 5299e61f Iustin Pop
    return self.jobs.pop(0)
3372 479636a3 Iustin Pop
3373 479636a3 Iustin Pop
  def GetResults(self):
3374 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
3375 479636a3 Iustin Pop

3376 479636a3 Iustin Pop
    @rtype: list
3377 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
3378 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
3379 479636a3 Iustin Pop
        there will be the error message
3380 479636a3 Iustin Pop

3381 479636a3 Iustin Pop
    """
3382 23b4b983 Iustin Pop
    if not self.jobs:
3383 23b4b983 Iustin Pop
      self.SubmitPending()
3384 479636a3 Iustin Pop
    results = []
3385 479636a3 Iustin Pop
    if self.verbose:
3386 5299e61f Iustin Pop
      ok_jobs = [row[2] for row in self.jobs if row[1]]
3387 23b4b983 Iustin Pop
      if ok_jobs:
3388 4474f112 Iustin Pop
        ToStdout("Submitted jobs %s", utils.CommaJoin(ok_jobs))
3389 5299e61f Iustin Pop
3390 5299e61f Iustin Pop
    # first, remove any non-submitted jobs
3391 cea881e5 Michael Hanselmann
    self.jobs, failures = compat.partition(self.jobs, lambda x: x[1])
3392 5299e61f Iustin Pop
    for idx, _, jid, name in failures:
3393 4474f112 Iustin Pop
      ToStderr("Failed to submit job%s: %s", self._IfName(name, " for %s"), jid)
3394 c63355f2 Iustin Pop
      results.append((idx, False, jid))
3395 5299e61f Iustin Pop
3396 5299e61f Iustin Pop
    while self.jobs:
3397 5299e61f Iustin Pop
      (idx, _, jid, name) = self._ChooseJob()
3398 4474f112 Iustin Pop
      ToStdout("Waiting for job %s%s ...", jid, self._IfName(name, " for %s"))
3399 479636a3 Iustin Pop
      try:
3400 919ca415 Iustin Pop
        job_result = PollJob(jid, cl=self.cl, feedback_fn=self.feedback_fn)
3401 479636a3 Iustin Pop
        success = True
3402 91c622a8 Iustin Pop
      except errors.JobLost, err:
3403 91c622a8 Iustin Pop
        _, job_result = FormatError(err)
3404 4474f112 Iustin Pop
        ToStderr("Job %s%s has been archived, cannot check its result",
3405 4474f112 Iustin Pop
                 jid, self._IfName(name, " for %s"))
3406 91c622a8 Iustin Pop
        success = False
3407 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
3408 479636a3 Iustin Pop
        _, job_result = FormatError(err)
3409 479636a3 Iustin Pop
        success = False
3410 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
3411 4474f112 Iustin Pop
        ToStderr("Job %s%s has failed: %s",
3412 4474f112 Iustin Pop
                 jid, self._IfName(name, " for %s"), job_result)
3413 479636a3 Iustin Pop
3414 5299e61f Iustin Pop
      results.append((idx, success, job_result))
3415 5299e61f Iustin Pop
3416 5299e61f Iustin Pop
    # sort based on the index, then drop it
3417 5299e61f Iustin Pop
    results.sort()
3418 5299e61f Iustin Pop
    results = [i[1:] for i in results]
3419 5299e61f Iustin Pop
3420 479636a3 Iustin Pop
    return results
3421 479636a3 Iustin Pop
3422 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
3423 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
3424 479636a3 Iustin Pop

3425 479636a3 Iustin Pop
    @type wait: boolean
3426 479636a3 Iustin Pop
    @param wait: whether to wait or not
3427 479636a3 Iustin Pop

3428 479636a3 Iustin Pop
    """
3429 479636a3 Iustin Pop
    if wait:
3430 479636a3 Iustin Pop
      return self.GetResults()
3431 479636a3 Iustin Pop
    else:
3432 23b4b983 Iustin Pop
      if not self.jobs:
3433 23b4b983 Iustin Pop
        self.SubmitPending()
3434 71834b2a Guido Trotter
      for _, status, result, name in self.jobs:
3435 23b4b983 Iustin Pop
        if status:
3436 4474f112 Iustin Pop
          ToStdout("%s: %s", result, name)
3437 23b4b983 Iustin Pop
        else:
3438 4474f112 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)
3439 53a8a54d Iustin Pop
      return [row[1:3] for row in self.jobs]
3440 acd19189 René Nussbaumer
3441 acd19189 René Nussbaumer
3442 acd19189 René Nussbaumer
def FormatParameterDict(buf, param_dict, actual, level=1):
3443 acd19189 René Nussbaumer
  """Formats a parameter dictionary.
3444 acd19189 René Nussbaumer

3445 acd19189 René Nussbaumer
  @type buf: L{StringIO}
3446 acd19189 René Nussbaumer
  @param buf: the buffer into which to write
3447 acd19189 René Nussbaumer
  @type param_dict: dict
3448 acd19189 René Nussbaumer
  @param param_dict: the own parameters
3449 acd19189 René Nussbaumer
  @type actual: dict
3450 acd19189 René Nussbaumer
  @param actual: the current parameter set (including defaults)
3451 acd19189 René Nussbaumer
  @param level: Level of indent
3452 acd19189 René Nussbaumer

3453 acd19189 René Nussbaumer
  """
3454 acd19189 René Nussbaumer
  indent = "  " * level
3455 64da5a53 René Nussbaumer
3456 acd19189 René Nussbaumer
  for key in sorted(actual):
3457 64da5a53 René Nussbaumer
    data = actual[key]
3458 64da5a53 René Nussbaumer
    buf.write("%s- %s:" % (indent, key))
3459 64da5a53 René Nussbaumer
3460 64da5a53 René Nussbaumer
    if isinstance(data, dict) and data:
3461 64da5a53 René Nussbaumer
      buf.write("\n")
3462 64da5a53 René Nussbaumer
      FormatParameterDict(buf, param_dict.get(key, {}), data,
3463 64da5a53 René Nussbaumer
                          level=level + 1)
3464 64da5a53 René Nussbaumer
    else:
3465 64da5a53 René Nussbaumer
      val = param_dict.get(key, "default (%s)" % data)
3466 64da5a53 René Nussbaumer
      buf.write(" %s\n" % val)
3467 25bd815c René Nussbaumer
3468 25bd815c René Nussbaumer
3469 25bd815c René Nussbaumer
def ConfirmOperation(names, list_type, text, extra=""):
3470 25bd815c René Nussbaumer
  """Ask the user to confirm an operation on a list of list_type.
3471 25bd815c René Nussbaumer

3472 25bd815c René Nussbaumer
  This function is used to request confirmation for doing an operation
3473 25bd815c René Nussbaumer
  on a given list of list_type.
3474 25bd815c René Nussbaumer

3475 25bd815c René Nussbaumer
  @type names: list
3476 25bd815c René Nussbaumer
  @param names: the list of names that we display when
3477 25bd815c René Nussbaumer
      we ask for confirmation
3478 25bd815c René Nussbaumer
  @type list_type: str
3479 25bd815c René Nussbaumer
  @param list_type: Human readable name for elements in the list (e.g. nodes)
3480 25bd815c René Nussbaumer
  @type text: str
3481 25bd815c René Nussbaumer
  @param text: the operation that the user should confirm
3482 25bd815c René Nussbaumer
  @rtype: boolean
3483 25bd815c René Nussbaumer
  @return: True or False depending on user's confirmation.
3484 25bd815c René Nussbaumer

3485 25bd815c René Nussbaumer
  """
3486 25bd815c René Nussbaumer
  count = len(names)
3487 25bd815c René Nussbaumer
  msg = ("The %s will operate on %d %s.\n%s"
3488 25bd815c René Nussbaumer
         "Do you want to continue?" % (text, count, list_type, extra))
3489 25bd815c René Nussbaumer
  affected = (("\nAffected %s:\n" % list_type) +
3490 25bd815c René Nussbaumer
              "\n".join(["  %s" % name for name in names]))
3491 25bd815c René Nussbaumer
3492 25bd815c René Nussbaumer
  choices = [("y", True, "Yes, execute the %s" % text),
3493 25bd815c René Nussbaumer
             ("n", False, "No, abort the %s" % text)]
3494 25bd815c René Nussbaumer
3495 25bd815c René Nussbaumer
  if count > 20:
3496 25bd815c René Nussbaumer
    choices.insert(1, ("v", "v", "View the list of affected %s" % list_type))
3497 25bd815c René Nussbaumer
    question = msg
3498 25bd815c René Nussbaumer
  else:
3499 25bd815c René Nussbaumer
    question = msg + affected
3500 25bd815c René Nussbaumer
3501 25bd815c René Nussbaumer
  choice = AskUser(question, choices)
3502 25bd815c René Nussbaumer
  if choice == "v":
3503 25bd815c René Nussbaumer
    choices.pop(1)
3504 25bd815c René Nussbaumer
    choice = AskUser(msg + affected, choices)
3505 25bd815c René Nussbaumer
  return choice
3506 703fa9ab Iustin Pop
3507 703fa9ab Iustin Pop
3508 cd415612 René Nussbaumer
def _MaybeParseUnit(elements):
3509 cd415612 René Nussbaumer
  """Parses and returns an array of potential values with units.
3510 cd415612 René Nussbaumer

3511 cd415612 René Nussbaumer
  """
3512 ef40c537 René Nussbaumer
  parsed = {}
3513 ef40c537 René Nussbaumer
  for k, v in elements.items():
3514 ef40c537 René Nussbaumer
    if v == constants.VALUE_DEFAULT:
3515 ef40c537 René Nussbaumer
      parsed[k] = v
3516 cd415612 René Nussbaumer
    else:
3517 ef40c537 René Nussbaumer
      parsed[k] = utils.ParseUnit(v)
3518 cd415612 René Nussbaumer
  return parsed
3519 cd415612 René Nussbaumer
3520 cd415612 René Nussbaumer
3521 703fa9ab Iustin Pop
def CreateIPolicyFromOpts(ispecs_mem_size=None,
3522 703fa9ab Iustin Pop
                          ispecs_cpu_count=None,
3523 703fa9ab Iustin Pop
                          ispecs_disk_count=None,
3524 703fa9ab Iustin Pop
                          ispecs_disk_size=None,
3525 703fa9ab Iustin Pop
                          ispecs_nic_count=None,
3526 703fa9ab Iustin Pop
                          ipolicy_disk_templates=None,
3527 703fa9ab Iustin Pop
                          ipolicy_vcpu_ratio=None,
3528 ad5cc6bd René Nussbaumer
                          ipolicy_spindle_ratio=None,
3529 703fa9ab Iustin Pop
                          group_ipolicy=False,
3530 703fa9ab Iustin Pop
                          allowed_values=None,
3531 703fa9ab Iustin Pop
                          fill_all=False):
3532 703fa9ab Iustin Pop
  """Creation of instance policy based on command line options.
3533 703fa9ab Iustin Pop

3534 703fa9ab Iustin Pop
  @param fill_all: whether for cluster policies we should ensure that
3535 703fa9ab Iustin Pop
    all values are filled
3536 703fa9ab Iustin Pop

3537 703fa9ab Iustin Pop

3538 703fa9ab Iustin Pop
  """
3539 d67e0a94 Iustin Pop
  try:
3540 d67e0a94 Iustin Pop
    if ispecs_mem_size:
3541 cd415612 René Nussbaumer
      ispecs_mem_size = _MaybeParseUnit(ispecs_mem_size)
3542 d67e0a94 Iustin Pop
    if ispecs_disk_size:
3543 cd415612 René Nussbaumer
      ispecs_disk_size = _MaybeParseUnit(ispecs_disk_size)
3544 d67e0a94 Iustin Pop
  except (TypeError, ValueError, errors.UnitParseError), err:
3545 d67e0a94 Iustin Pop
    raise errors.OpPrereqError("Invalid disk (%s) or memory (%s) size"
3546 d67e0a94 Iustin Pop
                               " in policy: %s" %
3547 d67e0a94 Iustin Pop
                               (ispecs_disk_size, ispecs_mem_size, err),
3548 d67e0a94 Iustin Pop
                               errors.ECODE_INVAL)
3549 d67e0a94 Iustin Pop
3550 703fa9ab Iustin Pop
  # prepare ipolicy dict
3551 703fa9ab Iustin Pop
  ipolicy_transposed = {
3552 703fa9ab Iustin Pop
    constants.ISPEC_MEM_SIZE: ispecs_mem_size,
3553 703fa9ab Iustin Pop
    constants.ISPEC_CPU_COUNT: ispecs_cpu_count,
3554 703fa9ab Iustin Pop
    constants.ISPEC_DISK_COUNT: ispecs_disk_count,
3555 703fa9ab Iustin Pop
    constants.ISPEC_DISK_SIZE: ispecs_disk_size,
3556 703fa9ab Iustin Pop
    constants.ISPEC_NIC_COUNT: ispecs_nic_count,
3557 703fa9ab Iustin Pop
    }
3558 703fa9ab Iustin Pop
3559 703fa9ab Iustin Pop
  # first, check that the values given are correct
3560 703fa9ab Iustin Pop
  if group_ipolicy:
3561 703fa9ab Iustin Pop
    forced_type = TISPECS_GROUP_TYPES
3562 703fa9ab Iustin Pop
  else:
3563 703fa9ab Iustin Pop
    forced_type = TISPECS_CLUSTER_TYPES
3564 703fa9ab Iustin Pop
3565 703fa9ab Iustin Pop
  for specs in ipolicy_transposed.values():
3566 703fa9ab Iustin Pop
    utils.ForceDictType(specs, forced_type, allowed_values=allowed_values)
3567 703fa9ab Iustin Pop
3568 703fa9ab Iustin Pop
  # then transpose
3569 703fa9ab Iustin Pop
  ipolicy_out = objects.MakeEmptyIPolicy()
3570 703fa9ab Iustin Pop
  for name, specs in ipolicy_transposed.iteritems():
3571 703fa9ab Iustin Pop
    assert name in constants.ISPECS_PARAMETERS
3572 703fa9ab Iustin Pop
    for key, val in specs.items(): # {min: .. ,max: .., std: ..}
3573 703fa9ab Iustin Pop
      ipolicy_out[key][name] = val
3574 703fa9ab Iustin Pop
3575 703fa9ab Iustin Pop
  # no filldict for non-dicts
3576 703fa9ab Iustin Pop
  if not group_ipolicy and fill_all:
3577 703fa9ab Iustin Pop
    if ipolicy_disk_templates is None:
3578 703fa9ab Iustin Pop
      ipolicy_disk_templates = constants.DISK_TEMPLATES
3579 703fa9ab Iustin Pop
    if ipolicy_vcpu_ratio is None:
3580 703fa9ab Iustin Pop
      ipolicy_vcpu_ratio = \
3581 703fa9ab Iustin Pop
        constants.IPOLICY_DEFAULTS[constants.IPOLICY_VCPU_RATIO]
3582 ad5cc6bd René Nussbaumer
    if ipolicy_spindle_ratio is None:
3583 ad5cc6bd René Nussbaumer
      ipolicy_spindle_ratio = \
3584 ad5cc6bd René Nussbaumer
        constants.IPOLICY_DEFAULTS[constants.IPOLICY_SPINDLE_RATIO]
3585 703fa9ab Iustin Pop
  if ipolicy_disk_templates is not None:
3586 703fa9ab Iustin Pop
    ipolicy_out[constants.IPOLICY_DTS] = list(ipolicy_disk_templates)
3587 703fa9ab Iustin Pop
  if ipolicy_vcpu_ratio is not None:
3588 703fa9ab Iustin Pop
    ipolicy_out[constants.IPOLICY_VCPU_RATIO] = ipolicy_vcpu_ratio
3589 ad5cc6bd René Nussbaumer
  if ipolicy_spindle_ratio is not None:
3590 ad5cc6bd René Nussbaumer
    ipolicy_out[constants.IPOLICY_SPINDLE_RATIO] = ipolicy_spindle_ratio
3591 703fa9ab Iustin Pop
3592 703fa9ab Iustin Pop
  assert not (frozenset(ipolicy_out.keys()) - constants.IPOLICY_ALL_KEYS)
3593 703fa9ab Iustin Pop
3594 703fa9ab Iustin Pop
  return ipolicy_out