Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ 858905fb

History | View | Annotate | Download (77 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 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 73702ee7 Iustin Pop
from cStringIO import StringIO
31 a8083063 Iustin Pop
32 a8083063 Iustin Pop
from ganeti import utils
33 a8083063 Iustin Pop
from ganeti import errors
34 a8083063 Iustin Pop
from ganeti import constants
35 846baef9 Iustin Pop
from ganeti import opcodes
36 ceab32dd Iustin Pop
from ganeti import luxi
37 b33e986b Iustin Pop
from ganeti import ssconf
38 4331f6cd Michael Hanselmann
from ganeti import rpc
39 7e49b6ce Michael Hanselmann
from ganeti import ssh
40 cea881e5 Michael Hanselmann
from ganeti import compat
41 a744b676 Manuel Franceschini
from ganeti import netutils
42 a8083063 Iustin Pop
43 c38c44ad Michael Hanselmann
from optparse import (OptionParser, TitledHelpFormatter,
44 38206f3c Iustin Pop
                      Option, OptionValueError)
45 a8083063 Iustin Pop
46 03298ebe Michael Hanselmann
47 4abc4f1e Iustin Pop
__all__ = [
48 4abc4f1e Iustin Pop
  # Command line options
49 fdad8c4d Balazs Lecz
  "ADD_UIDS_OPT",
50 e7e09483 Iustin Pop
  "ALLOCATABLE_OPT",
51 2d5e7ae1 Iustin Pop
  "ALL_OPT",
52 4c61d894 Iustin Pop
  "AUTO_PROMOTE_OPT",
53 e00f7a05 Iustin Pop
  "AUTO_REPLACE_OPT",
54 087ed2ed Iustin Pop
  "BACKEND_OPT",
55 baef337d Iustin Pop
  "CLEANUP_OPT",
56 3db3eb2a Michael Hanselmann
  "CLUSTER_DOMAIN_SECRET_OPT",
57 4abc4f1e Iustin Pop
  "CONFIRM_OPT",
58 e32df528 Iustin Pop
  "CP_SIZE_OPT",
59 4abc4f1e Iustin Pop
  "DEBUG_OPT",
60 a0c9776a Iustin Pop
  "DEBUG_SIMERR_OPT",
61 4b038a1e Iustin Pop
  "DISKIDX_OPT",
62 e3876ccb Iustin Pop
  "DISK_OPT",
63 4b038a1e Iustin Pop
  "DISK_TEMPLATE_OPT",
64 771734c9 Iustin Pop
  "DRAINED_OPT",
65 26591bfd Luca Bigliardi
  "DRBD_HELPER_OPT",
66 7ea7bcf6 Iustin Pop
  "EARLY_RELEASE_OPT",
67 383a3591 Iustin Pop
  "ENABLED_HV_OPT",
68 14e9e7f3 Iustin Pop
  "ERROR_CODES_OPT",
69 4abc4f1e Iustin Pop
  "FIELDS_OPT",
70 4a25828c Iustin Pop
  "FILESTORE_DIR_OPT",
71 0f87c43e Iustin Pop
  "FILESTORE_DRIVER_OPT",
72 06073e85 Guido Trotter
  "FORCE_OPT",
73 06073e85 Guido Trotter
  "FORCE_VARIANT_OPT",
74 29392516 Iustin Pop
  "GLOBAL_FILEDIR_OPT",
75 073271f6 Iustin Pop
  "HVLIST_OPT",
76 48f212d7 Iustin Pop
  "HVOPTS_OPT",
77 236fd9c4 Iustin Pop
  "HYPERVISOR_OPT",
78 4eb62659 Iustin Pop
  "IALLOCATOR_OPT",
79 bf4af505 Apollon Oikonomopoulos
  "DEFAULT_IALLOCATOR_OPT",
80 e588764d Iustin Pop
  "IDENTIFY_DEFAULTS_OPT",
81 82a786d5 Iustin Pop
  "IGNORE_CONSIST_OPT",
82 b6e841a8 Iustin Pop
  "IGNORE_FAILURES_OPT",
83 8d8d650c Michael Hanselmann
  "IGNORE_REMOVE_FAILURES_OPT",
84 ee3f9578 Iustin Pop
  "IGNORE_SECONDARIES_OPT",
85 05586c90 Iustin Pop
  "IGNORE_SIZE_OPT",
86 e3646f22 Iustin Pop
  "MAC_PREFIX_OPT",
87 3953242f Iustin Pop
  "MAINTAIN_NODE_HEALTH_OPT",
88 29392516 Iustin Pop
  "MASTER_NETDEV_OPT",
89 771734c9 Iustin Pop
  "MC_OPT",
90 7d3a9fab Iustin Pop
  "NET_OPT",
91 6d4a1656 Michael Hanselmann
  "NEW_CLUSTER_CERT_OPT",
92 3db3eb2a Michael Hanselmann
  "NEW_CLUSTER_DOMAIN_SECRET_OPT",
93 6b7d5878 Michael Hanselmann
  "NEW_CONFD_HMAC_KEY_OPT",
94 6d4a1656 Michael Hanselmann
  "NEW_RAPI_CERT_OPT",
95 a14db5ff Iustin Pop
  "NEW_SECONDARY_OPT",
96 4fbc93dd Iustin Pop
  "NIC_PARAMS_OPT",
97 7edc4637 Iustin Pop
  "NODE_LIST_OPT",
98 990b7886 Iustin Pop
  "NODE_PLACEMENT_OPT",
99 26591bfd Luca Bigliardi
  "NODRBD_STORAGE_OPT",
100 4abc4f1e Iustin Pop
  "NOHDR_OPT",
101 91e0748c Iustin Pop
  "NOIPCHECK_OPT",
102 25a8792c Iustin Pop
  "NO_INSTALL_OPT",
103 460d22be Iustin Pop
  "NONAMECHECK_OPT",
104 831040bf Iustin Pop
  "NOLVM_STORAGE_OPT",
105 29392516 Iustin Pop
  "NOMODIFY_ETCHOSTS_OPT",
106 b989b9d9 Ken Wehr
  "NOMODIFY_SSH_SETUP_OPT",
107 26023ecd Iustin Pop
  "NONICS_OPT",
108 f2a0828c Iustin Pop
  "NONLIVE_OPT",
109 14e9e7f3 Iustin Pop
  "NONPLUS1_OPT",
110 44c44832 Iustin Pop
  "NOSHUTDOWN_OPT",
111 edeb878a Iustin Pop
  "NOSTART_OPT",
112 fcdde7f2 Iustin Pop
  "NOSSH_KEYCHECK_OPT",
113 58371861 Iustin Pop
  "NOVOTING_OPT",
114 3f75b4f3 Iustin Pop
  "NWSYNC_OPT",
115 a72d0a79 Iustin Pop
  "ON_PRIMARY_OPT",
116 feb09e6a Iustin Pop
  "ON_SECONDARY_OPT",
117 771734c9 Iustin Pop
  "OFFLINE_OPT",
118 062a7100 Iustin Pop
  "OSPARAMS_OPT",
119 d3ed23ff Iustin Pop
  "OS_OPT",
120 ff00c1a7 Iustin Pop
  "OS_SIZE_OPT",
121 6d4a1656 Michael Hanselmann
  "RAPI_CERT_OPT",
122 b8d0f938 Iustin Pop
  "READD_OPT",
123 12054861 Iustin Pop
  "REBOOT_TYPE_OPT",
124 8d8d650c Michael Hanselmann
  "REMOVE_INSTANCE_OPT",
125 fdad8c4d Balazs Lecz
  "REMOVE_UIDS_OPT",
126 31d97b2a Guido Trotter
  "ROMAN_OPT",
127 8d823629 Iustin Pop
  "SECONDARY_IP_OPT",
128 67840b40 Iustin Pop
  "SELECT_OS_OPT",
129 4abc4f1e Iustin Pop
  "SEP_OPT",
130 fdcf4d84 Iustin Pop
  "SHOWCMD_OPT",
131 7e5eaaa8 Guido Trotter
  "SHUTDOWN_TIMEOUT_OPT",
132 f36d7d81 Iustin Pop
  "SINGLE_NODE_OPT",
133 df62e5db Iustin Pop
  "SRC_DIR_OPT",
134 df62e5db Iustin Pop
  "SRC_NODE_OPT",
135 4abc4f1e Iustin Pop
  "SUBMIT_OPT",
136 99a8c799 Iustin Pop
  "STATIC_OPT",
137 4abc4f1e Iustin Pop
  "SYNC_OPT",
138 4abc4f1e Iustin Pop
  "TAG_SRC_OPT",
139 b5762e2a Guido Trotter
  "TIMEOUT_OPT",
140 1338f2b4 Balazs Lecz
  "UIDPOOL_OPT",
141 4abc4f1e Iustin Pop
  "USEUNITS_OPT",
142 74adc100 Iustin Pop
  "USE_REPL_NET_OPT",
143 9cdb9578 Iustin Pop
  "VERBOSE_OPT",
144 b58726e8 Iustin Pop
  "VG_NAME_OPT",
145 1f587d3d Iustin Pop
  "YES_DOIT_OPT",
146 4abc4f1e Iustin Pop
  # Generic functions for CLI programs
147 4abc4f1e Iustin Pop
  "GenericMain",
148 d77490c5 Iustin Pop
  "GenericInstanceCreate",
149 4abc4f1e Iustin Pop
  "GetClient",
150 4abc4f1e Iustin Pop
  "GetOnlineNodes",
151 4abc4f1e Iustin Pop
  "JobExecutor",
152 4abc4f1e Iustin Pop
  "JobSubmittedException",
153 4abc4f1e Iustin Pop
  "ParseTimespec",
154 7e49b6ce Michael Hanselmann
  "RunWhileClusterStopped",
155 4abc4f1e Iustin Pop
  "SubmitOpCode",
156 4abc4f1e Iustin Pop
  "SubmitOrSend",
157 4abc4f1e Iustin Pop
  "UsesRPC",
158 4abc4f1e Iustin Pop
  # Formatting functions
159 4abc4f1e Iustin Pop
  "ToStderr", "ToStdout",
160 4abc4f1e Iustin Pop
  "FormatError",
161 4abc4f1e Iustin Pop
  "GenerateTable",
162 4abc4f1e Iustin Pop
  "AskUser",
163 4abc4f1e Iustin Pop
  "FormatTimestamp",
164 8a7f1c61 Michael Hanselmann
  "FormatLogMessage",
165 4abc4f1e Iustin Pop
  # Tags functions
166 4abc4f1e Iustin Pop
  "ListTags",
167 4abc4f1e Iustin Pop
  "AddTags",
168 4abc4f1e Iustin Pop
  "RemoveTags",
169 4abc4f1e Iustin Pop
  # command line options support infrastructure
170 4abc4f1e Iustin Pop
  "ARGS_MANY_INSTANCES",
171 4abc4f1e Iustin Pop
  "ARGS_MANY_NODES",
172 4abc4f1e Iustin Pop
  "ARGS_NONE",
173 4abc4f1e Iustin Pop
  "ARGS_ONE_INSTANCE",
174 4abc4f1e Iustin Pop
  "ARGS_ONE_NODE",
175 f9faf9c3 Renรฉ Nussbaumer
  "ARGS_ONE_OS",
176 4abc4f1e Iustin Pop
  "ArgChoice",
177 4abc4f1e Iustin Pop
  "ArgCommand",
178 4abc4f1e Iustin Pop
  "ArgFile",
179 4abc4f1e Iustin Pop
  "ArgHost",
180 4abc4f1e Iustin Pop
  "ArgInstance",
181 4abc4f1e Iustin Pop
  "ArgJobId",
182 4abc4f1e Iustin Pop
  "ArgNode",
183 f9faf9c3 Renรฉ Nussbaumer
  "ArgOs",
184 4abc4f1e Iustin Pop
  "ArgSuggest",
185 4abc4f1e Iustin Pop
  "ArgUnknown",
186 4abc4f1e Iustin Pop
  "OPT_COMPL_INST_ADD_NODES",
187 4abc4f1e Iustin Pop
  "OPT_COMPL_MANY_NODES",
188 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_IALLOCATOR",
189 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_INSTANCE",
190 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_NODE",
191 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_OS",
192 4abc4f1e Iustin Pop
  "cli_option",
193 4abc4f1e Iustin Pop
  "SplitNodeOption",
194 07150497 Guido Trotter
  "CalculateOSNames",
195 4abc4f1e Iustin Pop
  ]
196 846baef9 Iustin Pop
197 8b46606c Guido Trotter
NO_PREFIX = "no_"
198 8b46606c Guido Trotter
UN_PREFIX = "-"
199 846baef9 Iustin Pop
200 03298ebe Michael Hanselmann
201 863d7f46 Michael Hanselmann
class _Argument:
202 7260cfbe Iustin Pop
  def __init__(self, min=0, max=None): # pylint: disable-msg=W0622
203 863d7f46 Michael Hanselmann
    self.min = min
204 863d7f46 Michael Hanselmann
    self.max = max
205 863d7f46 Michael Hanselmann
206 863d7f46 Michael Hanselmann
  def __repr__(self):
207 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s>" %
208 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max))
209 863d7f46 Michael Hanselmann
210 863d7f46 Michael Hanselmann
211 863d7f46 Michael Hanselmann
class ArgSuggest(_Argument):
212 863d7f46 Michael Hanselmann
  """Suggesting argument.
213 863d7f46 Michael Hanselmann

214 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor.
215 863d7f46 Michael Hanselmann

216 863d7f46 Michael Hanselmann
  """
217 7260cfbe Iustin Pop
  # pylint: disable-msg=W0622
218 863d7f46 Michael Hanselmann
  def __init__(self, min=0, max=None, choices=None):
219 863d7f46 Michael Hanselmann
    _Argument.__init__(self, min=min, max=max)
220 863d7f46 Michael Hanselmann
    self.choices = choices
221 863d7f46 Michael Hanselmann
222 863d7f46 Michael Hanselmann
  def __repr__(self):
223 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s choices=%r>" %
224 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max, self.choices))
225 863d7f46 Michael Hanselmann
226 863d7f46 Michael Hanselmann
227 863d7f46 Michael Hanselmann
class ArgChoice(ArgSuggest):
228 863d7f46 Michael Hanselmann
  """Choice argument.
229 863d7f46 Michael Hanselmann

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

233 863d7f46 Michael Hanselmann
  """
234 863d7f46 Michael Hanselmann
235 863d7f46 Michael Hanselmann
236 863d7f46 Michael Hanselmann
class ArgUnknown(_Argument):
237 863d7f46 Michael Hanselmann
  """Unknown argument to program (e.g. determined at runtime).
238 863d7f46 Michael Hanselmann

239 863d7f46 Michael Hanselmann
  """
240 863d7f46 Michael Hanselmann
241 863d7f46 Michael Hanselmann
242 863d7f46 Michael Hanselmann
class ArgInstance(_Argument):
243 863d7f46 Michael Hanselmann
  """Instances argument.
244 863d7f46 Michael Hanselmann

245 863d7f46 Michael Hanselmann
  """
246 863d7f46 Michael Hanselmann
247 863d7f46 Michael Hanselmann
248 863d7f46 Michael Hanselmann
class ArgNode(_Argument):
249 863d7f46 Michael Hanselmann
  """Node argument.
250 863d7f46 Michael Hanselmann

251 863d7f46 Michael Hanselmann
  """
252 863d7f46 Michael Hanselmann
253 863d7f46 Michael Hanselmann
class ArgJobId(_Argument):
254 863d7f46 Michael Hanselmann
  """Job ID argument.
255 863d7f46 Michael Hanselmann

256 863d7f46 Michael Hanselmann
  """
257 863d7f46 Michael Hanselmann
258 863d7f46 Michael Hanselmann
259 863d7f46 Michael Hanselmann
class ArgFile(_Argument):
260 863d7f46 Michael Hanselmann
  """File path argument.
261 863d7f46 Michael Hanselmann

262 863d7f46 Michael Hanselmann
  """
263 863d7f46 Michael Hanselmann
264 863d7f46 Michael Hanselmann
265 863d7f46 Michael Hanselmann
class ArgCommand(_Argument):
266 863d7f46 Michael Hanselmann
  """Command argument.
267 863d7f46 Michael Hanselmann

268 863d7f46 Michael Hanselmann
  """
269 863d7f46 Michael Hanselmann
270 863d7f46 Michael Hanselmann
271 83ec7961 Michael Hanselmann
class ArgHost(_Argument):
272 83ec7961 Michael Hanselmann
  """Host argument.
273 83ec7961 Michael Hanselmann

274 83ec7961 Michael Hanselmann
  """
275 83ec7961 Michael Hanselmann
276 83ec7961 Michael Hanselmann
277 f9faf9c3 Renรฉ Nussbaumer
class ArgOs(_Argument):
278 f9faf9c3 Renรฉ Nussbaumer
  """OS argument.
279 f9faf9c3 Renรฉ Nussbaumer

280 f9faf9c3 Renรฉ Nussbaumer
  """
281 f9faf9c3 Renรฉ Nussbaumer
282 f9faf9c3 Renรฉ Nussbaumer
283 4a265c08 Michael Hanselmann
ARGS_NONE = []
284 4a265c08 Michael Hanselmann
ARGS_MANY_INSTANCES = [ArgInstance()]
285 4a265c08 Michael Hanselmann
ARGS_MANY_NODES = [ArgNode()]
286 4a265c08 Michael Hanselmann
ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
287 4a265c08 Michael Hanselmann
ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
288 f9faf9c3 Renรฉ Nussbaumer
ARGS_ONE_OS = [ArgOs(min=1, max=1)]
289 4a265c08 Michael Hanselmann
290 4a265c08 Michael Hanselmann
291 846baef9 Iustin Pop
def _ExtractTagsObject(opts, args):
292 846baef9 Iustin Pop
  """Extract the tag type object.
293 846baef9 Iustin Pop

294 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
295 846baef9 Iustin Pop

296 846baef9 Iustin Pop
  """
297 846baef9 Iustin Pop
  if not hasattr(opts, "tag_type"):
298 846baef9 Iustin Pop
    raise errors.ProgrammerError("tag_type not passed to _ExtractTagsObject")
299 846baef9 Iustin Pop
  kind = opts.tag_type
300 846baef9 Iustin Pop
  if kind == constants.TAG_CLUSTER:
301 846baef9 Iustin Pop
    retval = kind, kind
302 846baef9 Iustin Pop
  elif kind == constants.TAG_NODE or kind == constants.TAG_INSTANCE:
303 846baef9 Iustin Pop
    if not args:
304 0c434948 Iustin Pop
      raise errors.OpPrereqError("no arguments passed to the command")
305 846baef9 Iustin Pop
    name = args.pop(0)
306 846baef9 Iustin Pop
    retval = kind, name
307 846baef9 Iustin Pop
  else:
308 846baef9 Iustin Pop
    raise errors.ProgrammerError("Unhandled tag type '%s'" % kind)
309 846baef9 Iustin Pop
  return retval
310 846baef9 Iustin Pop
311 846baef9 Iustin Pop
312 810c50b7 Iustin Pop
def _ExtendTags(opts, args):
313 810c50b7 Iustin Pop
  """Extend the args if a source file has been given.
314 810c50b7 Iustin Pop

315 810c50b7 Iustin Pop
  This function will extend the tags with the contents of the file
316 810c50b7 Iustin Pop
  passed in the 'tags_source' attribute of the opts parameter. A file
317 810c50b7 Iustin Pop
  named '-' will be replaced by stdin.
318 810c50b7 Iustin Pop

319 810c50b7 Iustin Pop
  """
320 810c50b7 Iustin Pop
  fname = opts.tags_source
321 810c50b7 Iustin Pop
  if fname is None:
322 810c50b7 Iustin Pop
    return
323 810c50b7 Iustin Pop
  if fname == "-":
324 810c50b7 Iustin Pop
    new_fh = sys.stdin
325 810c50b7 Iustin Pop
  else:
326 810c50b7 Iustin Pop
    new_fh = open(fname, "r")
327 810c50b7 Iustin Pop
  new_data = []
328 810c50b7 Iustin Pop
  try:
329 810c50b7 Iustin Pop
    # we don't use the nice 'new_data = [line.strip() for line in fh]'
330 810c50b7 Iustin Pop
    # because of python bug 1633941
331 810c50b7 Iustin Pop
    while True:
332 810c50b7 Iustin Pop
      line = new_fh.readline()
333 810c50b7 Iustin Pop
      if not line:
334 810c50b7 Iustin Pop
        break
335 810c50b7 Iustin Pop
      new_data.append(line.strip())
336 810c50b7 Iustin Pop
  finally:
337 810c50b7 Iustin Pop
    new_fh.close()
338 810c50b7 Iustin Pop
  args.extend(new_data)
339 810c50b7 Iustin Pop
340 810c50b7 Iustin Pop
341 846baef9 Iustin Pop
def ListTags(opts, args):
342 846baef9 Iustin Pop
  """List the tags on a given object.
343 846baef9 Iustin Pop

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

349 846baef9 Iustin Pop
  """
350 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
351 7699c3af Iustin Pop
  cl = GetClient()
352 7699c3af Iustin Pop
  result = cl.QueryTags(kind, name)
353 846baef9 Iustin Pop
  result = list(result)
354 846baef9 Iustin Pop
  result.sort()
355 846baef9 Iustin Pop
  for tag in result:
356 03298ebe Michael Hanselmann
    ToStdout(tag)
357 846baef9 Iustin Pop
358 846baef9 Iustin Pop
359 846baef9 Iustin Pop
def AddTags(opts, args):
360 846baef9 Iustin Pop
  """Add tags on a given object.
361 846baef9 Iustin Pop

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

367 846baef9 Iustin Pop
  """
368 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
369 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
370 846baef9 Iustin Pop
  if not args:
371 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be added")
372 846baef9 Iustin Pop
  op = opcodes.OpAddTags(kind=kind, name=name, tags=args)
373 846baef9 Iustin Pop
  SubmitOpCode(op)
374 846baef9 Iustin Pop
375 846baef9 Iustin Pop
376 846baef9 Iustin Pop
def RemoveTags(opts, args):
377 846baef9 Iustin Pop
  """Remove tags from a given object.
378 846baef9 Iustin Pop

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

384 846baef9 Iustin Pop
  """
385 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
386 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
387 846baef9 Iustin Pop
  if not args:
388 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be removed")
389 846baef9 Iustin Pop
  op = opcodes.OpDelTags(kind=kind, name=name, tags=args)
390 846baef9 Iustin Pop
  SubmitOpCode(op)
391 846baef9 Iustin Pop
392 a8083063 Iustin Pop
393 8929d28c Iustin Pop
def check_unit(option, opt, value): # pylint: disable-msg=W0613
394 65fe4693 Iustin Pop
  """OptParsers custom converter for units.
395 65fe4693 Iustin Pop

396 65fe4693 Iustin Pop
  """
397 a8083063 Iustin Pop
  try:
398 a8083063 Iustin Pop
    return utils.ParseUnit(value)
399 a8083063 Iustin Pop
  except errors.UnitParseError, err:
400 3ecf6786 Iustin Pop
    raise OptionValueError("option %s: %s" % (opt, err))
401 a8083063 Iustin Pop
402 a8083063 Iustin Pop
403 a8469393 Iustin Pop
def _SplitKeyVal(opt, data):
404 a8469393 Iustin Pop
  """Convert a KeyVal string into a dict.
405 a8469393 Iustin Pop

406 a8469393 Iustin Pop
  This function will convert a key=val[,...] string into a dict. Empty
407 a8469393 Iustin Pop
  values will be converted specially: keys which have the prefix 'no_'
408 a8469393 Iustin Pop
  will have the value=False and the prefix stripped, the others will
409 a8469393 Iustin Pop
  have value=True.
410 a8469393 Iustin Pop

411 a8469393 Iustin Pop
  @type opt: string
412 a8469393 Iustin Pop
  @param opt: a string holding the option name for which we process the
413 a8469393 Iustin Pop
      data, used in building error messages
414 a8469393 Iustin Pop
  @type data: string
415 a8469393 Iustin Pop
  @param data: a string of the format key=val,key=val,...
416 a8469393 Iustin Pop
  @rtype: dict
417 a8469393 Iustin Pop
  @return: {key=val, key=val}
418 a8469393 Iustin Pop
  @raises errors.ParameterError: if there are duplicate keys
419 a8469393 Iustin Pop

420 a8469393 Iustin Pop
  """
421 a8469393 Iustin Pop
  kv_dict = {}
422 4f31882e Guido Trotter
  if data:
423 1b3a7656 Iustin Pop
    for elem in utils.UnescapeAndSplit(data, sep=","):
424 4f31882e Guido Trotter
      if "=" in elem:
425 4f31882e Guido Trotter
        key, val = elem.split("=", 1)
426 a8469393 Iustin Pop
      else:
427 4f31882e Guido Trotter
        if elem.startswith(NO_PREFIX):
428 4f31882e Guido Trotter
          key, val = elem[len(NO_PREFIX):], False
429 4f31882e Guido Trotter
        elif elem.startswith(UN_PREFIX):
430 4f31882e Guido Trotter
          key, val = elem[len(UN_PREFIX):], None
431 4f31882e Guido Trotter
        else:
432 4f31882e Guido Trotter
          key, val = elem, True
433 4f31882e Guido Trotter
      if key in kv_dict:
434 4f31882e Guido Trotter
        raise errors.ParameterError("Duplicate key '%s' in option %s" %
435 4f31882e Guido Trotter
                                    (key, opt))
436 4f31882e Guido Trotter
      kv_dict[key] = val
437 a8469393 Iustin Pop
  return kv_dict
438 a8469393 Iustin Pop
439 a8469393 Iustin Pop
440 8929d28c Iustin Pop
def check_ident_key_val(option, opt, value):  # pylint: disable-msg=W0613
441 552c8dff Michael Hanselmann
  """Custom parser for ident:key=val,key=val options.
442 552c8dff Michael Hanselmann

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

446 a8469393 Iustin Pop
  """
447 a8469393 Iustin Pop
  if ":" not in value:
448 8b46606c Guido Trotter
    ident, rest = value, ''
449 a8469393 Iustin Pop
  else:
450 a8469393 Iustin Pop
    ident, rest = value.split(":", 1)
451 8b46606c Guido Trotter
452 8b46606c Guido Trotter
  if ident.startswith(NO_PREFIX):
453 8b46606c Guido Trotter
    if rest:
454 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
455 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
456 8b46606c Guido Trotter
    retval = (ident[len(NO_PREFIX):], False)
457 8b46606c Guido Trotter
  elif ident.startswith(UN_PREFIX):
458 8b46606c Guido Trotter
    if rest:
459 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
460 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
461 8b46606c Guido Trotter
    retval = (ident[len(UN_PREFIX):], None)
462 8b46606c Guido Trotter
  else:
463 a8469393 Iustin Pop
    kv_dict = _SplitKeyVal(opt, rest)
464 a8469393 Iustin Pop
    retval = (ident, kv_dict)
465 a8469393 Iustin Pop
  return retval
466 a8469393 Iustin Pop
467 a8469393 Iustin Pop
468 8929d28c Iustin Pop
def check_key_val(option, opt, value):  # pylint: disable-msg=W0613
469 552c8dff Michael Hanselmann
  """Custom parser class for key=val,key=val options.
470 552c8dff Michael Hanselmann

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

473 a8469393 Iustin Pop
  """
474 a8469393 Iustin Pop
  return _SplitKeyVal(opt, value)
475 a8469393 Iustin Pop
476 a8469393 Iustin Pop
477 e7b61bb0 Iustin Pop
def check_bool(option, opt, value): # pylint: disable-msg=W0613
478 e7b61bb0 Iustin Pop
  """Custom parser for yes/no options.
479 e7b61bb0 Iustin Pop

480 e7b61bb0 Iustin Pop
  This will store the parsed value as either True or False.
481 e7b61bb0 Iustin Pop

482 e7b61bb0 Iustin Pop
  """
483 e7b61bb0 Iustin Pop
  value = value.lower()
484 e7b61bb0 Iustin Pop
  if value == constants.VALUE_FALSE or value == "no":
485 e7b61bb0 Iustin Pop
    return False
486 e7b61bb0 Iustin Pop
  elif value == constants.VALUE_TRUE or value == "yes":
487 e7b61bb0 Iustin Pop
    return True
488 e7b61bb0 Iustin Pop
  else:
489 e7b61bb0 Iustin Pop
    raise errors.ParameterError("Invalid boolean value '%s'" % value)
490 e7b61bb0 Iustin Pop
491 e7b61bb0 Iustin Pop
492 63d44c55 Michael Hanselmann
# completion_suggestion is normally a list. Using numeric values not evaluating
493 63d44c55 Michael Hanselmann
# to False for dynamic completion.
494 63d44c55 Michael Hanselmann
(OPT_COMPL_MANY_NODES,
495 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_NODE,
496 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_INSTANCE,
497 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_OS,
498 2d3ed64b Michael Hanselmann
 OPT_COMPL_ONE_IALLOCATOR,
499 2d3ed64b Michael Hanselmann
 OPT_COMPL_INST_ADD_NODES) = range(100, 106)
500 63d44c55 Michael Hanselmann
501 63d44c55 Michael Hanselmann
OPT_COMPL_ALL = frozenset([
502 63d44c55 Michael Hanselmann
  OPT_COMPL_MANY_NODES,
503 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_NODE,
504 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_INSTANCE,
505 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_OS,
506 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_IALLOCATOR,
507 2d3ed64b Michael Hanselmann
  OPT_COMPL_INST_ADD_NODES,
508 63d44c55 Michael Hanselmann
  ])
509 63d44c55 Michael Hanselmann
510 63d44c55 Michael Hanselmann
511 552c8dff Michael Hanselmann
class CliOption(Option):
512 552c8dff Michael Hanselmann
  """Custom option class for optparse.
513 a8469393 Iustin Pop

514 a8469393 Iustin Pop
  """
515 863d7f46 Michael Hanselmann
  ATTRS = Option.ATTRS + [
516 863d7f46 Michael Hanselmann
    "completion_suggest",
517 863d7f46 Michael Hanselmann
    ]
518 552c8dff Michael Hanselmann
  TYPES = Option.TYPES + (
519 552c8dff Michael Hanselmann
    "identkeyval",
520 552c8dff Michael Hanselmann
    "keyval",
521 552c8dff Michael Hanselmann
    "unit",
522 e7b61bb0 Iustin Pop
    "bool",
523 552c8dff Michael Hanselmann
    )
524 552c8dff Michael Hanselmann
  TYPE_CHECKER = Option.TYPE_CHECKER.copy()
525 552c8dff Michael Hanselmann
  TYPE_CHECKER["identkeyval"] = check_ident_key_val
526 a8469393 Iustin Pop
  TYPE_CHECKER["keyval"] = check_key_val
527 552c8dff Michael Hanselmann
  TYPE_CHECKER["unit"] = check_unit
528 e7b61bb0 Iustin Pop
  TYPE_CHECKER["bool"] = check_bool
529 a8469393 Iustin Pop
530 a8469393 Iustin Pop
531 a8083063 Iustin Pop
# optparse.py sets make_option, so we do it for our own option class, too
532 a8083063 Iustin Pop
cli_option = CliOption
533 a8083063 Iustin Pop
534 a8083063 Iustin Pop
535 771734c9 Iustin Pop
_YORNO = "yes|no"
536 771734c9 Iustin Pop
537 ea34193f Iustin Pop
DEBUG_OPT = cli_option("-d", "--debug", default=0, action="count",
538 ea34193f Iustin Pop
                       help="Increase debugging level")
539 c38c44ad Michael Hanselmann
540 c38c44ad Michael Hanselmann
NOHDR_OPT = cli_option("--no-headers", default=False,
541 c38c44ad Michael Hanselmann
                       action="store_true", dest="no_headers",
542 c38c44ad Michael Hanselmann
                       help="Don't display column headers")
543 c38c44ad Michael Hanselmann
544 c38c44ad Michael Hanselmann
SEP_OPT = cli_option("--separator", default=None,
545 c38c44ad Michael Hanselmann
                     action="store", dest="separator",
546 c38c44ad Michael Hanselmann
                     help=("Separator between output fields"
547 c38c44ad Michael Hanselmann
                           " (defaults to one space)"))
548 c38c44ad Michael Hanselmann
549 c38c44ad Michael Hanselmann
USEUNITS_OPT = cli_option("--units", default=None,
550 c38c44ad Michael Hanselmann
                          dest="units", choices=('h', 'm', 'g', 't'),
551 c38c44ad Michael Hanselmann
                          help="Specify units for output (one of hmgt)")
552 c38c44ad Michael Hanselmann
553 c38c44ad Michael Hanselmann
FIELDS_OPT = cli_option("-o", "--output", dest="output", action="store",
554 c38c44ad Michael Hanselmann
                        type="string", metavar="FIELDS",
555 c38c44ad Michael Hanselmann
                        help="Comma separated list of output fields")
556 c38c44ad Michael Hanselmann
557 c38c44ad Michael Hanselmann
FORCE_OPT = cli_option("-f", "--force", dest="force", action="store_true",
558 c38c44ad Michael Hanselmann
                       default=False, help="Force the operation")
559 c38c44ad Michael Hanselmann
560 c38c44ad Michael Hanselmann
CONFIRM_OPT = cli_option("--yes", dest="confirm", action="store_true",
561 c38c44ad Michael Hanselmann
                         default=False, help="Do not require confirmation")
562 c38c44ad Michael Hanselmann
563 c38c44ad Michael Hanselmann
TAG_SRC_OPT = cli_option("--from", dest="tags_source",
564 c38c44ad Michael Hanselmann
                         default=None, help="File with tag names")
565 c38c44ad Michael Hanselmann
566 c38c44ad Michael Hanselmann
SUBMIT_OPT = cli_option("--submit", dest="submit_only",
567 c38c44ad Michael Hanselmann
                        default=False, action="store_true",
568 c38c44ad Michael Hanselmann
                        help=("Submit the job and return the job ID, but"
569 c38c44ad Michael Hanselmann
                              " don't wait for the job to finish"))
570 c38c44ad Michael Hanselmann
571 c38c44ad Michael Hanselmann
SYNC_OPT = cli_option("--sync", dest="do_locking",
572 c38c44ad Michael Hanselmann
                      default=False, action="store_true",
573 c38c44ad Michael Hanselmann
                      help=("Grab locks while doing the queries"
574 c38c44ad Michael Hanselmann
                            " in order to ensure more consistent results"))
575 c38c44ad Michael Hanselmann
576 c38c44ad Michael Hanselmann
_DRY_RUN_OPT = cli_option("--dry-run", default=False,
577 c38c44ad Michael Hanselmann
                          action="store_true",
578 c38c44ad Michael Hanselmann
                          help=("Do not execute the operation, just run the"
579 c38c44ad Michael Hanselmann
                                " check steps and verify it it could be"
580 c38c44ad Michael Hanselmann
                                " executed"))
581 c38c44ad Michael Hanselmann
582 9cdb9578 Iustin Pop
VERBOSE_OPT = cli_option("-v", "--verbose", default=False,
583 9cdb9578 Iustin Pop
                         action="store_true",
584 9cdb9578 Iustin Pop
                         help="Increase the verbosity of the operation")
585 9cdb9578 Iustin Pop
586 a0c9776a Iustin Pop
DEBUG_SIMERR_OPT = cli_option("--debug-simulate-errors", default=False,
587 a0c9776a Iustin Pop
                              action="store_true", dest="simulate_errors",
588 a0c9776a Iustin Pop
                              help="Debugging option that makes the operation"
589 a0c9776a Iustin Pop
                              " treat most runtime checks as failed")
590 a0c9776a Iustin Pop
591 3f75b4f3 Iustin Pop
NWSYNC_OPT = cli_option("--no-wait-for-sync", dest="wait_for_sync",
592 3f75b4f3 Iustin Pop
                        default=True, action="store_false",
593 3f75b4f3 Iustin Pop
                        help="Don't wait for sync (DANGEROUS!)")
594 3f75b4f3 Iustin Pop
595 4f365444 Iustin Pop
DISK_TEMPLATE_OPT = cli_option("-t", "--disk-template", dest="disk_template",
596 4f365444 Iustin Pop
                               help="Custom disk setup (diskless, file,"
597 4f365444 Iustin Pop
                               " plain or drbd)",
598 4f365444 Iustin Pop
                               default=None, metavar="TEMPL",
599 4f365444 Iustin Pop
                               choices=list(constants.DISK_TEMPLATES))
600 4f365444 Iustin Pop
601 26023ecd Iustin Pop
NONICS_OPT = cli_option("--no-nics", default=False, action="store_true",
602 26023ecd Iustin Pop
                        help="Do not create any network cards for"
603 26023ecd Iustin Pop
                        " the instance")
604 26023ecd Iustin Pop
605 4a25828c Iustin Pop
FILESTORE_DIR_OPT = cli_option("--file-storage-dir", dest="file_storage_dir",
606 4a25828c Iustin Pop
                               help="Relative path under default cluster-wide"
607 4a25828c Iustin Pop
                               " file storage dir to store file-based disks",
608 4a25828c Iustin Pop
                               default=None, metavar="<DIR>")
609 4a25828c Iustin Pop
610 0f87c43e Iustin Pop
FILESTORE_DRIVER_OPT = cli_option("--file-driver", dest="file_driver",
611 0f87c43e Iustin Pop
                                  help="Driver to use for image files",
612 0f87c43e Iustin Pop
                                  default="loop", metavar="<DRIVER>",
613 0f87c43e Iustin Pop
                                  choices=list(constants.FILE_DRIVER))
614 0f87c43e Iustin Pop
615 4eb62659 Iustin Pop
IALLOCATOR_OPT = cli_option("-I", "--iallocator", metavar="<NAME>",
616 4eb62659 Iustin Pop
                            help="Select nodes for the instance automatically"
617 4eb62659 Iustin Pop
                            " using the <NAME> iallocator plugin",
618 4eb62659 Iustin Pop
                            default=None, type="string",
619 4eb62659 Iustin Pop
                            completion_suggest=OPT_COMPL_ONE_IALLOCATOR)
620 4eb62659 Iustin Pop
621 bf4af505 Apollon Oikonomopoulos
DEFAULT_IALLOCATOR_OPT = cli_option("-I", "--default-iallocator",
622 bf4af505 Apollon Oikonomopoulos
                            metavar="<NAME>",
623 bf4af505 Apollon Oikonomopoulos
                            help="Set the default instance allocator plugin",
624 bf4af505 Apollon Oikonomopoulos
                            default=None, type="string",
625 bf4af505 Apollon Oikonomopoulos
                            completion_suggest=OPT_COMPL_ONE_IALLOCATOR)
626 bf4af505 Apollon Oikonomopoulos
627 d3ed23ff Iustin Pop
OS_OPT = cli_option("-o", "--os-type", dest="os", help="What OS to run",
628 d3ed23ff Iustin Pop
                    metavar="<os>",
629 d3ed23ff Iustin Pop
                    completion_suggest=OPT_COMPL_ONE_OS)
630 d3ed23ff Iustin Pop
631 062a7100 Iustin Pop
OSPARAMS_OPT = cli_option("-O", "--os-parameters", dest="osparams",
632 062a7100 Iustin Pop
                         type="keyval", default={},
633 062a7100 Iustin Pop
                         help="OS parameters")
634 062a7100 Iustin Pop
635 06073e85 Guido Trotter
FORCE_VARIANT_OPT = cli_option("--force-variant", dest="force_variant",
636 06073e85 Guido Trotter
                               action="store_true", default=False,
637 06073e85 Guido Trotter
                               help="Force an unknown variant")
638 06073e85 Guido Trotter
639 25a8792c Iustin Pop
NO_INSTALL_OPT = cli_option("--no-install", dest="no_install",
640 25a8792c Iustin Pop
                            action="store_true", default=False,
641 25a8792c Iustin Pop
                            help="Do not install the OS (will"
642 25a8792c Iustin Pop
                            " enable no-start)")
643 25a8792c Iustin Pop
644 087ed2ed Iustin Pop
BACKEND_OPT = cli_option("-B", "--backend-parameters", dest="beparams",
645 087ed2ed Iustin Pop
                         type="keyval", default={},
646 087ed2ed Iustin Pop
                         help="Backend parameters")
647 48f212d7 Iustin Pop
648 48f212d7 Iustin Pop
HVOPTS_OPT =  cli_option("-H", "--hypervisor-parameters", type="keyval",
649 48f212d7 Iustin Pop
                         default={}, dest="hvparams",
650 48f212d7 Iustin Pop
                         help="Hypervisor parameters")
651 087ed2ed Iustin Pop
652 236fd9c4 Iustin Pop
HYPERVISOR_OPT = cli_option("-H", "--hypervisor-parameters", dest="hypervisor",
653 236fd9c4 Iustin Pop
                            help="Hypervisor and hypervisor options, in the"
654 236fd9c4 Iustin Pop
                            " format hypervisor:option=value,option=value,...",
655 236fd9c4 Iustin Pop
                            default=None, type="identkeyval")
656 073271f6 Iustin Pop
657 073271f6 Iustin Pop
HVLIST_OPT = cli_option("-H", "--hypervisor-parameters", dest="hvparams",
658 073271f6 Iustin Pop
                        help="Hypervisor and hypervisor options, in the"
659 073271f6 Iustin Pop
                        " format hypervisor:option=value,option=value,...",
660 073271f6 Iustin Pop
                        default=[], action="append", type="identkeyval")
661 236fd9c4 Iustin Pop
662 91e0748c Iustin Pop
NOIPCHECK_OPT = cli_option("--no-ip-check", dest="ip_check", default=True,
663 91e0748c Iustin Pop
                           action="store_false",
664 91e0748c Iustin Pop
                           help="Don't check that the instance's IP"
665 91e0748c Iustin Pop
                           " is alive")
666 91e0748c Iustin Pop
667 460d22be Iustin Pop
NONAMECHECK_OPT = cli_option("--no-name-check", dest="name_check",
668 460d22be Iustin Pop
                             default=True, action="store_false",
669 460d22be Iustin Pop
                             help="Don't check that the instance's name"
670 460d22be Iustin Pop
                             " is resolvable")
671 460d22be Iustin Pop
672 7d3a9fab Iustin Pop
NET_OPT = cli_option("--net",
673 7d3a9fab Iustin Pop
                     help="NIC parameters", default=[],
674 7d3a9fab Iustin Pop
                     dest="nics", action="append", type="identkeyval")
675 e3876ccb Iustin Pop
676 e3876ccb Iustin Pop
DISK_OPT = cli_option("--disk", help="Disk parameters", default=[],
677 e3876ccb Iustin Pop
                      dest="disks", action="append", type="identkeyval")
678 91e0748c Iustin Pop
679 4b038a1e Iustin Pop
DISKIDX_OPT = cli_option("--disks", dest="disks", default=None,
680 4b038a1e Iustin Pop
                         help="Comma-separated list of disks"
681 4b038a1e Iustin Pop
                         " indices to act on (e.g. 0,2) (optional,"
682 4b038a1e Iustin Pop
                         " defaults to all disks)")
683 4b038a1e Iustin Pop
684 ff00c1a7 Iustin Pop
OS_SIZE_OPT = cli_option("-s", "--os-size", dest="sd_size",
685 ff00c1a7 Iustin Pop
                         help="Enforces a single-disk configuration using the"
686 ff00c1a7 Iustin Pop
                         " given disk size, in MiB unless a suffix is used",
687 ff00c1a7 Iustin Pop
                         default=None, type="unit", metavar="<size>")
688 ff00c1a7 Iustin Pop
689 82a786d5 Iustin Pop
IGNORE_CONSIST_OPT = cli_option("--ignore-consistency",
690 82a786d5 Iustin Pop
                                dest="ignore_consistency",
691 82a786d5 Iustin Pop
                                action="store_true", default=False,
692 82a786d5 Iustin Pop
                                help="Ignore the consistency of the disks on"
693 82a786d5 Iustin Pop
                                " the secondary")
694 82a786d5 Iustin Pop
695 f2a0828c Iustin Pop
NONLIVE_OPT = cli_option("--non-live", dest="live",
696 f2a0828c Iustin Pop
                         default=True, action="store_false",
697 f2a0828c Iustin Pop
                         help="Do a non-live migration (this usually means"
698 f2a0828c Iustin Pop
                         " freeze the instance, save the state, transfer and"
699 f2a0828c Iustin Pop
                         " only then resume running on the secondary node)")
700 f2a0828c Iustin Pop
701 990b7886 Iustin Pop
NODE_PLACEMENT_OPT = cli_option("-n", "--node", dest="node",
702 990b7886 Iustin Pop
                                help="Target node and optional secondary node",
703 990b7886 Iustin Pop
                                metavar="<pnode>[:<snode>]",
704 990b7886 Iustin Pop
                                completion_suggest=OPT_COMPL_INST_ADD_NODES)
705 990b7886 Iustin Pop
706 7edc4637 Iustin Pop
NODE_LIST_OPT = cli_option("-n", "--node", dest="nodes", default=[],
707 7edc4637 Iustin Pop
                           action="append", metavar="<node>",
708 7edc4637 Iustin Pop
                           help="Use only this node (can be used multiple"
709 7edc4637 Iustin Pop
                           " times, if not given defaults to all nodes)",
710 7edc4637 Iustin Pop
                           completion_suggest=OPT_COMPL_ONE_NODE)
711 f36d7d81 Iustin Pop
712 f36d7d81 Iustin Pop
SINGLE_NODE_OPT = cli_option("-n", "--node", dest="node", help="Target node",
713 f36d7d81 Iustin Pop
                             metavar="<node>",
714 f36d7d81 Iustin Pop
                             completion_suggest=OPT_COMPL_ONE_NODE)
715 7edc4637 Iustin Pop
716 edeb878a Iustin Pop
NOSTART_OPT = cli_option("--no-start", dest="start", default=True,
717 edeb878a Iustin Pop
                         action="store_false",
718 edeb878a Iustin Pop
                         help="Don't start the instance after creation")
719 edeb878a Iustin Pop
720 fdcf4d84 Iustin Pop
SHOWCMD_OPT = cli_option("--show-cmd", dest="show_command",
721 fdcf4d84 Iustin Pop
                         action="store_true", default=False,
722 fdcf4d84 Iustin Pop
                         help="Show command instead of executing it")
723 fdcf4d84 Iustin Pop
724 baef337d Iustin Pop
CLEANUP_OPT = cli_option("--cleanup", dest="cleanup",
725 baef337d Iustin Pop
                         default=False, action="store_true",
726 baef337d Iustin Pop
                         help="Instead of performing the migration, try to"
727 baef337d Iustin Pop
                         " recover from a failed cleanup. This is safe"
728 baef337d Iustin Pop
                         " to run even if the instance is healthy, but it"
729 baef337d Iustin Pop
                         " will create extra replication traffic and "
730 baef337d Iustin Pop
                         " disrupt briefly the replication (like during the"
731 baef337d Iustin Pop
                         " migration")
732 baef337d Iustin Pop
733 99a8c799 Iustin Pop
STATIC_OPT = cli_option("-s", "--static", dest="static",
734 99a8c799 Iustin Pop
                        action="store_true", default=False,
735 99a8c799 Iustin Pop
                        help="Only show configuration data, not runtime data")
736 99a8c799 Iustin Pop
737 2d5e7ae1 Iustin Pop
ALL_OPT = cli_option("--all", dest="show_all",
738 2d5e7ae1 Iustin Pop
                     default=False, action="store_true",
739 2d5e7ae1 Iustin Pop
                     help="Show info on all instances on the cluster."
740 2d5e7ae1 Iustin Pop
                     " This can take a long time to run, use wisely")
741 2d5e7ae1 Iustin Pop
742 67840b40 Iustin Pop
SELECT_OS_OPT = cli_option("--select-os", dest="select_os",
743 67840b40 Iustin Pop
                           action="store_true", default=False,
744 67840b40 Iustin Pop
                           help="Interactive OS reinstall, lists available"
745 67840b40 Iustin Pop
                           " OS templates for selection")
746 2d5e7ae1 Iustin Pop
747 b6e841a8 Iustin Pop
IGNORE_FAILURES_OPT = cli_option("--ignore-failures", dest="ignore_failures",
748 b6e841a8 Iustin Pop
                                 action="store_true", default=False,
749 b6e841a8 Iustin Pop
                                 help="Remove the instance from the cluster"
750 b6e841a8 Iustin Pop
                                 " configuration even if there are failures"
751 b6e841a8 Iustin Pop
                                 " during the removal process")
752 b6e841a8 Iustin Pop
753 8d8d650c Michael Hanselmann
IGNORE_REMOVE_FAILURES_OPT = cli_option("--ignore-remove-failures",
754 8d8d650c Michael Hanselmann
                                        dest="ignore_remove_failures",
755 8d8d650c Michael Hanselmann
                                        action="store_true", default=False,
756 8d8d650c Michael Hanselmann
                                        help="Remove the instance from the"
757 8d8d650c Michael Hanselmann
                                        " cluster configuration even if there"
758 8d8d650c Michael Hanselmann
                                        " are failures during the removal"
759 8d8d650c Michael Hanselmann
                                        " process")
760 8d8d650c Michael Hanselmann
761 8d8d650c Michael Hanselmann
REMOVE_INSTANCE_OPT = cli_option("--remove-instance", dest="remove_instance",
762 8d8d650c Michael Hanselmann
                                 action="store_true", default=False,
763 8d8d650c Michael Hanselmann
                                 help="Remove the instance from the cluster")
764 8d8d650c Michael Hanselmann
765 a14db5ff Iustin Pop
NEW_SECONDARY_OPT = cli_option("-n", "--new-secondary", dest="dst_node",
766 a14db5ff Iustin Pop
                               help="Specifies the new secondary node",
767 a14db5ff Iustin Pop
                               metavar="NODE", default=None,
768 a14db5ff Iustin Pop
                               completion_suggest=OPT_COMPL_ONE_NODE)
769 a14db5ff Iustin Pop
770 a72d0a79 Iustin Pop
ON_PRIMARY_OPT = cli_option("-p", "--on-primary", dest="on_primary",
771 a72d0a79 Iustin Pop
                            default=False, action="store_true",
772 a72d0a79 Iustin Pop
                            help="Replace the disk(s) on the primary"
773 a72d0a79 Iustin Pop
                            " node (only for the drbd template)")
774 feb09e6a Iustin Pop
775 feb09e6a Iustin Pop
ON_SECONDARY_OPT = cli_option("-s", "--on-secondary", dest="on_secondary",
776 feb09e6a Iustin Pop
                              default=False, action="store_true",
777 feb09e6a Iustin Pop
                              help="Replace the disk(s) on the secondary"
778 feb09e6a Iustin Pop
                              " node (only for the drbd template)")
779 e00f7a05 Iustin Pop
780 4c61d894 Iustin Pop
AUTO_PROMOTE_OPT = cli_option("--auto-promote", dest="auto_promote",
781 4c61d894 Iustin Pop
                              default=False, action="store_true",
782 4c61d894 Iustin Pop
                              help="Lock all nodes and auto-promote as needed"
783 4c61d894 Iustin Pop
                              " to MC status")
784 4c61d894 Iustin Pop
785 e00f7a05 Iustin Pop
AUTO_REPLACE_OPT = cli_option("-a", "--auto", dest="auto",
786 e00f7a05 Iustin Pop
                              default=False, action="store_true",
787 e00f7a05 Iustin Pop
                              help="Automatically replace faulty disks"
788 e00f7a05 Iustin Pop
                              " (only for the drbd template)")
789 a72d0a79 Iustin Pop
790 05586c90 Iustin Pop
IGNORE_SIZE_OPT = cli_option("--ignore-size", dest="ignore_size",
791 05586c90 Iustin Pop
                             default=False, action="store_true",
792 05586c90 Iustin Pop
                             help="Ignore current recorded size"
793 05586c90 Iustin Pop
                             " (useful for forcing activation when"
794 05586c90 Iustin Pop
                             " the recorded size is wrong)")
795 05586c90 Iustin Pop
796 df62e5db Iustin Pop
SRC_NODE_OPT = cli_option("--src-node", dest="src_node", help="Source node",
797 df62e5db Iustin Pop
                          metavar="<node>",
798 df62e5db Iustin Pop
                          completion_suggest=OPT_COMPL_ONE_NODE)
799 df62e5db Iustin Pop
800 df62e5db Iustin Pop
SRC_DIR_OPT = cli_option("--src-dir", dest="src_dir", help="Source directory",
801 df62e5db Iustin Pop
                         metavar="<dir>")
802 df62e5db Iustin Pop
803 8d823629 Iustin Pop
SECONDARY_IP_OPT = cli_option("-s", "--secondary-ip", dest="secondary_ip",
804 8d823629 Iustin Pop
                              help="Specify the secondary ip for the node",
805 8d823629 Iustin Pop
                              metavar="ADDRESS", default=None)
806 8d823629 Iustin Pop
807 b8d0f938 Iustin Pop
READD_OPT = cli_option("--readd", dest="readd",
808 b8d0f938 Iustin Pop
                       default=False, action="store_true",
809 b8d0f938 Iustin Pop
                       help="Readd old node after replacing it")
810 b8d0f938 Iustin Pop
811 fcdde7f2 Iustin Pop
NOSSH_KEYCHECK_OPT = cli_option("--no-ssh-key-check", dest="ssh_key_check",
812 fcdde7f2 Iustin Pop
                                default=True, action="store_false",
813 fcdde7f2 Iustin Pop
                                help="Disable SSH key fingerprint checking")
814 fcdde7f2 Iustin Pop
815 c38c44ad Michael Hanselmann
816 771734c9 Iustin Pop
MC_OPT = cli_option("-C", "--master-candidate", dest="master_candidate",
817 e7b61bb0 Iustin Pop
                    type="bool", default=None, metavar=_YORNO,
818 771734c9 Iustin Pop
                    help="Set the master_candidate flag on the node")
819 771734c9 Iustin Pop
820 771734c9 Iustin Pop
OFFLINE_OPT = cli_option("-O", "--offline", dest="offline", metavar=_YORNO,
821 e7b61bb0 Iustin Pop
                         type="bool", default=None,
822 771734c9 Iustin Pop
                         help="Set the offline flag on the node")
823 771734c9 Iustin Pop
824 771734c9 Iustin Pop
DRAINED_OPT = cli_option("-D", "--drained", dest="drained", metavar=_YORNO,
825 e7b61bb0 Iustin Pop
                         type="bool", default=None,
826 771734c9 Iustin Pop
                         help="Set the drained flag on the node")
827 771734c9 Iustin Pop
828 e7e09483 Iustin Pop
ALLOCATABLE_OPT = cli_option("--allocatable", dest="allocatable",
829 e7b61bb0 Iustin Pop
                             type="bool", default=None, metavar=_YORNO,
830 e7e09483 Iustin Pop
                             help="Set the allocatable flag on a volume")
831 e7e09483 Iustin Pop
832 831040bf Iustin Pop
NOLVM_STORAGE_OPT = cli_option("--no-lvm-storage", dest="lvm_storage",
833 831040bf Iustin Pop
                               help="Disable support for lvm based instances"
834 831040bf Iustin Pop
                               " (cluster-wide)",
835 831040bf Iustin Pop
                               action="store_false", default=True)
836 831040bf Iustin Pop
837 383a3591 Iustin Pop
ENABLED_HV_OPT = cli_option("--enabled-hypervisors",
838 383a3591 Iustin Pop
                            dest="enabled_hypervisors",
839 383a3591 Iustin Pop
                            help="Comma-separated list of hypervisors",
840 383a3591 Iustin Pop
                            type="string", default=None)
841 383a3591 Iustin Pop
842 4fbc93dd Iustin Pop
NIC_PARAMS_OPT = cli_option("-N", "--nic-parameters", dest="nicparams",
843 4fbc93dd Iustin Pop
                            type="keyval", default={},
844 4fbc93dd Iustin Pop
                            help="NIC parameters")
845 4fbc93dd Iustin Pop
846 e32df528 Iustin Pop
CP_SIZE_OPT = cli_option("-C", "--candidate-pool-size", default=None,
847 e32df528 Iustin Pop
                         dest="candidate_pool_size", type="int",
848 e32df528 Iustin Pop
                         help="Set the candidate pool size")
849 e32df528 Iustin Pop
850 b58726e8 Iustin Pop
VG_NAME_OPT = cli_option("-g", "--vg-name", dest="vg_name",
851 b58726e8 Iustin Pop
                         help="Enables LVM and specifies the volume group"
852 b58726e8 Iustin Pop
                         " name (cluster-wide) for disk allocation [xenvg]",
853 b58726e8 Iustin Pop
                         metavar="VG", default=None)
854 b58726e8 Iustin Pop
855 1f587d3d Iustin Pop
YES_DOIT_OPT = cli_option("--yes-do-it", dest="yes_do_it",
856 1f587d3d Iustin Pop
                          help="Destroy cluster", action="store_true")
857 b58726e8 Iustin Pop
858 58371861 Iustin Pop
NOVOTING_OPT = cli_option("--no-voting", dest="no_voting",
859 58371861 Iustin Pop
                          help="Skip node agreement check (dangerous)",
860 58371861 Iustin Pop
                          action="store_true", default=False)
861 58371861 Iustin Pop
862 e3646f22 Iustin Pop
MAC_PREFIX_OPT = cli_option("-m", "--mac-prefix", dest="mac_prefix",
863 e3646f22 Iustin Pop
                            help="Specify the mac prefix for the instance IP"
864 e3646f22 Iustin Pop
                            " addresses, in the format XX:XX:XX",
865 e3646f22 Iustin Pop
                            metavar="PREFIX",
866 e3646f22 Iustin Pop
                            default=None)
867 e3646f22 Iustin Pop
868 29392516 Iustin Pop
MASTER_NETDEV_OPT = cli_option("--master-netdev", dest="master_netdev",
869 29392516 Iustin Pop
                               help="Specify the node interface (cluster-wide)"
870 29392516 Iustin Pop
                               " on which the master IP address will be added "
871 29392516 Iustin Pop
                               " [%s]" % constants.DEFAULT_BRIDGE,
872 29392516 Iustin Pop
                               metavar="NETDEV",
873 29392516 Iustin Pop
                               default=constants.DEFAULT_BRIDGE)
874 29392516 Iustin Pop
875 29392516 Iustin Pop
GLOBAL_FILEDIR_OPT = cli_option("--file-storage-dir", dest="file_storage_dir",
876 29392516 Iustin Pop
                                help="Specify the default directory (cluster-"
877 29392516 Iustin Pop
                                "wide) for storing the file-based disks [%s]" %
878 29392516 Iustin Pop
                                constants.DEFAULT_FILE_STORAGE_DIR,
879 29392516 Iustin Pop
                                metavar="DIR",
880 29392516 Iustin Pop
                                default=constants.DEFAULT_FILE_STORAGE_DIR)
881 29392516 Iustin Pop
882 29392516 Iustin Pop
NOMODIFY_ETCHOSTS_OPT = cli_option("--no-etc-hosts", dest="modify_etc_hosts",
883 29392516 Iustin Pop
                                   help="Don't modify /etc/hosts",
884 29392516 Iustin Pop
                                   action="store_false", default=True)
885 29392516 Iustin Pop
886 b989b9d9 Ken Wehr
NOMODIFY_SSH_SETUP_OPT = cli_option("--no-ssh-init", dest="modify_ssh_setup",
887 b989b9d9 Ken Wehr
                                    help="Don't initialize SSH keys",
888 b989b9d9 Ken Wehr
                                    action="store_false", default=True)
889 b989b9d9 Ken Wehr
890 14e9e7f3 Iustin Pop
ERROR_CODES_OPT = cli_option("--error-codes", dest="error_codes",
891 14e9e7f3 Iustin Pop
                             help="Enable parseable error messages",
892 14e9e7f3 Iustin Pop
                             action="store_true", default=False)
893 14e9e7f3 Iustin Pop
894 14e9e7f3 Iustin Pop
NONPLUS1_OPT = cli_option("--no-nplus1-mem", dest="skip_nplusone_mem",
895 14e9e7f3 Iustin Pop
                          help="Skip N+1 memory redundancy tests",
896 14e9e7f3 Iustin Pop
                          action="store_true", default=False)
897 14e9e7f3 Iustin Pop
898 12054861 Iustin Pop
REBOOT_TYPE_OPT = cli_option("-t", "--type", dest="reboot_type",
899 12054861 Iustin Pop
                             help="Type of reboot: soft/hard/full",
900 12054861 Iustin Pop
                             default=constants.INSTANCE_REBOOT_HARD,
901 12054861 Iustin Pop
                             metavar="<REBOOT>",
902 12054861 Iustin Pop
                             choices=list(constants.REBOOT_TYPES))
903 12054861 Iustin Pop
904 ee3f9578 Iustin Pop
IGNORE_SECONDARIES_OPT = cli_option("--ignore-secondaries",
905 ee3f9578 Iustin Pop
                                    dest="ignore_secondaries",
906 ee3f9578 Iustin Pop
                                    default=False, action="store_true",
907 ee3f9578 Iustin Pop
                                    help="Ignore errors from secondaries")
908 ee3f9578 Iustin Pop
909 69b99987 Michael Hanselmann
NOSHUTDOWN_OPT = cli_option("--noshutdown", dest="shutdown",
910 44c44832 Iustin Pop
                            action="store_false", default=True,
911 44c44832 Iustin Pop
                            help="Don't shutdown the instance (unsafe)")
912 44c44832 Iustin Pop
913 b5762e2a Guido Trotter
TIMEOUT_OPT = cli_option("--timeout", dest="timeout", type="int",
914 b5762e2a Guido Trotter
                         default=constants.DEFAULT_SHUTDOWN_TIMEOUT,
915 b5762e2a Guido Trotter
                         help="Maximum time to wait")
916 44c44832 Iustin Pop
917 4d98c565 Guido Trotter
SHUTDOWN_TIMEOUT_OPT = cli_option("--shutdown-timeout",
918 4d98c565 Guido Trotter
                         dest="shutdown_timeout", type="int",
919 7e5eaaa8 Guido Trotter
                         default=constants.DEFAULT_SHUTDOWN_TIMEOUT,
920 7e5eaaa8 Guido Trotter
                         help="Maximum time to wait for instance shutdown")
921 7e5eaaa8 Guido Trotter
922 7ea7bcf6 Iustin Pop
EARLY_RELEASE_OPT = cli_option("--early-release",
923 7ea7bcf6 Iustin Pop
                               dest="early_release", default=False,
924 7ea7bcf6 Iustin Pop
                               action="store_true",
925 7ea7bcf6 Iustin Pop
                               help="Release the locks on the secondary"
926 7ea7bcf6 Iustin Pop
                               " node(s) early")
927 7ea7bcf6 Iustin Pop
928 6d4a1656 Michael Hanselmann
NEW_CLUSTER_CERT_OPT = cli_option("--new-cluster-certificate",
929 6d4a1656 Michael Hanselmann
                                  dest="new_cluster_cert",
930 6d4a1656 Michael Hanselmann
                                  default=False, action="store_true",
931 6d4a1656 Michael Hanselmann
                                  help="Generate a new cluster certificate")
932 6d4a1656 Michael Hanselmann
933 6d4a1656 Michael Hanselmann
RAPI_CERT_OPT = cli_option("--rapi-certificate", dest="rapi_cert",
934 6d4a1656 Michael Hanselmann
                           default=None,
935 6d4a1656 Michael Hanselmann
                           help="File containing new RAPI certificate")
936 6d4a1656 Michael Hanselmann
937 6d4a1656 Michael Hanselmann
NEW_RAPI_CERT_OPT = cli_option("--new-rapi-certificate", dest="new_rapi_cert",
938 6d4a1656 Michael Hanselmann
                               default=None, action="store_true",
939 6d4a1656 Michael Hanselmann
                               help=("Generate a new self-signed RAPI"
940 6d4a1656 Michael Hanselmann
                                     " certificate"))
941 6d4a1656 Michael Hanselmann
942 6b7d5878 Michael Hanselmann
NEW_CONFD_HMAC_KEY_OPT = cli_option("--new-confd-hmac-key",
943 6b7d5878 Michael Hanselmann
                                    dest="new_confd_hmac_key",
944 6b7d5878 Michael Hanselmann
                                    default=False, action="store_true",
945 6b7d5878 Michael Hanselmann
                                    help=("Create a new HMAC key for %s" %
946 6b7d5878 Michael Hanselmann
                                          constants.CONFD))
947 6d4a1656 Michael Hanselmann
948 3db3eb2a Michael Hanselmann
CLUSTER_DOMAIN_SECRET_OPT = cli_option("--cluster-domain-secret",
949 3db3eb2a Michael Hanselmann
                                       dest="cluster_domain_secret",
950 3db3eb2a Michael Hanselmann
                                       default=None,
951 3db3eb2a Michael Hanselmann
                                       help=("Load new new cluster domain"
952 3db3eb2a Michael Hanselmann
                                             " secret from file"))
953 3db3eb2a Michael Hanselmann
954 3db3eb2a Michael Hanselmann
NEW_CLUSTER_DOMAIN_SECRET_OPT = cli_option("--new-cluster-domain-secret",
955 3db3eb2a Michael Hanselmann
                                           dest="new_cluster_domain_secret",
956 3db3eb2a Michael Hanselmann
                                           default=False, action="store_true",
957 3db3eb2a Michael Hanselmann
                                           help=("Create a new cluster domain"
958 3db3eb2a Michael Hanselmann
                                                 " secret"))
959 3db3eb2a Michael Hanselmann
960 74adc100 Iustin Pop
USE_REPL_NET_OPT = cli_option("--use-replication-network",
961 74adc100 Iustin Pop
                              dest="use_replication_network",
962 74adc100 Iustin Pop
                              help="Whether to use the replication network"
963 74adc100 Iustin Pop
                              " for talking to the nodes",
964 74adc100 Iustin Pop
                              action="store_true", default=False)
965 74adc100 Iustin Pop
966 3953242f Iustin Pop
MAINTAIN_NODE_HEALTH_OPT = \
967 3953242f Iustin Pop
    cli_option("--maintain-node-health", dest="maintain_node_health",
968 3953242f Iustin Pop
               metavar=_YORNO, default=None, type="bool",
969 3953242f Iustin Pop
               help="Configure the cluster to automatically maintain node"
970 3953242f Iustin Pop
               " health, by shutting down unknown instances, shutting down"
971 3953242f Iustin Pop
               " unknown DRBD devices, etc.")
972 3953242f Iustin Pop
973 e588764d Iustin Pop
IDENTIFY_DEFAULTS_OPT = \
974 e588764d Iustin Pop
    cli_option("--identify-defaults", dest="identify_defaults",
975 e588764d Iustin Pop
               default=False, action="store_true",
976 e588764d Iustin Pop
               help="Identify which saved instance parameters are equal to"
977 e588764d Iustin Pop
               " the current cluster defaults and set them as such, instead"
978 e588764d Iustin Pop
               " of marking them as overridden")
979 e588764d Iustin Pop
980 1338f2b4 Balazs Lecz
UIDPOOL_OPT = cli_option("--uid-pool", default=None,
981 1338f2b4 Balazs Lecz
                         action="store", dest="uid_pool",
982 1338f2b4 Balazs Lecz
                         help=("A list of user-ids or user-id"
983 1338f2b4 Balazs Lecz
                               " ranges separated by commas"))
984 1338f2b4 Balazs Lecz
985 fdad8c4d Balazs Lecz
ADD_UIDS_OPT = cli_option("--add-uids", default=None,
986 fdad8c4d Balazs Lecz
                          action="store", dest="add_uids",
987 fdad8c4d Balazs Lecz
                          help=("A list of user-ids or user-id"
988 fdad8c4d Balazs Lecz
                                " ranges separated by commas, to be"
989 fdad8c4d Balazs Lecz
                                " added to the user-id pool"))
990 fdad8c4d Balazs Lecz
991 fdad8c4d Balazs Lecz
REMOVE_UIDS_OPT = cli_option("--remove-uids", default=None,
992 fdad8c4d Balazs Lecz
                             action="store", dest="remove_uids",
993 fdad8c4d Balazs Lecz
                             help=("A list of user-ids or user-id"
994 fdad8c4d Balazs Lecz
                                   " ranges separated by commas, to be"
995 fdad8c4d Balazs Lecz
                                   " removed from the user-id pool"))
996 fdad8c4d Balazs Lecz
997 31d97b2a Guido Trotter
ROMAN_OPT = cli_option("--roman",
998 31d97b2a Guido Trotter
                       dest="roman_integers", default=False,
999 31d97b2a Guido Trotter
                       action="store_true",
1000 31d97b2a Guido Trotter
                       help="Use roman numbers for positive integers")
1001 31d97b2a Guido Trotter
1002 26591bfd Luca Bigliardi
DRBD_HELPER_OPT = cli_option("--drbd-usermode-helper", dest="drbd_helper",
1003 26591bfd Luca Bigliardi
                             action="store", default=None,
1004 26591bfd Luca Bigliardi
                             help="Specifies usermode helper for DRBD")
1005 26591bfd Luca Bigliardi
1006 26591bfd Luca Bigliardi
NODRBD_STORAGE_OPT = cli_option("--no-drbd-storage", dest="drbd_storage",
1007 26591bfd Luca Bigliardi
                                action="store_false", default=True,
1008 26591bfd Luca Bigliardi
                                help="Disable support for DRBD")
1009 31d97b2a Guido Trotter
1010 771734c9 Iustin Pop
1011 de47cf8f Guido Trotter
def _ParseArgs(argv, commands, aliases):
1012 c41eea6e Iustin Pop
  """Parser for the command line arguments.
1013 a8083063 Iustin Pop

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

1017 c41eea6e Iustin Pop
  @param argv: the command line
1018 c41eea6e Iustin Pop
  @param commands: dictionary with special contents, see the design
1019 c41eea6e Iustin Pop
      doc for cmdline handling
1020 c41eea6e Iustin Pop
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
1021 098c0958 Michael Hanselmann

1022 a8083063 Iustin Pop
  """
1023 a8083063 Iustin Pop
  if len(argv) == 0:
1024 a8083063 Iustin Pop
    binary = "<command>"
1025 a8083063 Iustin Pop
  else:
1026 a8083063 Iustin Pop
    binary = argv[0].split("/")[-1]
1027 a8083063 Iustin Pop
1028 a8083063 Iustin Pop
  if len(argv) > 1 and argv[1] == "--version":
1029 03298ebe Michael Hanselmann
    ToStdout("%s (ganeti) %s", binary, constants.RELEASE_VERSION)
1030 a8083063 Iustin Pop
    # Quit right away. That way we don't have to care about this special
1031 a8083063 Iustin Pop
    # argument. optparse.py does it the same.
1032 a8083063 Iustin Pop
    sys.exit(0)
1033 a8083063 Iustin Pop
1034 de47cf8f Guido Trotter
  if len(argv) < 2 or not (argv[1] in commands or
1035 70a35b6f Guido Trotter
                           argv[1] in aliases):
1036 a8083063 Iustin Pop
    # let's do a nice thing
1037 a8083063 Iustin Pop
    sortedcmds = commands.keys()
1038 a8083063 Iustin Pop
    sortedcmds.sort()
1039 03298ebe Michael Hanselmann
1040 03298ebe Michael Hanselmann
    ToStdout("Usage: %s {command} [options...] [argument...]", binary)
1041 03298ebe Michael Hanselmann
    ToStdout("%s <command> --help to see details, or man %s", binary, binary)
1042 03298ebe Michael Hanselmann
    ToStdout("")
1043 03298ebe Michael Hanselmann
1044 a8083063 Iustin Pop
    # compute the max line length for cmd + usage
1045 4e713df6 Iustin Pop
    mlen = max([len(" %s" % cmd) for cmd in commands])
1046 a8083063 Iustin Pop
    mlen = min(60, mlen) # should not get here...
1047 03298ebe Michael Hanselmann
1048 a8083063 Iustin Pop
    # and format a nice command list
1049 03298ebe Michael Hanselmann
    ToStdout("Commands:")
1050 a8083063 Iustin Pop
    for cmd in sortedcmds:
1051 4e713df6 Iustin Pop
      cmdstr = " %s" % (cmd,)
1052 9a033156 Iustin Pop
      help_text = commands[cmd][4]
1053 03298ebe Michael Hanselmann
      help_lines = textwrap.wrap(help_text, 79 - 3 - mlen)
1054 03298ebe Michael Hanselmann
      ToStdout("%-*s - %s", mlen, cmdstr, help_lines.pop(0))
1055 a8083063 Iustin Pop
      for line in help_lines:
1056 03298ebe Michael Hanselmann
        ToStdout("%-*s   %s", mlen, "", line)
1057 03298ebe Michael Hanselmann
1058 03298ebe Michael Hanselmann
    ToStdout("")
1059 03298ebe Michael Hanselmann
1060 a8083063 Iustin Pop
    return None, None, None
1061 de47cf8f Guido Trotter
1062 de47cf8f Guido Trotter
  # get command, unalias it, and look it up in commands
1063 a8083063 Iustin Pop
  cmd = argv.pop(1)
1064 de47cf8f Guido Trotter
  if cmd in aliases:
1065 de47cf8f Guido Trotter
    if cmd in commands:
1066 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' overrides an existing"
1067 de47cf8f Guido Trotter
                                   " command" % cmd)
1068 de47cf8f Guido Trotter
1069 de47cf8f Guido Trotter
    if aliases[cmd] not in commands:
1070 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' maps to non-existing"
1071 de47cf8f Guido Trotter
                                   " command '%s'" % (cmd, aliases[cmd]))
1072 de47cf8f Guido Trotter
1073 de47cf8f Guido Trotter
    cmd = aliases[cmd]
1074 de47cf8f Guido Trotter
1075 a8005e17 Michael Hanselmann
  func, args_def, parser_opts, usage, description = commands[cmd]
1076 064c21f8 Iustin Pop
  parser = OptionParser(option_list=parser_opts + [_DRY_RUN_OPT, DEBUG_OPT],
1077 a8083063 Iustin Pop
                        description=description,
1078 a8083063 Iustin Pop
                        formatter=TitledHelpFormatter(),
1079 a8083063 Iustin Pop
                        usage="%%prog %s %s" % (cmd, usage))
1080 a8083063 Iustin Pop
  parser.disable_interspersed_args()
1081 a8083063 Iustin Pop
  options, args = parser.parse_args()
1082 a8005e17 Michael Hanselmann
1083 a8005e17 Michael Hanselmann
  if not _CheckArguments(cmd, args_def, args):
1084 a8083063 Iustin Pop
    return None, None, None
1085 a8083063 Iustin Pop
1086 a8083063 Iustin Pop
  return func, options, args
1087 a8083063 Iustin Pop
1088 a8083063 Iustin Pop
1089 a8005e17 Michael Hanselmann
def _CheckArguments(cmd, args_def, args):
1090 a8005e17 Michael Hanselmann
  """Verifies the arguments using the argument definition.
1091 a8005e17 Michael Hanselmann

1092 a8005e17 Michael Hanselmann
  Algorithm:
1093 a8005e17 Michael Hanselmann

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

1096 a8005e17 Michael Hanselmann
    1. For each argument in definition
1097 a8005e17 Michael Hanselmann

1098 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
1099 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
1100 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
1101 a8005e17 Michael Hanselmann

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

1104 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
1105 a8005e17 Michael Hanselmann

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

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

1110 a8005e17 Michael Hanselmann
  """
1111 a8005e17 Michael Hanselmann
  if args and not args_def:
1112 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects no arguments", cmd)
1113 a8005e17 Michael Hanselmann
    return False
1114 a8005e17 Michael Hanselmann
1115 a8005e17 Michael Hanselmann
  min_count = None
1116 a8005e17 Michael Hanselmann
  max_count = None
1117 a8005e17 Michael Hanselmann
  check_max = None
1118 a8005e17 Michael Hanselmann
1119 a8005e17 Michael Hanselmann
  last_idx = len(args_def) - 1
1120 a8005e17 Michael Hanselmann
1121 a8005e17 Michael Hanselmann
  for idx, arg in enumerate(args_def):
1122 a8005e17 Michael Hanselmann
    if min_count is None:
1123 a8005e17 Michael Hanselmann
      min_count = arg.min
1124 a8005e17 Michael Hanselmann
    elif arg.min is not None:
1125 a8005e17 Michael Hanselmann
      min_count += arg.min
1126 a8005e17 Michael Hanselmann
1127 a8005e17 Michael Hanselmann
    if max_count is None:
1128 a8005e17 Michael Hanselmann
      max_count = arg.max
1129 a8005e17 Michael Hanselmann
    elif arg.max is not None:
1130 a8005e17 Michael Hanselmann
      max_count += arg.max
1131 a8005e17 Michael Hanselmann
1132 a8005e17 Michael Hanselmann
    if idx == last_idx:
1133 a8005e17 Michael Hanselmann
      check_max = (arg.max is not None)
1134 a8005e17 Michael Hanselmann
1135 a8005e17 Michael Hanselmann
    elif arg.max is None:
1136 a8005e17 Michael Hanselmann
      raise errors.ProgrammerError("Only the last argument can have max=None")
1137 a8005e17 Michael Hanselmann
1138 a8005e17 Michael Hanselmann
  if check_max:
1139 a8005e17 Michael Hanselmann
    # Command with exact number of arguments
1140 a8005e17 Michael Hanselmann
    if (min_count is not None and max_count is not None and
1141 a8005e17 Michael Hanselmann
        min_count == max_count and len(args) != min_count):
1142 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects %d argument(s)", cmd, min_count)
1143 a8005e17 Michael Hanselmann
      return False
1144 a8005e17 Michael Hanselmann
1145 a8005e17 Michael Hanselmann
    # Command with limited number of arguments
1146 a8005e17 Michael Hanselmann
    if max_count is not None and len(args) > max_count:
1147 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects only %d argument(s)",
1148 a8005e17 Michael Hanselmann
               cmd, max_count)
1149 a8005e17 Michael Hanselmann
      return False
1150 a8005e17 Michael Hanselmann
1151 a8005e17 Michael Hanselmann
  # Command with some required arguments
1152 a8005e17 Michael Hanselmann
  if min_count is not None and len(args) < min_count:
1153 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects at least %d argument(s)",
1154 a8005e17 Michael Hanselmann
             cmd, min_count)
1155 a8005e17 Michael Hanselmann
    return False
1156 a8005e17 Michael Hanselmann
1157 a8005e17 Michael Hanselmann
  return True
1158 a8005e17 Michael Hanselmann
1159 a8005e17 Michael Hanselmann
1160 60d49723 Michael Hanselmann
def SplitNodeOption(value):
1161 60d49723 Michael Hanselmann
  """Splits the value of a --node option.
1162 60d49723 Michael Hanselmann

1163 60d49723 Michael Hanselmann
  """
1164 60d49723 Michael Hanselmann
  if value and ':' in value:
1165 60d49723 Michael Hanselmann
    return value.split(':', 1)
1166 60d49723 Michael Hanselmann
  else:
1167 60d49723 Michael Hanselmann
    return (value, None)
1168 60d49723 Michael Hanselmann
1169 60d49723 Michael Hanselmann
1170 07150497 Guido Trotter
def CalculateOSNames(os_name, os_variants):
1171 07150497 Guido Trotter
  """Calculates all the names an OS can be called, according to its variants.
1172 07150497 Guido Trotter

1173 07150497 Guido Trotter
  @type os_name: string
1174 07150497 Guido Trotter
  @param os_name: base name of the os
1175 07150497 Guido Trotter
  @type os_variants: list or None
1176 07150497 Guido Trotter
  @param os_variants: list of supported variants
1177 07150497 Guido Trotter
  @rtype: list
1178 07150497 Guido Trotter
  @return: list of valid names
1179 07150497 Guido Trotter

1180 07150497 Guido Trotter
  """
1181 07150497 Guido Trotter
  if os_variants:
1182 07150497 Guido Trotter
    return ['%s+%s' % (os_name, v) for v in os_variants]
1183 07150497 Guido Trotter
  else:
1184 07150497 Guido Trotter
    return [os_name]
1185 07150497 Guido Trotter
1186 07150497 Guido Trotter
1187 4331f6cd Michael Hanselmann
def UsesRPC(fn):
1188 4331f6cd Michael Hanselmann
  def wrapper(*args, **kwargs):
1189 4331f6cd Michael Hanselmann
    rpc.Init()
1190 4331f6cd Michael Hanselmann
    try:
1191 4331f6cd Michael Hanselmann
      return fn(*args, **kwargs)
1192 4331f6cd Michael Hanselmann
    finally:
1193 4331f6cd Michael Hanselmann
      rpc.Shutdown()
1194 4331f6cd Michael Hanselmann
  return wrapper
1195 4331f6cd Michael Hanselmann
1196 4331f6cd Michael Hanselmann
1197 47988778 Iustin Pop
def AskUser(text, choices=None):
1198 47988778 Iustin Pop
  """Ask the user a question.
1199 a8083063 Iustin Pop

1200 c41eea6e Iustin Pop
  @param text: the question to ask
1201 a8083063 Iustin Pop

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

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

1211 a8083063 Iustin Pop
  """
1212 47988778 Iustin Pop
  if choices is None:
1213 47988778 Iustin Pop
    choices = [('y', True, 'Perform the operation'),
1214 47988778 Iustin Pop
               ('n', False, 'Do not perform the operation')]
1215 47988778 Iustin Pop
  if not choices or not isinstance(choices, list):
1216 5bbd3f7f Michael Hanselmann
    raise errors.ProgrammerError("Invalid choices argument to AskUser")
1217 47988778 Iustin Pop
  for entry in choices:
1218 47988778 Iustin Pop
    if not isinstance(entry, tuple) or len(entry) < 3 or entry[0] == '?':
1219 5bbd3f7f Michael Hanselmann
      raise errors.ProgrammerError("Invalid choices element to AskUser")
1220 47988778 Iustin Pop
1221 47988778 Iustin Pop
  answer = choices[-1][1]
1222 47988778 Iustin Pop
  new_text = []
1223 47988778 Iustin Pop
  for line in text.splitlines():
1224 47988778 Iustin Pop
    new_text.append(textwrap.fill(line, 70, replace_whitespace=False))
1225 47988778 Iustin Pop
  text = "\n".join(new_text)
1226 a8083063 Iustin Pop
  try:
1227 3023170f Iustin Pop
    f = file("/dev/tty", "a+")
1228 a8083063 Iustin Pop
  except IOError:
1229 47988778 Iustin Pop
    return answer
1230 a8083063 Iustin Pop
  try:
1231 47988778 Iustin Pop
    chars = [entry[0] for entry in choices]
1232 47988778 Iustin Pop
    chars[-1] = "[%s]" % chars[-1]
1233 47988778 Iustin Pop
    chars.append('?')
1234 47988778 Iustin Pop
    maps = dict([(entry[0], entry[1]) for entry in choices])
1235 47988778 Iustin Pop
    while True:
1236 47988778 Iustin Pop
      f.write(text)
1237 47988778 Iustin Pop
      f.write('\n')
1238 47988778 Iustin Pop
      f.write("/".join(chars))
1239 47988778 Iustin Pop
      f.write(": ")
1240 47988778 Iustin Pop
      line = f.readline(2).strip().lower()
1241 47988778 Iustin Pop
      if line in maps:
1242 47988778 Iustin Pop
        answer = maps[line]
1243 47988778 Iustin Pop
        break
1244 47988778 Iustin Pop
      elif line == '?':
1245 47988778 Iustin Pop
        for entry in choices:
1246 47988778 Iustin Pop
          f.write(" %s - %s\n" % (entry[0], entry[2]))
1247 47988778 Iustin Pop
        f.write("\n")
1248 47988778 Iustin Pop
        continue
1249 a8083063 Iustin Pop
  finally:
1250 a8083063 Iustin Pop
    f.close()
1251 a8083063 Iustin Pop
  return answer
1252 a8083063 Iustin Pop
1253 a8083063 Iustin Pop
1254 e9d741b6 Iustin Pop
class JobSubmittedException(Exception):
1255 e9d741b6 Iustin Pop
  """Job was submitted, client should exit.
1256 e9d741b6 Iustin Pop

1257 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1258 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1259 e9d741b6 Iustin Pop

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

1262 e9d741b6 Iustin Pop
  """
1263 e9d741b6 Iustin Pop
1264 e9d741b6 Iustin Pop
1265 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1266 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1267 a8083063 Iustin Pop

1268 0a1e74d9 Iustin Pop
  @type ops: list
1269 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1270 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1271 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1272 0a1e74d9 Iustin Pop
             if None, a new client will be created
1273 a8083063 Iustin Pop

1274 a8083063 Iustin Pop
  """
1275 e2212007 Iustin Pop
  if cl is None:
1276 b33e986b Iustin Pop
    cl = GetClient()
1277 685ee993 Iustin Pop
1278 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1279 0a1e74d9 Iustin Pop
1280 0a1e74d9 Iustin Pop
  return job_id
1281 0a1e74d9 Iustin Pop
1282 0a1e74d9 Iustin Pop
1283 4e338533 Michael Hanselmann
def GenericPollJob(job_id, cbs, report_cbs):
1284 4e338533 Michael Hanselmann
  """Generic job-polling function.
1285 0a1e74d9 Iustin Pop

1286 4e338533 Michael Hanselmann
  @type job_id: number
1287 4e338533 Michael Hanselmann
  @param job_id: Job ID
1288 4e338533 Michael Hanselmann
  @type cbs: Instance of L{JobPollCbBase}
1289 4e338533 Michael Hanselmann
  @param cbs: Data callbacks
1290 4e338533 Michael Hanselmann
  @type report_cbs: Instance of L{JobPollReportCbBase}
1291 4e338533 Michael Hanselmann
  @param report_cbs: Reporting callbacks
1292 0a1e74d9 Iustin Pop

1293 0a1e74d9 Iustin Pop
  """
1294 6c5a7090 Michael Hanselmann
  prev_job_info = None
1295 6c5a7090 Michael Hanselmann
  prev_logmsg_serial = None
1296 6c5a7090 Michael Hanselmann
1297 f4484122 Michael Hanselmann
  status = None
1298 f4484122 Michael Hanselmann
1299 685ee993 Iustin Pop
  while True:
1300 4e338533 Michael Hanselmann
    result = cbs.WaitForJobChangeOnce(job_id, ["status"], prev_job_info,
1301 4e338533 Michael Hanselmann
                                      prev_logmsg_serial)
1302 6c5a7090 Michael Hanselmann
    if not result:
1303 685ee993 Iustin Pop
      # job not found, go away!
1304 0bbe448c Michael Hanselmann
      raise errors.JobLost("Job with id %s lost" % job_id)
1305 4e338533 Michael Hanselmann
1306 4e338533 Michael Hanselmann
    if result == constants.JOB_NOTCHANGED:
1307 4e338533 Michael Hanselmann
      report_cbs.ReportNotChanged(job_id, status)
1308 f4484122 Michael Hanselmann
1309 f4484122 Michael Hanselmann
      # Wait again
1310 f4484122 Michael Hanselmann
      continue
1311 685ee993 Iustin Pop
1312 6c5a7090 Michael Hanselmann
    # Split result, a tuple of (field values, log entries)
1313 6c5a7090 Michael Hanselmann
    (job_info, log_entries) = result
1314 6c5a7090 Michael Hanselmann
    (status, ) = job_info
1315 6c5a7090 Michael Hanselmann
1316 6c5a7090 Michael Hanselmann
    if log_entries:
1317 6c5a7090 Michael Hanselmann
      for log_entry in log_entries:
1318 4e338533 Michael Hanselmann
        (serial, timestamp, log_type, message) = log_entry
1319 4e338533 Michael Hanselmann
        report_cbs.ReportLogMessage(job_id, serial, timestamp,
1320 4e338533 Michael Hanselmann
                                    log_type, message)
1321 6c5a7090 Michael Hanselmann
        prev_logmsg_serial = max(prev_logmsg_serial, serial)
1322 6c5a7090 Michael Hanselmann
1323 0bbe448c Michael Hanselmann
    # TODO: Handle canceled and archived jobs
1324 fbf0262f Michael Hanselmann
    elif status in (constants.JOB_STATUS_SUCCESS,
1325 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_ERROR,
1326 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELING,
1327 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELED):
1328 685ee993 Iustin Pop
      break
1329 6c5a7090 Michael Hanselmann
1330 6c5a7090 Michael Hanselmann
    prev_job_info = job_info
1331 685ee993 Iustin Pop
1332 4e338533 Michael Hanselmann
  jobs = cbs.QueryJobs([job_id], ["status", "opstatus", "opresult"])
1333 0bbe448c Michael Hanselmann
  if not jobs:
1334 0bbe448c Michael Hanselmann
    raise errors.JobLost("Job with id %s lost" % job_id)
1335 685ee993 Iustin Pop
1336 0e050889 Iustin Pop
  status, opstatus, result = jobs[0]
1337 4e338533 Michael Hanselmann
1338 0bbe448c Michael Hanselmann
  if status == constants.JOB_STATUS_SUCCESS:
1339 53c04d04 Iustin Pop
    return result
1340 4e338533 Michael Hanselmann
1341 4e338533 Michael Hanselmann
  if status in (constants.JOB_STATUS_CANCELING, constants.JOB_STATUS_CANCELED):
1342 fbf0262f Michael Hanselmann
    raise errors.OpExecError("Job was canceled")
1343 4e338533 Michael Hanselmann
1344 4e338533 Michael Hanselmann
  has_ok = False
1345 4e338533 Michael Hanselmann
  for idx, (status, msg) in enumerate(zip(opstatus, result)):
1346 4e338533 Michael Hanselmann
    if status == constants.OP_STATUS_SUCCESS:
1347 4e338533 Michael Hanselmann
      has_ok = True
1348 4e338533 Michael Hanselmann
    elif status == constants.OP_STATUS_ERROR:
1349 4e338533 Michael Hanselmann
      errors.MaybeRaise(msg)
1350 4e338533 Michael Hanselmann
1351 4e338533 Michael Hanselmann
      if has_ok:
1352 4e338533 Michael Hanselmann
        raise errors.OpExecError("partial failure (opcode %d): %s" %
1353 4e338533 Michael Hanselmann
                                 (idx, msg))
1354 4e338533 Michael Hanselmann
1355 4e338533 Michael Hanselmann
      raise errors.OpExecError(str(msg))
1356 4e338533 Michael Hanselmann
1357 4e338533 Michael Hanselmann
  # default failure mode
1358 4e338533 Michael Hanselmann
  raise errors.OpExecError(result)
1359 4e338533 Michael Hanselmann
1360 4e338533 Michael Hanselmann
1361 4e338533 Michael Hanselmann
class JobPollCbBase:
1362 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} callbacks.
1363 4e338533 Michael Hanselmann

1364 4e338533 Michael Hanselmann
  """
1365 4e338533 Michael Hanselmann
  def __init__(self):
1366 4e338533 Michael Hanselmann
    """Initializes this class.
1367 4e338533 Michael Hanselmann

1368 4e338533 Michael Hanselmann
    """
1369 4e338533 Michael Hanselmann
1370 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1371 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1372 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1373 4e338533 Michael Hanselmann

1374 4e338533 Michael Hanselmann
    """
1375 4e338533 Michael Hanselmann
    raise NotImplementedError()
1376 4e338533 Michael Hanselmann
1377 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1378 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1379 4e338533 Michael Hanselmann

1380 4e338533 Michael Hanselmann
    @type job_ids: list of numbers
1381 4e338533 Michael Hanselmann
    @param job_ids: Job IDs
1382 4e338533 Michael Hanselmann
    @type fields: list of strings
1383 4e338533 Michael Hanselmann
    @param fields: Fields
1384 4e338533 Michael Hanselmann

1385 4e338533 Michael Hanselmann
    """
1386 4e338533 Michael Hanselmann
    raise NotImplementedError()
1387 4e338533 Michael Hanselmann
1388 4e338533 Michael Hanselmann
1389 4e338533 Michael Hanselmann
class JobPollReportCbBase:
1390 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} reporting callbacks.
1391 4e338533 Michael Hanselmann

1392 4e338533 Michael Hanselmann
  """
1393 4e338533 Michael Hanselmann
  def __init__(self):
1394 4e338533 Michael Hanselmann
    """Initializes this class.
1395 4e338533 Michael Hanselmann

1396 4e338533 Michael Hanselmann
    """
1397 4e338533 Michael Hanselmann
1398 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1399 4e338533 Michael Hanselmann
    """Handles a log message.
1400 4e338533 Michael Hanselmann

1401 4e338533 Michael Hanselmann
    """
1402 4e338533 Michael Hanselmann
    raise NotImplementedError()
1403 4e338533 Michael Hanselmann
1404 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1405 4e338533 Michael Hanselmann
    """Called for if a job hasn't changed in a while.
1406 4e338533 Michael Hanselmann

1407 4e338533 Michael Hanselmann
    @type job_id: number
1408 4e338533 Michael Hanselmann
    @param job_id: Job ID
1409 4e338533 Michael Hanselmann
    @type status: string or None
1410 4e338533 Michael Hanselmann
    @param status: Job status if available
1411 4e338533 Michael Hanselmann

1412 4e338533 Michael Hanselmann
    """
1413 4e338533 Michael Hanselmann
    raise NotImplementedError()
1414 4e338533 Michael Hanselmann
1415 4e338533 Michael Hanselmann
1416 4e338533 Michael Hanselmann
class _LuxiJobPollCb(JobPollCbBase):
1417 4e338533 Michael Hanselmann
  def __init__(self, cl):
1418 4e338533 Michael Hanselmann
    """Initializes this class.
1419 4e338533 Michael Hanselmann

1420 4e338533 Michael Hanselmann
    """
1421 4e338533 Michael Hanselmann
    JobPollCbBase.__init__(self)
1422 4e338533 Michael Hanselmann
    self.cl = cl
1423 4e338533 Michael Hanselmann
1424 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1425 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1426 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1427 4e338533 Michael Hanselmann

1428 4e338533 Michael Hanselmann
    """
1429 4e338533 Michael Hanselmann
    return self.cl.WaitForJobChangeOnce(job_id, fields,
1430 4e338533 Michael Hanselmann
                                        prev_job_info, prev_log_serial)
1431 4e338533 Michael Hanselmann
1432 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1433 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1434 4e338533 Michael Hanselmann

1435 4e338533 Michael Hanselmann
    """
1436 4e338533 Michael Hanselmann
    return self.cl.QueryJobs(job_ids, fields)
1437 4e338533 Michael Hanselmann
1438 4e338533 Michael Hanselmann
1439 4e338533 Michael Hanselmann
class FeedbackFnJobPollReportCb(JobPollReportCbBase):
1440 4e338533 Michael Hanselmann
  def __init__(self, feedback_fn):
1441 4e338533 Michael Hanselmann
    """Initializes this class.
1442 4e338533 Michael Hanselmann

1443 4e338533 Michael Hanselmann
    """
1444 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1445 4e338533 Michael Hanselmann
1446 4e338533 Michael Hanselmann
    self.feedback_fn = feedback_fn
1447 4e338533 Michael Hanselmann
1448 4e338533 Michael Hanselmann
    assert callable(feedback_fn)
1449 4e338533 Michael Hanselmann
1450 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1451 4e338533 Michael Hanselmann
    """Handles a log message.
1452 4e338533 Michael Hanselmann

1453 4e338533 Michael Hanselmann
    """
1454 4e338533 Michael Hanselmann
    self.feedback_fn((timestamp, log_type, log_msg))
1455 4e338533 Michael Hanselmann
1456 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1457 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1458 4e338533 Michael Hanselmann

1459 4e338533 Michael Hanselmann
    """
1460 4e338533 Michael Hanselmann
    # Ignore
1461 4e338533 Michael Hanselmann
1462 4e338533 Michael Hanselmann
1463 4e338533 Michael Hanselmann
class StdioJobPollReportCb(JobPollReportCbBase):
1464 4e338533 Michael Hanselmann
  def __init__(self):
1465 4e338533 Michael Hanselmann
    """Initializes this class.
1466 4e338533 Michael Hanselmann

1467 4e338533 Michael Hanselmann
    """
1468 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1469 4e338533 Michael Hanselmann
1470 4e338533 Michael Hanselmann
    self.notified_queued = False
1471 4e338533 Michael Hanselmann
    self.notified_waitlock = False
1472 4e338533 Michael Hanselmann
1473 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1474 4e338533 Michael Hanselmann
    """Handles a log message.
1475 4e338533 Michael Hanselmann

1476 4e338533 Michael Hanselmann
    """
1477 4e338533 Michael Hanselmann
    ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)),
1478 8a7f1c61 Michael Hanselmann
             FormatLogMessage(log_type, log_msg))
1479 4e338533 Michael Hanselmann
1480 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1481 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1482 4e338533 Michael Hanselmann

1483 4e338533 Michael Hanselmann
    """
1484 4e338533 Michael Hanselmann
    if status is None:
1485 4e338533 Michael Hanselmann
      return
1486 4e338533 Michael Hanselmann
1487 4e338533 Michael Hanselmann
    if status == constants.JOB_STATUS_QUEUED and not self.notified_queued:
1488 4e338533 Michael Hanselmann
      ToStderr("Job %s is waiting in queue", job_id)
1489 4e338533 Michael Hanselmann
      self.notified_queued = True
1490 4e338533 Michael Hanselmann
1491 4e338533 Michael Hanselmann
    elif status == constants.JOB_STATUS_WAITLOCK and not self.notified_waitlock:
1492 4e338533 Michael Hanselmann
      ToStderr("Job %s is trying to acquire all necessary locks", job_id)
1493 4e338533 Michael Hanselmann
      self.notified_waitlock = True
1494 4e338533 Michael Hanselmann
1495 4e338533 Michael Hanselmann
1496 8a7f1c61 Michael Hanselmann
def FormatLogMessage(log_type, log_msg):
1497 8a7f1c61 Michael Hanselmann
  """Formats a job message according to its type.
1498 8a7f1c61 Michael Hanselmann

1499 8a7f1c61 Michael Hanselmann
  """
1500 8a7f1c61 Michael Hanselmann
  if log_type != constants.ELOG_MESSAGE:
1501 8a7f1c61 Michael Hanselmann
    log_msg = str(log_msg)
1502 8a7f1c61 Michael Hanselmann
1503 8a7f1c61 Michael Hanselmann
  return utils.SafeEncode(log_msg)
1504 8a7f1c61 Michael Hanselmann
1505 8a7f1c61 Michael Hanselmann
1506 583163a6 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None, reporter=None):
1507 4e338533 Michael Hanselmann
  """Function to poll for the result of a job.
1508 4e338533 Michael Hanselmann

1509 4e338533 Michael Hanselmann
  @type job_id: job identified
1510 4e338533 Michael Hanselmann
  @param job_id: the job to poll for results
1511 4e338533 Michael Hanselmann
  @type cl: luxi.Client
1512 4e338533 Michael Hanselmann
  @param cl: the luxi client to use for communicating with the master;
1513 4e338533 Michael Hanselmann
             if None, a new client will be created
1514 4e338533 Michael Hanselmann

1515 4e338533 Michael Hanselmann
  """
1516 4e338533 Michael Hanselmann
  if cl is None:
1517 4e338533 Michael Hanselmann
    cl = GetClient()
1518 4e338533 Michael Hanselmann
1519 583163a6 Michael Hanselmann
  if reporter is None:
1520 583163a6 Michael Hanselmann
    if feedback_fn:
1521 583163a6 Michael Hanselmann
      reporter = FeedbackFnJobPollReportCb(feedback_fn)
1522 583163a6 Michael Hanselmann
    else:
1523 583163a6 Michael Hanselmann
      reporter = StdioJobPollReportCb()
1524 583163a6 Michael Hanselmann
  elif feedback_fn:
1525 583163a6 Michael Hanselmann
    raise errors.ProgrammerError("Can't specify reporter and feedback function")
1526 4e338533 Michael Hanselmann
1527 4e338533 Michael Hanselmann
  return GenericPollJob(job_id, _LuxiJobPollCb(cl), reporter)
1528 ceab32dd Iustin Pop
1529 ceab32dd Iustin Pop
1530 583163a6 Michael Hanselmann
def SubmitOpCode(op, cl=None, feedback_fn=None, opts=None, reporter=None):
1531 0a1e74d9 Iustin Pop
  """Legacy function to submit an opcode.
1532 0a1e74d9 Iustin Pop

1533 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1534 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1535 0a1e74d9 Iustin Pop
  interaction functions.
1536 0a1e74d9 Iustin Pop

1537 0a1e74d9 Iustin Pop
  """
1538 0a1e74d9 Iustin Pop
  if cl is None:
1539 0a1e74d9 Iustin Pop
    cl = GetClient()
1540 0a1e74d9 Iustin Pop
1541 293ba2d8 Iustin Pop
  SetGenericOpcodeOpts([op], opts)
1542 293ba2d8 Iustin Pop
1543 0a1e74d9 Iustin Pop
  job_id = SendJob([op], cl)
1544 0a1e74d9 Iustin Pop
1545 583163a6 Michael Hanselmann
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn,
1546 583163a6 Michael Hanselmann
                       reporter=reporter)
1547 53c04d04 Iustin Pop
1548 53c04d04 Iustin Pop
  return op_results[0]
1549 0a1e74d9 Iustin Pop
1550 0a1e74d9 Iustin Pop
1551 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1552 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1553 94428652 Iustin Pop

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

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

1562 94428652 Iustin Pop
  """
1563 94428652 Iustin Pop
  if opts and opts.submit_only:
1564 293ba2d8 Iustin Pop
    job = [op]
1565 293ba2d8 Iustin Pop
    SetGenericOpcodeOpts(job, opts)
1566 293ba2d8 Iustin Pop
    job_id = SendJob(job, cl=cl)
1567 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
1568 94428652 Iustin Pop
  else:
1569 293ba2d8 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
1570 293ba2d8 Iustin Pop
1571 293ba2d8 Iustin Pop
1572 293ba2d8 Iustin Pop
def SetGenericOpcodeOpts(opcode_list, options):
1573 293ba2d8 Iustin Pop
  """Processor for generic options.
1574 293ba2d8 Iustin Pop

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

1578 293ba2d8 Iustin Pop
  @param opcode_list: list of opcodes
1579 293ba2d8 Iustin Pop
  @param options: command line options or None
1580 293ba2d8 Iustin Pop
  @return: None (in-place modification)
1581 293ba2d8 Iustin Pop

1582 293ba2d8 Iustin Pop
  """
1583 293ba2d8 Iustin Pop
  if not options:
1584 293ba2d8 Iustin Pop
    return
1585 293ba2d8 Iustin Pop
  for op in opcode_list:
1586 293ba2d8 Iustin Pop
    op.dry_run = options.dry_run
1587 293ba2d8 Iustin Pop
    op.debug_level = options.debug
1588 94428652 Iustin Pop
1589 94428652 Iustin Pop
1590 af30b2fd Michael Hanselmann
def GetClient():
1591 af30b2fd Michael Hanselmann
  # TODO: Cache object?
1592 b33e986b Iustin Pop
  try:
1593 b33e986b Iustin Pop
    client = luxi.Client()
1594 b33e986b Iustin Pop
  except luxi.NoMasterError:
1595 d9a51679 Michael Hanselmann
    ss = ssconf.SimpleStore()
1596 d9a51679 Michael Hanselmann
1597 d9a51679 Michael Hanselmann
    # Try to read ssconf file
1598 d9a51679 Michael Hanselmann
    try:
1599 d9a51679 Michael Hanselmann
      ss.GetMasterNode()
1600 d9a51679 Michael Hanselmann
    except errors.ConfigurationError:
1601 d9a51679 Michael Hanselmann
      raise errors.OpPrereqError("Cluster not initialized or this machine is"
1602 d9a51679 Michael Hanselmann
                                 " not part of a cluster")
1603 d9a51679 Michael Hanselmann
1604 d9a51679 Michael Hanselmann
    master, myself = ssconf.GetMasterAndMyself(ss=ss)
1605 b33e986b Iustin Pop
    if master != myself:
1606 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
1607 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
1608 b33e986b Iustin Pop
                                 master)
1609 d9a51679 Michael Hanselmann
    raise
1610 b33e986b Iustin Pop
  return client
1611 af30b2fd Michael Hanselmann
1612 af30b2fd Michael Hanselmann
1613 73702ee7 Iustin Pop
def FormatError(err):
1614 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
1615 73702ee7 Iustin Pop

1616 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
1617 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
1618 73702ee7 Iustin Pop
  second, a string describing the error message (not
1619 73702ee7 Iustin Pop
  newline-terminated).
1620 73702ee7 Iustin Pop

1621 73702ee7 Iustin Pop
  """
1622 73702ee7 Iustin Pop
  retcode = 1
1623 73702ee7 Iustin Pop
  obuf = StringIO()
1624 e2e521d0 Iustin Pop
  msg = str(err)
1625 73702ee7 Iustin Pop
  if isinstance(err, errors.ConfigurationError):
1626 e2e521d0 Iustin Pop
    txt = "Corrupt configuration file: %s" % msg
1627 46fbdd04 Iustin Pop
    logging.error(txt)
1628 e2e521d0 Iustin Pop
    obuf.write(txt + "\n")
1629 73702ee7 Iustin Pop
    obuf.write("Aborting.")
1630 73702ee7 Iustin Pop
    retcode = 2
1631 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksAbort):
1632 73702ee7 Iustin Pop
    obuf.write("Failure: hooks execution failed:\n")
1633 73702ee7 Iustin Pop
    for node, script, out in err.args[0]:
1634 73702ee7 Iustin Pop
      if out:
1635 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s, output: %s\n" %
1636 73702ee7 Iustin Pop
                   (node, script, out))
1637 73702ee7 Iustin Pop
      else:
1638 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s (no output)\n" %
1639 73702ee7 Iustin Pop
                   (node, script))
1640 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksFailure):
1641 e2e521d0 Iustin Pop
    obuf.write("Failure: hooks general failure: %s" % msg)
1642 73702ee7 Iustin Pop
  elif isinstance(err, errors.ResolverError):
1643 a744b676 Manuel Franceschini
    this_host = netutils.HostInfo.SysName()
1644 73702ee7 Iustin Pop
    if err.args[0] == this_host:
1645 73702ee7 Iustin Pop
      msg = "Failure: can't resolve my own hostname ('%s')"
1646 73702ee7 Iustin Pop
    else:
1647 73702ee7 Iustin Pop
      msg = "Failure: can't resolve hostname '%s'"
1648 73702ee7 Iustin Pop
    obuf.write(msg % err.args[0])
1649 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpPrereqError):
1650 5c983ee5 Iustin Pop
    if len(err.args) == 2:
1651 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
1652 5c983ee5 Iustin Pop
               " operation:\nerror type: %s, error details:\n%s" %
1653 5c983ee5 Iustin Pop
                 (err.args[1], err.args[0]))
1654 5c983ee5 Iustin Pop
    else:
1655 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
1656 5c983ee5 Iustin Pop
                 " operation:\n%s" % msg)
1657 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpExecError):
1658 e2e521d0 Iustin Pop
    obuf.write("Failure: command execution error:\n%s" % msg)
1659 73702ee7 Iustin Pop
  elif isinstance(err, errors.TagError):
1660 e2e521d0 Iustin Pop
    obuf.write("Failure: invalid tag(s) given:\n%s" % msg)
1661 686d7433 Iustin Pop
  elif isinstance(err, errors.JobQueueDrainError):
1662 686d7433 Iustin Pop
    obuf.write("Failure: the job queue is marked for drain and doesn't"
1663 686d7433 Iustin Pop
               " accept new requests\n")
1664 f87b405e Michael Hanselmann
  elif isinstance(err, errors.JobQueueFull):
1665 f87b405e Michael Hanselmann
    obuf.write("Failure: the job queue is full and doesn't accept new"
1666 f87b405e Michael Hanselmann
               " job submissions until old jobs are archived\n")
1667 a5728081 Guido Trotter
  elif isinstance(err, errors.TypeEnforcementError):
1668 a5728081 Guido Trotter
    obuf.write("Parameter Error: %s" % msg)
1669 c1ce76bb Iustin Pop
  elif isinstance(err, errors.ParameterError):
1670 c1ce76bb Iustin Pop
    obuf.write("Failure: unknown/wrong parameter name '%s'" % msg)
1671 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.NoMasterError):
1672 03a8dbdc Iustin Pop
    obuf.write("Cannot communicate with the master daemon.\nIs it running"
1673 082c5adb Michael Hanselmann
               " and listening for connections?")
1674 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.TimeoutError):
1675 03a8dbdc Iustin Pop
    obuf.write("Timeout while talking to the master daemon. Error:\n"
1676 03a8dbdc Iustin Pop
               "%s" % msg)
1677 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.ProtocolError):
1678 03a8dbdc Iustin Pop
    obuf.write("Unhandled protocol error while talking to the master daemon:\n"
1679 03a8dbdc Iustin Pop
               "%s" % msg)
1680 797506fc Michael Hanselmann
  elif isinstance(err, errors.GenericError):
1681 797506fc Michael Hanselmann
    obuf.write("Unhandled Ganeti error: %s" % msg)
1682 e9d741b6 Iustin Pop
  elif isinstance(err, JobSubmittedException):
1683 e9d741b6 Iustin Pop
    obuf.write("JobID: %s\n" % err.args[0])
1684 e9d741b6 Iustin Pop
    retcode = 0
1685 73702ee7 Iustin Pop
  else:
1686 e2e521d0 Iustin Pop
    obuf.write("Unhandled exception: %s" % msg)
1687 73702ee7 Iustin Pop
  return retcode, obuf.getvalue().rstrip('\n')
1688 73702ee7 Iustin Pop
1689 73702ee7 Iustin Pop
1690 de47cf8f Guido Trotter
def GenericMain(commands, override=None, aliases=None):
1691 a8083063 Iustin Pop
  """Generic main function for all the gnt-* commands.
1692 a8083063 Iustin Pop

1693 334d1483 Iustin Pop
  Arguments:
1694 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
1695 334d1483 Iustin Pop
                for command line handling.
1696 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
1697 334d1483 Iustin Pop
                override command line options; this can be used to pass
1698 334d1483 Iustin Pop
                options from the scripts to generic functions
1699 de47cf8f Guido Trotter
    - aliases: dictionary with command aliases {'alias': 'target, ...}
1700 a8083063 Iustin Pop

1701 a8083063 Iustin Pop
  """
1702 a8083063 Iustin Pop
  # save the program name and the entire command line for later logging
1703 a8083063 Iustin Pop
  if sys.argv:
1704 a8083063 Iustin Pop
    binary = os.path.basename(sys.argv[0]) or sys.argv[0]
1705 a8083063 Iustin Pop
    if len(sys.argv) >= 2:
1706 a8083063 Iustin Pop
      binary += " " + sys.argv[1]
1707 a8083063 Iustin Pop
      old_cmdline = " ".join(sys.argv[2:])
1708 a8083063 Iustin Pop
    else:
1709 a8083063 Iustin Pop
      old_cmdline = ""
1710 a8083063 Iustin Pop
  else:
1711 a8083063 Iustin Pop
    binary = "<unknown program>"
1712 a8083063 Iustin Pop
    old_cmdline = ""
1713 a8083063 Iustin Pop
1714 de47cf8f Guido Trotter
  if aliases is None:
1715 de47cf8f Guido Trotter
    aliases = {}
1716 de47cf8f Guido Trotter
1717 3126878d Guido Trotter
  try:
1718 3126878d Guido Trotter
    func, options, args = _ParseArgs(sys.argv, commands, aliases)
1719 3126878d Guido Trotter
  except errors.ParameterError, err:
1720 3126878d Guido Trotter
    result, err_msg = FormatError(err)
1721 3126878d Guido Trotter
    ToStderr(err_msg)
1722 3126878d Guido Trotter
    return 1
1723 3126878d Guido Trotter
1724 a8083063 Iustin Pop
  if func is None: # parse error
1725 a8083063 Iustin Pop
    return 1
1726 a8083063 Iustin Pop
1727 334d1483 Iustin Pop
  if override is not None:
1728 334d1483 Iustin Pop
    for key, val in override.iteritems():
1729 334d1483 Iustin Pop
      setattr(options, key, val)
1730 334d1483 Iustin Pop
1731 82d9caef Iustin Pop
  utils.SetupLogging(constants.LOG_COMMANDS, debug=options.debug,
1732 82d9caef Iustin Pop
                     stderr_logging=True, program=binary)
1733 a8083063 Iustin Pop
1734 a8083063 Iustin Pop
  if old_cmdline:
1735 46fbdd04 Iustin Pop
    logging.info("run with arguments '%s'", old_cmdline)
1736 a8083063 Iustin Pop
  else:
1737 46fbdd04 Iustin Pop
    logging.info("run with no arguments")
1738 a8083063 Iustin Pop
1739 a8083063 Iustin Pop
  try:
1740 a4af651e Iustin Pop
    result = func(options, args)
1741 d8353c3a Iustin Pop
  except (errors.GenericError, luxi.ProtocolError,
1742 d8353c3a Iustin Pop
          JobSubmittedException), err:
1743 a4af651e Iustin Pop
    result, err_msg = FormatError(err)
1744 5bbd3f7f Michael Hanselmann
    logging.exception("Error during command processing")
1745 46fbdd04 Iustin Pop
    ToStderr(err_msg)
1746 a8083063 Iustin Pop
1747 a8083063 Iustin Pop
  return result
1748 137161c9 Michael Hanselmann
1749 137161c9 Michael Hanselmann
1750 d77490c5 Iustin Pop
def GenericInstanceCreate(mode, opts, args):
1751 d77490c5 Iustin Pop
  """Add an instance to the cluster via either creation or import.
1752 d77490c5 Iustin Pop

1753 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
1754 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
1755 d77490c5 Iustin Pop
  @type args: list
1756 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
1757 d77490c5 Iustin Pop
  @rtype: int
1758 d77490c5 Iustin Pop
  @return: the desired exit code
1759 d77490c5 Iustin Pop

1760 d77490c5 Iustin Pop
  """
1761 d77490c5 Iustin Pop
  instance = args[0]
1762 d77490c5 Iustin Pop
1763 d77490c5 Iustin Pop
  (pnode, snode) = SplitNodeOption(opts.node)
1764 d77490c5 Iustin Pop
1765 d77490c5 Iustin Pop
  hypervisor = None
1766 d77490c5 Iustin Pop
  hvparams = {}
1767 d77490c5 Iustin Pop
  if opts.hypervisor:
1768 d77490c5 Iustin Pop
    hypervisor, hvparams = opts.hypervisor
1769 d77490c5 Iustin Pop
1770 d77490c5 Iustin Pop
  if opts.nics:
1771 d77490c5 Iustin Pop
    try:
1772 21bcb9aa Michael Hanselmann
      nic_max = max(int(nidx[0]) + 1 for nidx in opts.nics)
1773 d77490c5 Iustin Pop
    except ValueError, err:
1774 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Invalid NIC index passed: %s" % str(err))
1775 d77490c5 Iustin Pop
    nics = [{}] * nic_max
1776 d77490c5 Iustin Pop
    for nidx, ndict in opts.nics:
1777 d77490c5 Iustin Pop
      nidx = int(nidx)
1778 d77490c5 Iustin Pop
      if not isinstance(ndict, dict):
1779 d77490c5 Iustin Pop
        msg = "Invalid nic/%d value: expected dict, got %s" % (nidx, ndict)
1780 d77490c5 Iustin Pop
        raise errors.OpPrereqError(msg)
1781 d77490c5 Iustin Pop
      nics[nidx] = ndict
1782 d77490c5 Iustin Pop
  elif opts.no_nics:
1783 d77490c5 Iustin Pop
    # no nics
1784 d77490c5 Iustin Pop
    nics = []
1785 0af0f641 Iustin Pop
  elif mode == constants.INSTANCE_CREATE:
1786 d77490c5 Iustin Pop
    # default of one nic, all auto
1787 d77490c5 Iustin Pop
    nics = [{}]
1788 0af0f641 Iustin Pop
  else:
1789 0af0f641 Iustin Pop
    # mode == import
1790 0af0f641 Iustin Pop
    nics = []
1791 d77490c5 Iustin Pop
1792 d77490c5 Iustin Pop
  if opts.disk_template == constants.DT_DISKLESS:
1793 d77490c5 Iustin Pop
    if opts.disks or opts.sd_size is not None:
1794 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Diskless instance but disk"
1795 d77490c5 Iustin Pop
                                 " information passed")
1796 d77490c5 Iustin Pop
    disks = []
1797 d77490c5 Iustin Pop
  else:
1798 9b12ed0f Iustin Pop
    if (not opts.disks and not opts.sd_size
1799 9b12ed0f Iustin Pop
        and mode == constants.INSTANCE_CREATE):
1800 d77490c5 Iustin Pop
      raise errors.OpPrereqError("No disk information specified")
1801 d77490c5 Iustin Pop
    if opts.disks and opts.sd_size is not None:
1802 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Please use either the '--disk' or"
1803 d77490c5 Iustin Pop
                                 " '-s' option")
1804 d77490c5 Iustin Pop
    if opts.sd_size is not None:
1805 d77490c5 Iustin Pop
      opts.disks = [(0, {"size": opts.sd_size})]
1806 9b12ed0f Iustin Pop
1807 9b12ed0f Iustin Pop
    if opts.disks:
1808 9b12ed0f Iustin Pop
      try:
1809 9b12ed0f Iustin Pop
        disk_max = max(int(didx[0]) + 1 for didx in opts.disks)
1810 9b12ed0f Iustin Pop
      except ValueError, err:
1811 9b12ed0f Iustin Pop
        raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err))
1812 9b12ed0f Iustin Pop
      disks = [{}] * disk_max
1813 9b12ed0f Iustin Pop
    else:
1814 9b12ed0f Iustin Pop
      disks = []
1815 d77490c5 Iustin Pop
    for didx, ddict in opts.disks:
1816 d77490c5 Iustin Pop
      didx = int(didx)
1817 d77490c5 Iustin Pop
      if not isinstance(ddict, dict):
1818 d77490c5 Iustin Pop
        msg = "Invalid disk/%d value: expected dict, got %s" % (didx, ddict)
1819 d77490c5 Iustin Pop
        raise errors.OpPrereqError(msg)
1820 5029db65 Iustin Pop
      elif "size" in ddict:
1821 5029db65 Iustin Pop
        if "adopt" in ddict:
1822 5029db65 Iustin Pop
          raise errors.OpPrereqError("Only one of 'size' and 'adopt' allowed"
1823 5029db65 Iustin Pop
                                     " (disk %d)" % didx)
1824 5029db65 Iustin Pop
        try:
1825 5029db65 Iustin Pop
          ddict["size"] = utils.ParseUnit(ddict["size"])
1826 5029db65 Iustin Pop
        except ValueError, err:
1827 5029db65 Iustin Pop
          raise errors.OpPrereqError("Invalid disk size for disk %d: %s" %
1828 5029db65 Iustin Pop
                                     (didx, err))
1829 5029db65 Iustin Pop
      elif "adopt" in ddict:
1830 5029db65 Iustin Pop
        if mode == constants.INSTANCE_IMPORT:
1831 5029db65 Iustin Pop
          raise errors.OpPrereqError("Disk adoption not allowed for instance"
1832 5029db65 Iustin Pop
                                     " import")
1833 5029db65 Iustin Pop
        ddict["size"] = 0
1834 5029db65 Iustin Pop
      else:
1835 5029db65 Iustin Pop
        raise errors.OpPrereqError("Missing size or adoption source for"
1836 5029db65 Iustin Pop
                                   " disk %d" % didx)
1837 d77490c5 Iustin Pop
      disks[didx] = ddict
1838 d77490c5 Iustin Pop
1839 d77490c5 Iustin Pop
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_TYPES)
1840 d77490c5 Iustin Pop
  utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
1841 d77490c5 Iustin Pop
1842 d77490c5 Iustin Pop
  if mode == constants.INSTANCE_CREATE:
1843 d77490c5 Iustin Pop
    start = opts.start
1844 d77490c5 Iustin Pop
    os_type = opts.os
1845 1ee8e01a Guido Trotter
    force_variant = opts.force_variant
1846 d77490c5 Iustin Pop
    src_node = None
1847 d77490c5 Iustin Pop
    src_path = None
1848 25a8792c Iustin Pop
    no_install = opts.no_install
1849 e588764d Iustin Pop
    identify_defaults = False
1850 d77490c5 Iustin Pop
  elif mode == constants.INSTANCE_IMPORT:
1851 d77490c5 Iustin Pop
    start = False
1852 d77490c5 Iustin Pop
    os_type = None
1853 1ee8e01a Guido Trotter
    force_variant = False
1854 d77490c5 Iustin Pop
    src_node = opts.src_node
1855 d77490c5 Iustin Pop
    src_path = opts.src_dir
1856 25a8792c Iustin Pop
    no_install = None
1857 e588764d Iustin Pop
    identify_defaults = opts.identify_defaults
1858 d77490c5 Iustin Pop
  else:
1859 d77490c5 Iustin Pop
    raise errors.ProgrammerError("Invalid creation mode %s" % mode)
1860 d77490c5 Iustin Pop
1861 d77490c5 Iustin Pop
  op = opcodes.OpCreateInstance(instance_name=instance,
1862 d77490c5 Iustin Pop
                                disks=disks,
1863 d77490c5 Iustin Pop
                                disk_template=opts.disk_template,
1864 d77490c5 Iustin Pop
                                nics=nics,
1865 d77490c5 Iustin Pop
                                pnode=pnode, snode=snode,
1866 d77490c5 Iustin Pop
                                ip_check=opts.ip_check,
1867 460d22be Iustin Pop
                                name_check=opts.name_check,
1868 d77490c5 Iustin Pop
                                wait_for_sync=opts.wait_for_sync,
1869 d77490c5 Iustin Pop
                                file_storage_dir=opts.file_storage_dir,
1870 d77490c5 Iustin Pop
                                file_driver=opts.file_driver,
1871 d77490c5 Iustin Pop
                                iallocator=opts.iallocator,
1872 d77490c5 Iustin Pop
                                hypervisor=hypervisor,
1873 d77490c5 Iustin Pop
                                hvparams=hvparams,
1874 d77490c5 Iustin Pop
                                beparams=opts.beparams,
1875 062a7100 Iustin Pop
                                osparams=opts.osparams,
1876 d77490c5 Iustin Pop
                                mode=mode,
1877 d77490c5 Iustin Pop
                                start=start,
1878 d77490c5 Iustin Pop
                                os_type=os_type,
1879 1ee8e01a Guido Trotter
                                force_variant=force_variant,
1880 d77490c5 Iustin Pop
                                src_node=src_node,
1881 25a8792c Iustin Pop
                                src_path=src_path,
1882 e588764d Iustin Pop
                                no_install=no_install,
1883 e588764d Iustin Pop
                                identify_defaults=identify_defaults)
1884 d77490c5 Iustin Pop
1885 d77490c5 Iustin Pop
  SubmitOrSend(op, opts)
1886 d77490c5 Iustin Pop
  return 0
1887 d77490c5 Iustin Pop
1888 d77490c5 Iustin Pop
1889 7e49b6ce Michael Hanselmann
class _RunWhileClusterStoppedHelper:
1890 7e49b6ce Michael Hanselmann
  """Helper class for L{RunWhileClusterStopped} to simplify state management
1891 7e49b6ce Michael Hanselmann

1892 7e49b6ce Michael Hanselmann
  """
1893 7e49b6ce Michael Hanselmann
  def __init__(self, feedback_fn, cluster_name, master_node, online_nodes):
1894 7e49b6ce Michael Hanselmann
    """Initializes this class.
1895 7e49b6ce Michael Hanselmann

1896 7e49b6ce Michael Hanselmann
    @type feedback_fn: callable
1897 7e49b6ce Michael Hanselmann
    @param feedback_fn: Feedback function
1898 7e49b6ce Michael Hanselmann
    @type cluster_name: string
1899 7e49b6ce Michael Hanselmann
    @param cluster_name: Cluster name
1900 7e49b6ce Michael Hanselmann
    @type master_node: string
1901 7e49b6ce Michael Hanselmann
    @param master_node Master node name
1902 7e49b6ce Michael Hanselmann
    @type online_nodes: list
1903 7e49b6ce Michael Hanselmann
    @param online_nodes: List of names of online nodes
1904 7e49b6ce Michael Hanselmann

1905 7e49b6ce Michael Hanselmann
    """
1906 7e49b6ce Michael Hanselmann
    self.feedback_fn = feedback_fn
1907 7e49b6ce Michael Hanselmann
    self.cluster_name = cluster_name
1908 7e49b6ce Michael Hanselmann
    self.master_node = master_node
1909 7e49b6ce Michael Hanselmann
    self.online_nodes = online_nodes
1910 7e49b6ce Michael Hanselmann
1911 7e49b6ce Michael Hanselmann
    self.ssh = ssh.SshRunner(self.cluster_name)
1912 7e49b6ce Michael Hanselmann
1913 7e49b6ce Michael Hanselmann
    self.nonmaster_nodes = [name for name in online_nodes
1914 7e49b6ce Michael Hanselmann
                            if name != master_node]
1915 7e49b6ce Michael Hanselmann
1916 7e49b6ce Michael Hanselmann
    assert self.master_node not in self.nonmaster_nodes
1917 7e49b6ce Michael Hanselmann
1918 7e49b6ce Michael Hanselmann
  def _RunCmd(self, node_name, cmd):
1919 7e49b6ce Michael Hanselmann
    """Runs a command on the local or a remote machine.
1920 7e49b6ce Michael Hanselmann

1921 7e49b6ce Michael Hanselmann
    @type node_name: string
1922 7e49b6ce Michael Hanselmann
    @param node_name: Machine name
1923 7e49b6ce Michael Hanselmann
    @type cmd: list
1924 7e49b6ce Michael Hanselmann
    @param cmd: Command
1925 7e49b6ce Michael Hanselmann

1926 7e49b6ce Michael Hanselmann
    """
1927 7e49b6ce Michael Hanselmann
    if node_name is None or node_name == self.master_node:
1928 7e49b6ce Michael Hanselmann
      # No need to use SSH
1929 7e49b6ce Michael Hanselmann
      result = utils.RunCmd(cmd)
1930 7e49b6ce Michael Hanselmann
    else:
1931 7e49b6ce Michael Hanselmann
      result = self.ssh.Run(node_name, "root", utils.ShellQuoteArgs(cmd))
1932 7e49b6ce Michael Hanselmann
1933 7e49b6ce Michael Hanselmann
    if result.failed:
1934 7e49b6ce Michael Hanselmann
      errmsg = ["Failed to run command %s" % result.cmd]
1935 7e49b6ce Michael Hanselmann
      if node_name:
1936 7e49b6ce Michael Hanselmann
        errmsg.append("on node %s" % node_name)
1937 7e49b6ce Michael Hanselmann
      errmsg.append(": exitcode %s and error %s" %
1938 7e49b6ce Michael Hanselmann
                    (result.exit_code, result.output))
1939 7e49b6ce Michael Hanselmann
      raise errors.OpExecError(" ".join(errmsg))
1940 7e49b6ce Michael Hanselmann
1941 7e49b6ce Michael Hanselmann
  def Call(self, fn, *args):
1942 7e49b6ce Michael Hanselmann
    """Call function while all daemons are stopped.
1943 7e49b6ce Michael Hanselmann

1944 7e49b6ce Michael Hanselmann
    @type fn: callable
1945 7e49b6ce Michael Hanselmann
    @param fn: Function to be called
1946 7e49b6ce Michael Hanselmann

1947 7e49b6ce Michael Hanselmann
    """
1948 7e49b6ce Michael Hanselmann
    # Pause watcher by acquiring an exclusive lock on watcher state file
1949 7e49b6ce Michael Hanselmann
    self.feedback_fn("Blocking watcher")
1950 7e49b6ce Michael Hanselmann
    watcher_block = utils.FileLock.Open(constants.WATCHER_STATEFILE)
1951 7e49b6ce Michael Hanselmann
    try:
1952 7e49b6ce Michael Hanselmann
      # TODO: Currently, this just blocks. There's no timeout.
1953 7e49b6ce Michael Hanselmann
      # TODO: Should it be a shared lock?
1954 7e49b6ce Michael Hanselmann
      watcher_block.Exclusive(blocking=True)
1955 7e49b6ce Michael Hanselmann
1956 7e49b6ce Michael Hanselmann
      # Stop master daemons, so that no new jobs can come in and all running
1957 7e49b6ce Michael Hanselmann
      # ones are finished
1958 7e49b6ce Michael Hanselmann
      self.feedback_fn("Stopping master daemons")
1959 7e49b6ce Michael Hanselmann
      self._RunCmd(None, [constants.DAEMON_UTIL, "stop-master"])
1960 7e49b6ce Michael Hanselmann
      try:
1961 7e49b6ce Michael Hanselmann
        # Stop daemons on all nodes
1962 7e49b6ce Michael Hanselmann
        for node_name in self.online_nodes:
1963 7e49b6ce Michael Hanselmann
          self.feedback_fn("Stopping daemons on %s" % node_name)
1964 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "stop-all"])
1965 7e49b6ce Michael Hanselmann
1966 7e49b6ce Michael Hanselmann
        # All daemons are shut down now
1967 7e49b6ce Michael Hanselmann
        try:
1968 7e49b6ce Michael Hanselmann
          return fn(self, *args)
1969 d512e84b Michael Hanselmann
        except Exception, err:
1970 d512e84b Michael Hanselmann
          _, errmsg = FormatError(err)
1971 7e49b6ce Michael Hanselmann
          logging.exception("Caught exception")
1972 d512e84b Michael Hanselmann
          self.feedback_fn(errmsg)
1973 7e49b6ce Michael Hanselmann
          raise
1974 7e49b6ce Michael Hanselmann
      finally:
1975 7e49b6ce Michael Hanselmann
        # Start cluster again, master node last
1976 7e49b6ce Michael Hanselmann
        for node_name in self.nonmaster_nodes + [self.master_node]:
1977 7e49b6ce Michael Hanselmann
          self.feedback_fn("Starting daemons on %s" % node_name)
1978 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "start-all"])
1979 7e49b6ce Michael Hanselmann
    finally:
1980 7e49b6ce Michael Hanselmann
      # Resume watcher
1981 7e49b6ce Michael Hanselmann
      watcher_block.Close()
1982 7e49b6ce Michael Hanselmann
1983 7e49b6ce Michael Hanselmann
1984 7e49b6ce Michael Hanselmann
def RunWhileClusterStopped(feedback_fn, fn, *args):
1985 7e49b6ce Michael Hanselmann
  """Calls a function while all cluster daemons are stopped.
1986 7e49b6ce Michael Hanselmann

1987 7e49b6ce Michael Hanselmann
  @type feedback_fn: callable
1988 7e49b6ce Michael Hanselmann
  @param feedback_fn: Feedback function
1989 7e49b6ce Michael Hanselmann
  @type fn: callable
1990 7e49b6ce Michael Hanselmann
  @param fn: Function to be called when daemons are stopped
1991 7e49b6ce Michael Hanselmann

1992 7e49b6ce Michael Hanselmann
  """
1993 7e49b6ce Michael Hanselmann
  feedback_fn("Gathering cluster information")
1994 7e49b6ce Michael Hanselmann
1995 7e49b6ce Michael Hanselmann
  # This ensures we're running on the master daemon
1996 7e49b6ce Michael Hanselmann
  cl = GetClient()
1997 7e49b6ce Michael Hanselmann
1998 7e49b6ce Michael Hanselmann
  (cluster_name, master_node) = \
1999 7e49b6ce Michael Hanselmann
    cl.QueryConfigValues(["cluster_name", "master_node"])
2000 7e49b6ce Michael Hanselmann
2001 7e49b6ce Michael Hanselmann
  online_nodes = GetOnlineNodes([], cl=cl)
2002 7e49b6ce Michael Hanselmann
2003 7e49b6ce Michael Hanselmann
  # Don't keep a reference to the client. The master daemon will go away.
2004 7e49b6ce Michael Hanselmann
  del cl
2005 7e49b6ce Michael Hanselmann
2006 7e49b6ce Michael Hanselmann
  assert master_node in online_nodes
2007 7e49b6ce Michael Hanselmann
2008 7e49b6ce Michael Hanselmann
  return _RunWhileClusterStoppedHelper(feedback_fn, cluster_name, master_node,
2009 7e49b6ce Michael Hanselmann
                                       online_nodes).Call(fn, *args)
2010 7e49b6ce Michael Hanselmann
2011 7e49b6ce Michael Hanselmann
2012 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
2013 9fbfbb7b Iustin Pop
                  numfields=None, unitfields=None,
2014 9fbfbb7b Iustin Pop
                  units=None):
2015 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
2016 137161c9 Michael Hanselmann

2017 9fbfbb7b Iustin Pop
  @type headers: dict
2018 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
2019 9fbfbb7b Iustin Pop
      the table
2020 9fbfbb7b Iustin Pop
  @type fields: list
2021 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
2022 9fbfbb7b Iustin Pop
      the data field
2023 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
2024 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
2025 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
2026 9fbfbb7b Iustin Pop
      each field
2027 9fbfbb7b Iustin Pop
  @type data: list
2028 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
2029 9fbfbb7b Iustin Pop
  @type numfields: list
2030 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
2031 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
2032 9fbfbb7b Iustin Pop
  @type unitfields: list
2033 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
2034 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
2035 9fbfbb7b Iustin Pop
  @type units: string or None
2036 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
2037 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
2038 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
2039 137161c9 Michael Hanselmann

2040 137161c9 Michael Hanselmann
  """
2041 9fbfbb7b Iustin Pop
  if units is None:
2042 9fbfbb7b Iustin Pop
    if separator:
2043 9fbfbb7b Iustin Pop
      units = "m"
2044 9fbfbb7b Iustin Pop
    else:
2045 9fbfbb7b Iustin Pop
      units = "h"
2046 9fbfbb7b Iustin Pop
2047 137161c9 Michael Hanselmann
  if numfields is None:
2048 137161c9 Michael Hanselmann
    numfields = []
2049 137161c9 Michael Hanselmann
  if unitfields is None:
2050 137161c9 Michael Hanselmann
    unitfields = []
2051 137161c9 Michael Hanselmann
2052 fe267188 Iustin Pop
  numfields = utils.FieldSet(*numfields)   # pylint: disable-msg=W0142
2053 fe267188 Iustin Pop
  unitfields = utils.FieldSet(*unitfields) # pylint: disable-msg=W0142
2054 00430f8e Iustin Pop
2055 137161c9 Michael Hanselmann
  format_fields = []
2056 137161c9 Michael Hanselmann
  for field in fields:
2057 01ca31ae Iustin Pop
    if headers and field not in headers:
2058 ea5a5b74 Guido Trotter
      # TODO: handle better unknown fields (either revert to old
2059 71c1af58 Iustin Pop
      # style of raising exception, or deal more intelligently with
2060 71c1af58 Iustin Pop
      # variable fields)
2061 71c1af58 Iustin Pop
      headers[field] = field
2062 137161c9 Michael Hanselmann
    if separator is not None:
2063 137161c9 Michael Hanselmann
      format_fields.append("%s")
2064 00430f8e Iustin Pop
    elif numfields.Matches(field):
2065 137161c9 Michael Hanselmann
      format_fields.append("%*s")
2066 137161c9 Michael Hanselmann
    else:
2067 137161c9 Michael Hanselmann
      format_fields.append("%-*s")
2068 137161c9 Michael Hanselmann
2069 137161c9 Michael Hanselmann
  if separator is None:
2070 137161c9 Michael Hanselmann
    mlens = [0 for name in fields]
2071 c04bc777 Iustin Pop
    format_str = ' '.join(format_fields)
2072 137161c9 Michael Hanselmann
  else:
2073 c04bc777 Iustin Pop
    format_str = separator.replace("%", "%%").join(format_fields)
2074 137161c9 Michael Hanselmann
2075 137161c9 Michael Hanselmann
  for row in data:
2076 dcbd6288 Guido Trotter
    if row is None:
2077 dcbd6288 Guido Trotter
      continue
2078 137161c9 Michael Hanselmann
    for idx, val in enumerate(row):
2079 00430f8e Iustin Pop
      if unitfields.Matches(fields[idx]):
2080 137161c9 Michael Hanselmann
        try:
2081 137161c9 Michael Hanselmann
          val = int(val)
2082 691744c4 Iustin Pop
        except (TypeError, ValueError):
2083 137161c9 Michael Hanselmann
          pass
2084 137161c9 Michael Hanselmann
        else:
2085 9fbfbb7b Iustin Pop
          val = row[idx] = utils.FormatUnit(val, units)
2086 01ca31ae Iustin Pop
      val = row[idx] = str(val)
2087 137161c9 Michael Hanselmann
      if separator is None:
2088 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(val))
2089 137161c9 Michael Hanselmann
2090 16be8703 Iustin Pop
  result = []
2091 137161c9 Michael Hanselmann
  if headers:
2092 137161c9 Michael Hanselmann
    args = []
2093 137161c9 Michael Hanselmann
    for idx, name in enumerate(fields):
2094 137161c9 Michael Hanselmann
      hdr = headers[name]
2095 137161c9 Michael Hanselmann
      if separator is None:
2096 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(hdr))
2097 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2098 137161c9 Michael Hanselmann
      args.append(hdr)
2099 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2100 137161c9 Michael Hanselmann
2101 ec39d63c Michael Hanselmann
  if separator is None:
2102 ec39d63c Michael Hanselmann
    assert len(mlens) == len(fields)
2103 ec39d63c Michael Hanselmann
2104 ec39d63c Michael Hanselmann
    if fields and not numfields.Matches(fields[-1]):
2105 ec39d63c Michael Hanselmann
      mlens[-1] = 0
2106 ec39d63c Michael Hanselmann
2107 137161c9 Michael Hanselmann
  for line in data:
2108 137161c9 Michael Hanselmann
    args = []
2109 dcbd6288 Guido Trotter
    if line is None:
2110 dcbd6288 Guido Trotter
      line = ['-' for _ in fields]
2111 f1501b3f Michael Hanselmann
    for idx in range(len(fields)):
2112 137161c9 Michael Hanselmann
      if separator is None:
2113 137161c9 Michael Hanselmann
        args.append(mlens[idx])
2114 137161c9 Michael Hanselmann
      args.append(line[idx])
2115 c04bc777 Iustin Pop
    result.append(format_str % tuple(args))
2116 16be8703 Iustin Pop
2117 16be8703 Iustin Pop
  return result
2118 3386e7a9 Iustin Pop
2119 3386e7a9 Iustin Pop
2120 3386e7a9 Iustin Pop
def FormatTimestamp(ts):
2121 3386e7a9 Iustin Pop
  """Formats a given timestamp.
2122 3386e7a9 Iustin Pop

2123 3386e7a9 Iustin Pop
  @type ts: timestamp
2124 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
2125 3386e7a9 Iustin Pop

2126 3386e7a9 Iustin Pop
  @rtype: string
2127 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
2128 3386e7a9 Iustin Pop

2129 3386e7a9 Iustin Pop
  """
2130 e0ec0ff6 Iustin Pop
  if not isinstance (ts, (tuple, list)) or len(ts) != 2:
2131 e0ec0ff6 Iustin Pop
    return '?'
2132 3386e7a9 Iustin Pop
  sec, usec = ts
2133 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
2134 2241e2b9 Iustin Pop
2135 2241e2b9 Iustin Pop
2136 2241e2b9 Iustin Pop
def ParseTimespec(value):
2137 2241e2b9 Iustin Pop
  """Parse a time specification.
2138 2241e2b9 Iustin Pop

2139 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
2140 2241e2b9 Iustin Pop

2141 2241e2b9 Iustin Pop
    - s: seconds
2142 2241e2b9 Iustin Pop
    - m: minutes
2143 2241e2b9 Iustin Pop
    - h: hours
2144 2241e2b9 Iustin Pop
    - d: day
2145 2241e2b9 Iustin Pop
    - w: weeks
2146 2241e2b9 Iustin Pop

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

2149 2241e2b9 Iustin Pop
  """
2150 2241e2b9 Iustin Pop
  value = str(value)
2151 2241e2b9 Iustin Pop
  if not value:
2152 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
2153 2241e2b9 Iustin Pop
  suffix_map = {
2154 2241e2b9 Iustin Pop
    's': 1,
2155 2241e2b9 Iustin Pop
    'm': 60,
2156 2241e2b9 Iustin Pop
    'h': 3600,
2157 2241e2b9 Iustin Pop
    'd': 86400,
2158 2241e2b9 Iustin Pop
    'w': 604800,
2159 2241e2b9 Iustin Pop
    }
2160 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
2161 2241e2b9 Iustin Pop
    try:
2162 2241e2b9 Iustin Pop
      value = int(value)
2163 691744c4 Iustin Pop
    except (TypeError, ValueError):
2164 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2165 2241e2b9 Iustin Pop
  else:
2166 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
2167 2241e2b9 Iustin Pop
    value = value[:-1]
2168 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
2169 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
2170 2241e2b9 Iustin Pop
                                 " suffix passed)")
2171 2241e2b9 Iustin Pop
    try:
2172 2241e2b9 Iustin Pop
      value = int(value) * multiplier
2173 691744c4 Iustin Pop
    except (TypeError, ValueError):
2174 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2175 2241e2b9 Iustin Pop
  return value
2176 46fbdd04 Iustin Pop
2177 46fbdd04 Iustin Pop
2178 e9e26bb3 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False, secondary_ips=False,
2179 e9e26bb3 Iustin Pop
                   filter_master=False):
2180 4040a784 Iustin Pop
  """Returns the names of online nodes.
2181 4040a784 Iustin Pop

2182 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
2183 4040a784 Iustin Pop
  the online nodes.
2184 4040a784 Iustin Pop

2185 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
2186 4040a784 Iustin Pop
      offline ones)
2187 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
2188 4040a784 Iustin Pop
  @type nowarn: boolean
2189 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
2190 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
2191 4040a784 Iustin Pop
      note is not displayed
2192 e9e26bb3 Iustin Pop
  @type secondary_ips: boolean
2193 e9e26bb3 Iustin Pop
  @param secondary_ips: if True, return the secondary IPs instead of the
2194 e9e26bb3 Iustin Pop
      names, useful for doing network traffic over the replication interface
2195 e9e26bb3 Iustin Pop
      (if any)
2196 e9e26bb3 Iustin Pop
  @type filter_master: boolean
2197 e9e26bb3 Iustin Pop
  @param filter_master: if True, do not return the master node in the list
2198 e9e26bb3 Iustin Pop
      (useful in coordination with secondary_ips where we cannot check our
2199 e9e26bb3 Iustin Pop
      node name against the list)
2200 4040a784 Iustin Pop

2201 4040a784 Iustin Pop
  """
2202 4040a784 Iustin Pop
  if cl is None:
2203 4040a784 Iustin Pop
    cl = GetClient()
2204 4040a784 Iustin Pop
2205 e9e26bb3 Iustin Pop
  if secondary_ips:
2206 e9e26bb3 Iustin Pop
    name_idx = 2
2207 e9e26bb3 Iustin Pop
  else:
2208 e9e26bb3 Iustin Pop
    name_idx = 0
2209 e9e26bb3 Iustin Pop
2210 e9e26bb3 Iustin Pop
  if filter_master:
2211 e9e26bb3 Iustin Pop
    master_node = cl.QueryConfigValues(["master_node"])[0]
2212 e9e26bb3 Iustin Pop
    filter_fn = lambda x: x != master_node
2213 e9e26bb3 Iustin Pop
  else:
2214 e9e26bb3 Iustin Pop
    filter_fn = lambda _: True
2215 e9e26bb3 Iustin Pop
2216 e9e26bb3 Iustin Pop
  result = cl.QueryNodes(names=nodes, fields=["name", "offline", "sip"],
2217 2e7b8369 Iustin Pop
                         use_locking=False)
2218 4040a784 Iustin Pop
  offline = [row[0] for row in result if row[1]]
2219 4040a784 Iustin Pop
  if offline and not nowarn:
2220 1f864b60 Iustin Pop
    ToStderr("Note: skipping offline node(s): %s" % utils.CommaJoin(offline))
2221 e9e26bb3 Iustin Pop
  return [row[name_idx] for row in result if not row[1] and filter_fn(row[0])]
2222 4040a784 Iustin Pop
2223 4040a784 Iustin Pop
2224 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
2225 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
2226 46fbdd04 Iustin Pop

2227 46fbdd04 Iustin Pop
  @type stream: file object
2228 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
2229 46fbdd04 Iustin Pop
  @type txt: str
2230 46fbdd04 Iustin Pop
  @param txt: the message
2231 46fbdd04 Iustin Pop

2232 46fbdd04 Iustin Pop
  """
2233 46fbdd04 Iustin Pop
  if args:
2234 46fbdd04 Iustin Pop
    args = tuple(args)
2235 46fbdd04 Iustin Pop
    stream.write(txt % args)
2236 46fbdd04 Iustin Pop
  else:
2237 46fbdd04 Iustin Pop
    stream.write(txt)
2238 46fbdd04 Iustin Pop
  stream.write('\n')
2239 46fbdd04 Iustin Pop
  stream.flush()
2240 46fbdd04 Iustin Pop
2241 46fbdd04 Iustin Pop
2242 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
2243 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
2244 46fbdd04 Iustin Pop

2245 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2246 46fbdd04 Iustin Pop

2247 46fbdd04 Iustin Pop
  @type txt: str
2248 46fbdd04 Iustin Pop
  @param txt: the message
2249 46fbdd04 Iustin Pop

2250 46fbdd04 Iustin Pop
  """
2251 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
2252 46fbdd04 Iustin Pop
2253 46fbdd04 Iustin Pop
2254 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
2255 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
2256 46fbdd04 Iustin Pop

2257 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2258 46fbdd04 Iustin Pop

2259 46fbdd04 Iustin Pop
  @type txt: str
2260 46fbdd04 Iustin Pop
  @param txt: the message
2261 46fbdd04 Iustin Pop

2262 46fbdd04 Iustin Pop
  """
2263 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
2264 479636a3 Iustin Pop
2265 479636a3 Iustin Pop
2266 479636a3 Iustin Pop
class JobExecutor(object):
2267 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
2268 479636a3 Iustin Pop

2269 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
2270 479636a3 Iustin Pop
  GetResults() calls.
2271 479636a3 Iustin Pop

2272 479636a3 Iustin Pop
  """
2273 919ca415 Iustin Pop
  def __init__(self, cl=None, verbose=True, opts=None, feedback_fn=None):
2274 479636a3 Iustin Pop
    self.queue = []
2275 479636a3 Iustin Pop
    if cl is None:
2276 479636a3 Iustin Pop
      cl = GetClient()
2277 479636a3 Iustin Pop
    self.cl = cl
2278 479636a3 Iustin Pop
    self.verbose = verbose
2279 23b4b983 Iustin Pop
    self.jobs = []
2280 cff5fa7f Iustin Pop
    self.opts = opts
2281 919ca415 Iustin Pop
    self.feedback_fn = feedback_fn
2282 479636a3 Iustin Pop
2283 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
2284 23b4b983 Iustin Pop
    """Record a job for later submit.
2285 479636a3 Iustin Pop

2286 479636a3 Iustin Pop
    @type name: string
2287 479636a3 Iustin Pop
    @param name: a description of the job, will be used in WaitJobSet
2288 479636a3 Iustin Pop
    """
2289 cff5fa7f Iustin Pop
    SetGenericOpcodeOpts(ops, self.opts)
2290 23b4b983 Iustin Pop
    self.queue.append((name, ops))
2291 23b4b983 Iustin Pop
2292 66ecc479 Guido Trotter
  def SubmitPending(self, each=False):
2293 23b4b983 Iustin Pop
    """Submit all pending jobs.
2294 23b4b983 Iustin Pop

2295 23b4b983 Iustin Pop
    """
2296 66ecc479 Guido Trotter
    if each:
2297 66ecc479 Guido Trotter
      results = []
2298 66ecc479 Guido Trotter
      for row in self.queue:
2299 66ecc479 Guido Trotter
        # SubmitJob will remove the success status, but raise an exception if
2300 66ecc479 Guido Trotter
        # the submission fails, so we'll notice that anyway.
2301 66ecc479 Guido Trotter
        results.append([True, self.cl.SubmitJob(row[1])])
2302 66ecc479 Guido Trotter
    else:
2303 66ecc479 Guido Trotter
      results = self.cl.SubmitManyJobs([row[1] for row in self.queue])
2304 5299e61f Iustin Pop
    for (idx, ((status, data), (name, _))) in enumerate(zip(results,
2305 5299e61f Iustin Pop
                                                            self.queue)):
2306 5299e61f Iustin Pop
      self.jobs.append((idx, status, data, name))
2307 5299e61f Iustin Pop
2308 5299e61f Iustin Pop
  def _ChooseJob(self):
2309 5299e61f Iustin Pop
    """Choose a non-waiting/queued job to poll next.
2310 5299e61f Iustin Pop

2311 5299e61f Iustin Pop
    """
2312 5299e61f Iustin Pop
    assert self.jobs, "_ChooseJob called with empty job list"
2313 5299e61f Iustin Pop
2314 5299e61f Iustin Pop
    result = self.cl.QueryJobs([i[2] for i in self.jobs], ["status"])
2315 5299e61f Iustin Pop
    assert result
2316 5299e61f Iustin Pop
2317 5299e61f Iustin Pop
    for job_data, status in zip(self.jobs, result):
2318 5299e61f Iustin Pop
      if status[0] in (constants.JOB_STATUS_QUEUED,
2319 5299e61f Iustin Pop
                    constants.JOB_STATUS_WAITLOCK,
2320 5299e61f Iustin Pop
                    constants.JOB_STATUS_CANCELING):
2321 5299e61f Iustin Pop
        # job is still waiting
2322 5299e61f Iustin Pop
        continue
2323 5299e61f Iustin Pop
      # good candidate found
2324 5299e61f Iustin Pop
      self.jobs.remove(job_data)
2325 5299e61f Iustin Pop
      return job_data
2326 5299e61f Iustin Pop
2327 5299e61f Iustin Pop
    # no job found
2328 5299e61f Iustin Pop
    return self.jobs.pop(0)
2329 479636a3 Iustin Pop
2330 479636a3 Iustin Pop
  def GetResults(self):
2331 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
2332 479636a3 Iustin Pop

2333 479636a3 Iustin Pop
    @rtype: list
2334 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
2335 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
2336 479636a3 Iustin Pop
        there will be the error message
2337 479636a3 Iustin Pop

2338 479636a3 Iustin Pop
    """
2339 23b4b983 Iustin Pop
    if not self.jobs:
2340 23b4b983 Iustin Pop
      self.SubmitPending()
2341 479636a3 Iustin Pop
    results = []
2342 479636a3 Iustin Pop
    if self.verbose:
2343 5299e61f Iustin Pop
      ok_jobs = [row[2] for row in self.jobs if row[1]]
2344 23b4b983 Iustin Pop
      if ok_jobs:
2345 1f864b60 Iustin Pop
        ToStdout("Submitted jobs %s", utils.CommaJoin(ok_jobs))
2346 5299e61f Iustin Pop
2347 5299e61f Iustin Pop
    # first, remove any non-submitted jobs
2348 cea881e5 Michael Hanselmann
    self.jobs, failures = compat.partition(self.jobs, lambda x: x[1])
2349 5299e61f Iustin Pop
    for idx, _, jid, name in failures:
2350 c63355f2 Iustin Pop
      ToStderr("Failed to submit job for %s: %s", name, jid)
2351 c63355f2 Iustin Pop
      results.append((idx, False, jid))
2352 5299e61f Iustin Pop
2353 5299e61f Iustin Pop
    while self.jobs:
2354 5299e61f Iustin Pop
      (idx, _, jid, name) = self._ChooseJob()
2355 5299e61f Iustin Pop
      ToStdout("Waiting for job %s for %s...", jid, name)
2356 479636a3 Iustin Pop
      try:
2357 919ca415 Iustin Pop
        job_result = PollJob(jid, cl=self.cl, feedback_fn=self.feedback_fn)
2358 479636a3 Iustin Pop
        success = True
2359 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
2360 479636a3 Iustin Pop
        _, job_result = FormatError(err)
2361 479636a3 Iustin Pop
        success = False
2362 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
2363 479636a3 Iustin Pop
        ToStderr("Job %s for %s has failed: %s", jid, name, job_result)
2364 479636a3 Iustin Pop
2365 5299e61f Iustin Pop
      results.append((idx, success, job_result))
2366 5299e61f Iustin Pop
2367 5299e61f Iustin Pop
    # sort based on the index, then drop it
2368 5299e61f Iustin Pop
    results.sort()
2369 5299e61f Iustin Pop
    results = [i[1:] for i in results]
2370 5299e61f Iustin Pop
2371 479636a3 Iustin Pop
    return results
2372 479636a3 Iustin Pop
2373 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
2374 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
2375 479636a3 Iustin Pop

2376 479636a3 Iustin Pop
    @type wait: boolean
2377 479636a3 Iustin Pop
    @param wait: whether to wait or not
2378 479636a3 Iustin Pop

2379 479636a3 Iustin Pop
    """
2380 479636a3 Iustin Pop
    if wait:
2381 479636a3 Iustin Pop
      return self.GetResults()
2382 479636a3 Iustin Pop
    else:
2383 23b4b983 Iustin Pop
      if not self.jobs:
2384 23b4b983 Iustin Pop
        self.SubmitPending()
2385 71834b2a Guido Trotter
      for _, status, result, name in self.jobs:
2386 23b4b983 Iustin Pop
        if status:
2387 23b4b983 Iustin Pop
          ToStdout("%s: %s", result, name)
2388 23b4b983 Iustin Pop
        else:
2389 23b4b983 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)
2390 53a8a54d Iustin Pop
      return [row[1:3] for row in self.jobs]