Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ 53a8a54d

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

211 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor.
212 863d7f46 Michael Hanselmann

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

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

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

236 863d7f46 Michael Hanselmann
  """
237 863d7f46 Michael Hanselmann
238 863d7f46 Michael Hanselmann
239 863d7f46 Michael Hanselmann
class ArgInstance(_Argument):
240 863d7f46 Michael Hanselmann
  """Instances argument.
241 863d7f46 Michael Hanselmann

242 863d7f46 Michael Hanselmann
  """
243 863d7f46 Michael Hanselmann
244 863d7f46 Michael Hanselmann
245 863d7f46 Michael Hanselmann
class ArgNode(_Argument):
246 863d7f46 Michael Hanselmann
  """Node argument.
247 863d7f46 Michael Hanselmann

248 863d7f46 Michael Hanselmann
  """
249 863d7f46 Michael Hanselmann
250 863d7f46 Michael Hanselmann
class ArgJobId(_Argument):
251 863d7f46 Michael Hanselmann
  """Job ID argument.
252 863d7f46 Michael Hanselmann

253 863d7f46 Michael Hanselmann
  """
254 863d7f46 Michael Hanselmann
255 863d7f46 Michael Hanselmann
256 863d7f46 Michael Hanselmann
class ArgFile(_Argument):
257 863d7f46 Michael Hanselmann
  """File path argument.
258 863d7f46 Michael Hanselmann

259 863d7f46 Michael Hanselmann
  """
260 863d7f46 Michael Hanselmann
261 863d7f46 Michael Hanselmann
262 863d7f46 Michael Hanselmann
class ArgCommand(_Argument):
263 863d7f46 Michael Hanselmann
  """Command argument.
264 863d7f46 Michael Hanselmann

265 863d7f46 Michael Hanselmann
  """
266 863d7f46 Michael Hanselmann
267 863d7f46 Michael Hanselmann
268 83ec7961 Michael Hanselmann
class ArgHost(_Argument):
269 83ec7961 Michael Hanselmann
  """Host argument.
270 83ec7961 Michael Hanselmann

271 83ec7961 Michael Hanselmann
  """
272 83ec7961 Michael Hanselmann
273 83ec7961 Michael Hanselmann
274 f9faf9c3 Renรฉ Nussbaumer
class ArgOs(_Argument):
275 f9faf9c3 Renรฉ Nussbaumer
  """OS argument.
276 f9faf9c3 Renรฉ Nussbaumer

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

291 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
292 846baef9 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

477 e7b61bb0 Iustin Pop
  This will store the parsed value as either True or False.
478 e7b61bb0 Iustin Pop

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

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

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

1008 c41eea6e Iustin Pop
  @param argv: the command line
1009 c41eea6e Iustin Pop
  @param commands: dictionary with special contents, see the design
1010 c41eea6e Iustin Pop
      doc for cmdline handling
1011 c41eea6e Iustin Pop
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
1012 098c0958 Michael Hanselmann

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

1083 a8005e17 Michael Hanselmann
  Algorithm:
1084 a8005e17 Michael Hanselmann

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

1087 a8005e17 Michael Hanselmann
    1. For each argument in definition
1088 a8005e17 Michael Hanselmann

1089 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
1090 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
1091 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
1092 a8005e17 Michael Hanselmann

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

1095 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
1096 a8005e17 Michael Hanselmann

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

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

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

1154 60d49723 Michael Hanselmann
  """
1155 60d49723 Michael Hanselmann
  if value and ':' in value:
1156 60d49723 Michael Hanselmann
    return value.split(':', 1)
1157 60d49723 Michael Hanselmann
  else:
1158 60d49723 Michael Hanselmann
    return (value, None)
1159 60d49723 Michael Hanselmann
1160 60d49723 Michael Hanselmann
1161 07150497 Guido Trotter
def CalculateOSNames(os_name, os_variants):
1162 07150497 Guido Trotter
  """Calculates all the names an OS can be called, according to its variants.
1163 07150497 Guido Trotter

1164 07150497 Guido Trotter
  @type os_name: string
1165 07150497 Guido Trotter
  @param os_name: base name of the os
1166 07150497 Guido Trotter
  @type os_variants: list or None
1167 07150497 Guido Trotter
  @param os_variants: list of supported variants
1168 07150497 Guido Trotter
  @rtype: list
1169 07150497 Guido Trotter
  @return: list of valid names
1170 07150497 Guido Trotter

1171 07150497 Guido Trotter
  """
1172 07150497 Guido Trotter
  if os_variants:
1173 07150497 Guido Trotter
    return ['%s+%s' % (os_name, v) for v in os_variants]
1174 07150497 Guido Trotter
  else:
1175 07150497 Guido Trotter
    return [os_name]
1176 07150497 Guido Trotter
1177 07150497 Guido Trotter
1178 4331f6cd Michael Hanselmann
def UsesRPC(fn):
1179 4331f6cd Michael Hanselmann
  def wrapper(*args, **kwargs):
1180 4331f6cd Michael Hanselmann
    rpc.Init()
1181 4331f6cd Michael Hanselmann
    try:
1182 4331f6cd Michael Hanselmann
      return fn(*args, **kwargs)
1183 4331f6cd Michael Hanselmann
    finally:
1184 4331f6cd Michael Hanselmann
      rpc.Shutdown()
1185 4331f6cd Michael Hanselmann
  return wrapper
1186 4331f6cd Michael Hanselmann
1187 4331f6cd Michael Hanselmann
1188 47988778 Iustin Pop
def AskUser(text, choices=None):
1189 47988778 Iustin Pop
  """Ask the user a question.
1190 a8083063 Iustin Pop

1191 c41eea6e Iustin Pop
  @param text: the question to ask
1192 a8083063 Iustin Pop

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

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

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

1248 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1249 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1250 e9d741b6 Iustin Pop

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

1253 e9d741b6 Iustin Pop
  """
1254 e9d741b6 Iustin Pop
1255 e9d741b6 Iustin Pop
1256 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1257 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1258 a8083063 Iustin Pop

1259 0a1e74d9 Iustin Pop
  @type ops: list
1260 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1261 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1262 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1263 0a1e74d9 Iustin Pop
             if None, a new client will be created
1264 a8083063 Iustin Pop

1265 a8083063 Iustin Pop
  """
1266 e2212007 Iustin Pop
  if cl is None:
1267 b33e986b Iustin Pop
    cl = GetClient()
1268 685ee993 Iustin Pop
1269 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1270 0a1e74d9 Iustin Pop
1271 0a1e74d9 Iustin Pop
  return job_id
1272 0a1e74d9 Iustin Pop
1273 0a1e74d9 Iustin Pop
1274 4e338533 Michael Hanselmann
def GenericPollJob(job_id, cbs, report_cbs):
1275 4e338533 Michael Hanselmann
  """Generic job-polling function.
1276 0a1e74d9 Iustin Pop

1277 4e338533 Michael Hanselmann
  @type job_id: number
1278 4e338533 Michael Hanselmann
  @param job_id: Job ID
1279 4e338533 Michael Hanselmann
  @type cbs: Instance of L{JobPollCbBase}
1280 4e338533 Michael Hanselmann
  @param cbs: Data callbacks
1281 4e338533 Michael Hanselmann
  @type report_cbs: Instance of L{JobPollReportCbBase}
1282 4e338533 Michael Hanselmann
  @param report_cbs: Reporting callbacks
1283 0a1e74d9 Iustin Pop

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

1355 4e338533 Michael Hanselmann
  """
1356 4e338533 Michael Hanselmann
  def __init__(self):
1357 4e338533 Michael Hanselmann
    """Initializes this class.
1358 4e338533 Michael Hanselmann

1359 4e338533 Michael Hanselmann
    """
1360 4e338533 Michael Hanselmann
1361 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1362 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1363 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1364 4e338533 Michael Hanselmann

1365 4e338533 Michael Hanselmann
    """
1366 4e338533 Michael Hanselmann
    raise NotImplementedError()
1367 4e338533 Michael Hanselmann
1368 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1369 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1370 4e338533 Michael Hanselmann

1371 4e338533 Michael Hanselmann
    @type job_ids: list of numbers
1372 4e338533 Michael Hanselmann
    @param job_ids: Job IDs
1373 4e338533 Michael Hanselmann
    @type fields: list of strings
1374 4e338533 Michael Hanselmann
    @param fields: Fields
1375 4e338533 Michael Hanselmann

1376 4e338533 Michael Hanselmann
    """
1377 4e338533 Michael Hanselmann
    raise NotImplementedError()
1378 4e338533 Michael Hanselmann
1379 4e338533 Michael Hanselmann
1380 4e338533 Michael Hanselmann
class JobPollReportCbBase:
1381 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} reporting callbacks.
1382 4e338533 Michael Hanselmann

1383 4e338533 Michael Hanselmann
  """
1384 4e338533 Michael Hanselmann
  def __init__(self):
1385 4e338533 Michael Hanselmann
    """Initializes this class.
1386 4e338533 Michael Hanselmann

1387 4e338533 Michael Hanselmann
    """
1388 4e338533 Michael Hanselmann
1389 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1390 4e338533 Michael Hanselmann
    """Handles a log message.
1391 4e338533 Michael Hanselmann

1392 4e338533 Michael Hanselmann
    """
1393 4e338533 Michael Hanselmann
    raise NotImplementedError()
1394 4e338533 Michael Hanselmann
1395 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1396 4e338533 Michael Hanselmann
    """Called for if a job hasn't changed in a while.
1397 4e338533 Michael Hanselmann

1398 4e338533 Michael Hanselmann
    @type job_id: number
1399 4e338533 Michael Hanselmann
    @param job_id: Job ID
1400 4e338533 Michael Hanselmann
    @type status: string or None
1401 4e338533 Michael Hanselmann
    @param status: Job status if available
1402 4e338533 Michael Hanselmann

1403 4e338533 Michael Hanselmann
    """
1404 4e338533 Michael Hanselmann
    raise NotImplementedError()
1405 4e338533 Michael Hanselmann
1406 4e338533 Michael Hanselmann
1407 4e338533 Michael Hanselmann
class _LuxiJobPollCb(JobPollCbBase):
1408 4e338533 Michael Hanselmann
  def __init__(self, cl):
1409 4e338533 Michael Hanselmann
    """Initializes this class.
1410 4e338533 Michael Hanselmann

1411 4e338533 Michael Hanselmann
    """
1412 4e338533 Michael Hanselmann
    JobPollCbBase.__init__(self)
1413 4e338533 Michael Hanselmann
    self.cl = cl
1414 4e338533 Michael Hanselmann
1415 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1416 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1417 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1418 4e338533 Michael Hanselmann

1419 4e338533 Michael Hanselmann
    """
1420 4e338533 Michael Hanselmann
    return self.cl.WaitForJobChangeOnce(job_id, fields,
1421 4e338533 Michael Hanselmann
                                        prev_job_info, prev_log_serial)
1422 4e338533 Michael Hanselmann
1423 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1424 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1425 4e338533 Michael Hanselmann

1426 4e338533 Michael Hanselmann
    """
1427 4e338533 Michael Hanselmann
    return self.cl.QueryJobs(job_ids, fields)
1428 4e338533 Michael Hanselmann
1429 4e338533 Michael Hanselmann
1430 4e338533 Michael Hanselmann
class FeedbackFnJobPollReportCb(JobPollReportCbBase):
1431 4e338533 Michael Hanselmann
  def __init__(self, feedback_fn):
1432 4e338533 Michael Hanselmann
    """Initializes this class.
1433 4e338533 Michael Hanselmann

1434 4e338533 Michael Hanselmann
    """
1435 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1436 4e338533 Michael Hanselmann
1437 4e338533 Michael Hanselmann
    self.feedback_fn = feedback_fn
1438 4e338533 Michael Hanselmann
1439 4e338533 Michael Hanselmann
    assert callable(feedback_fn)
1440 4e338533 Michael Hanselmann
1441 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1442 4e338533 Michael Hanselmann
    """Handles a log message.
1443 4e338533 Michael Hanselmann

1444 4e338533 Michael Hanselmann
    """
1445 4e338533 Michael Hanselmann
    self.feedback_fn((timestamp, log_type, log_msg))
1446 4e338533 Michael Hanselmann
1447 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1448 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1449 4e338533 Michael Hanselmann

1450 4e338533 Michael Hanselmann
    """
1451 4e338533 Michael Hanselmann
    # Ignore
1452 4e338533 Michael Hanselmann
1453 4e338533 Michael Hanselmann
1454 4e338533 Michael Hanselmann
class StdioJobPollReportCb(JobPollReportCbBase):
1455 4e338533 Michael Hanselmann
  def __init__(self):
1456 4e338533 Michael Hanselmann
    """Initializes this class.
1457 4e338533 Michael Hanselmann

1458 4e338533 Michael Hanselmann
    """
1459 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1460 4e338533 Michael Hanselmann
1461 4e338533 Michael Hanselmann
    self.notified_queued = False
1462 4e338533 Michael Hanselmann
    self.notified_waitlock = False
1463 4e338533 Michael Hanselmann
1464 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1465 4e338533 Michael Hanselmann
    """Handles a log message.
1466 4e338533 Michael Hanselmann

1467 4e338533 Michael Hanselmann
    """
1468 4e338533 Michael Hanselmann
    ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)),
1469 4e338533 Michael Hanselmann
             utils.SafeEncode(log_msg))
1470 4e338533 Michael Hanselmann
1471 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1472 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1473 4e338533 Michael Hanselmann

1474 4e338533 Michael Hanselmann
    """
1475 4e338533 Michael Hanselmann
    if status is None:
1476 4e338533 Michael Hanselmann
      return
1477 4e338533 Michael Hanselmann
1478 4e338533 Michael Hanselmann
    if status == constants.JOB_STATUS_QUEUED and not self.notified_queued:
1479 4e338533 Michael Hanselmann
      ToStderr("Job %s is waiting in queue", job_id)
1480 4e338533 Michael Hanselmann
      self.notified_queued = True
1481 4e338533 Michael Hanselmann
1482 4e338533 Michael Hanselmann
    elif status == constants.JOB_STATUS_WAITLOCK and not self.notified_waitlock:
1483 4e338533 Michael Hanselmann
      ToStderr("Job %s is trying to acquire all necessary locks", job_id)
1484 4e338533 Michael Hanselmann
      self.notified_waitlock = True
1485 4e338533 Michael Hanselmann
1486 4e338533 Michael Hanselmann
1487 4e338533 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None):
1488 4e338533 Michael Hanselmann
  """Function to poll for the result of a job.
1489 4e338533 Michael Hanselmann

1490 4e338533 Michael Hanselmann
  @type job_id: job identified
1491 4e338533 Michael Hanselmann
  @param job_id: the job to poll for results
1492 4e338533 Michael Hanselmann
  @type cl: luxi.Client
1493 4e338533 Michael Hanselmann
  @param cl: the luxi client to use for communicating with the master;
1494 4e338533 Michael Hanselmann
             if None, a new client will be created
1495 4e338533 Michael Hanselmann

1496 4e338533 Michael Hanselmann
  """
1497 4e338533 Michael Hanselmann
  if cl is None:
1498 4e338533 Michael Hanselmann
    cl = GetClient()
1499 4e338533 Michael Hanselmann
1500 4e338533 Michael Hanselmann
  if feedback_fn:
1501 4e338533 Michael Hanselmann
    reporter = FeedbackFnJobPollReportCb(feedback_fn)
1502 0bbe448c Michael Hanselmann
  else:
1503 4e338533 Michael Hanselmann
    reporter = StdioJobPollReportCb()
1504 4e338533 Michael Hanselmann
1505 4e338533 Michael Hanselmann
  return GenericPollJob(job_id, _LuxiJobPollCb(cl), reporter)
1506 ceab32dd Iustin Pop
1507 ceab32dd Iustin Pop
1508 293ba2d8 Iustin Pop
def SubmitOpCode(op, cl=None, feedback_fn=None, opts=None):
1509 0a1e74d9 Iustin Pop
  """Legacy function to submit an opcode.
1510 0a1e74d9 Iustin Pop

1511 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1512 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1513 0a1e74d9 Iustin Pop
  interaction functions.
1514 0a1e74d9 Iustin Pop

1515 0a1e74d9 Iustin Pop
  """
1516 0a1e74d9 Iustin Pop
  if cl is None:
1517 0a1e74d9 Iustin Pop
    cl = GetClient()
1518 0a1e74d9 Iustin Pop
1519 293ba2d8 Iustin Pop
  SetGenericOpcodeOpts([op], opts)
1520 293ba2d8 Iustin Pop
1521 0a1e74d9 Iustin Pop
  job_id = SendJob([op], cl)
1522 0a1e74d9 Iustin Pop
1523 53c04d04 Iustin Pop
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn)
1524 53c04d04 Iustin Pop
1525 53c04d04 Iustin Pop
  return op_results[0]
1526 0a1e74d9 Iustin Pop
1527 0a1e74d9 Iustin Pop
1528 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1529 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1530 94428652 Iustin Pop

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

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

1539 94428652 Iustin Pop
  """
1540 94428652 Iustin Pop
  if opts and opts.submit_only:
1541 293ba2d8 Iustin Pop
    job = [op]
1542 293ba2d8 Iustin Pop
    SetGenericOpcodeOpts(job, opts)
1543 293ba2d8 Iustin Pop
    job_id = SendJob(job, cl=cl)
1544 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
1545 94428652 Iustin Pop
  else:
1546 293ba2d8 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
1547 293ba2d8 Iustin Pop
1548 293ba2d8 Iustin Pop
1549 293ba2d8 Iustin Pop
def SetGenericOpcodeOpts(opcode_list, options):
1550 293ba2d8 Iustin Pop
  """Processor for generic options.
1551 293ba2d8 Iustin Pop

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

1555 293ba2d8 Iustin Pop
  @param opcode_list: list of opcodes
1556 293ba2d8 Iustin Pop
  @param options: command line options or None
1557 293ba2d8 Iustin Pop
  @return: None (in-place modification)
1558 293ba2d8 Iustin Pop

1559 293ba2d8 Iustin Pop
  """
1560 293ba2d8 Iustin Pop
  if not options:
1561 293ba2d8 Iustin Pop
    return
1562 293ba2d8 Iustin Pop
  for op in opcode_list:
1563 293ba2d8 Iustin Pop
    op.dry_run = options.dry_run
1564 293ba2d8 Iustin Pop
    op.debug_level = options.debug
1565 94428652 Iustin Pop
1566 94428652 Iustin Pop
1567 af30b2fd Michael Hanselmann
def GetClient():
1568 af30b2fd Michael Hanselmann
  # TODO: Cache object?
1569 b33e986b Iustin Pop
  try:
1570 b33e986b Iustin Pop
    client = luxi.Client()
1571 b33e986b Iustin Pop
  except luxi.NoMasterError:
1572 d9a51679 Michael Hanselmann
    ss = ssconf.SimpleStore()
1573 d9a51679 Michael Hanselmann
1574 d9a51679 Michael Hanselmann
    # Try to read ssconf file
1575 d9a51679 Michael Hanselmann
    try:
1576 d9a51679 Michael Hanselmann
      ss.GetMasterNode()
1577 d9a51679 Michael Hanselmann
    except errors.ConfigurationError:
1578 d9a51679 Michael Hanselmann
      raise errors.OpPrereqError("Cluster not initialized or this machine is"
1579 d9a51679 Michael Hanselmann
                                 " not part of a cluster")
1580 d9a51679 Michael Hanselmann
1581 d9a51679 Michael Hanselmann
    master, myself = ssconf.GetMasterAndMyself(ss=ss)
1582 b33e986b Iustin Pop
    if master != myself:
1583 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
1584 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
1585 b33e986b Iustin Pop
                                 master)
1586 d9a51679 Michael Hanselmann
    raise
1587 b33e986b Iustin Pop
  return client
1588 af30b2fd Michael Hanselmann
1589 af30b2fd Michael Hanselmann
1590 73702ee7 Iustin Pop
def FormatError(err):
1591 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
1592 73702ee7 Iustin Pop

1593 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
1594 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
1595 73702ee7 Iustin Pop
  second, a string describing the error message (not
1596 73702ee7 Iustin Pop
  newline-terminated).
1597 73702ee7 Iustin Pop

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

1670 334d1483 Iustin Pop
  Arguments:
1671 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
1672 334d1483 Iustin Pop
                for command line handling.
1673 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
1674 334d1483 Iustin Pop
                override command line options; this can be used to pass
1675 334d1483 Iustin Pop
                options from the scripts to generic functions
1676 de47cf8f Guido Trotter
    - aliases: dictionary with command aliases {'alias': 'target, ...}
1677 a8083063 Iustin Pop

1678 a8083063 Iustin Pop
  """
1679 a8083063 Iustin Pop
  # save the program name and the entire command line for later logging
1680 a8083063 Iustin Pop
  if sys.argv:
1681 a8083063 Iustin Pop
    binary = os.path.basename(sys.argv[0]) or sys.argv[0]
1682 a8083063 Iustin Pop
    if len(sys.argv) >= 2:
1683 a8083063 Iustin Pop
      binary += " " + sys.argv[1]
1684 a8083063 Iustin Pop
      old_cmdline = " ".join(sys.argv[2:])
1685 a8083063 Iustin Pop
    else:
1686 a8083063 Iustin Pop
      old_cmdline = ""
1687 a8083063 Iustin Pop
  else:
1688 a8083063 Iustin Pop
    binary = "<unknown program>"
1689 a8083063 Iustin Pop
    old_cmdline = ""
1690 a8083063 Iustin Pop
1691 de47cf8f Guido Trotter
  if aliases is None:
1692 de47cf8f Guido Trotter
    aliases = {}
1693 de47cf8f Guido Trotter
1694 3126878d Guido Trotter
  try:
1695 3126878d Guido Trotter
    func, options, args = _ParseArgs(sys.argv, commands, aliases)
1696 3126878d Guido Trotter
  except errors.ParameterError, err:
1697 3126878d Guido Trotter
    result, err_msg = FormatError(err)
1698 3126878d Guido Trotter
    ToStderr(err_msg)
1699 3126878d Guido Trotter
    return 1
1700 3126878d Guido Trotter
1701 a8083063 Iustin Pop
  if func is None: # parse error
1702 a8083063 Iustin Pop
    return 1
1703 a8083063 Iustin Pop
1704 334d1483 Iustin Pop
  if override is not None:
1705 334d1483 Iustin Pop
    for key, val in override.iteritems():
1706 334d1483 Iustin Pop
      setattr(options, key, val)
1707 334d1483 Iustin Pop
1708 82d9caef Iustin Pop
  utils.SetupLogging(constants.LOG_COMMANDS, debug=options.debug,
1709 82d9caef Iustin Pop
                     stderr_logging=True, program=binary)
1710 a8083063 Iustin Pop
1711 a8083063 Iustin Pop
  if old_cmdline:
1712 46fbdd04 Iustin Pop
    logging.info("run with arguments '%s'", old_cmdline)
1713 a8083063 Iustin Pop
  else:
1714 46fbdd04 Iustin Pop
    logging.info("run with no arguments")
1715 a8083063 Iustin Pop
1716 a8083063 Iustin Pop
  try:
1717 a4af651e Iustin Pop
    result = func(options, args)
1718 d8353c3a Iustin Pop
  except (errors.GenericError, luxi.ProtocolError,
1719 d8353c3a Iustin Pop
          JobSubmittedException), err:
1720 a4af651e Iustin Pop
    result, err_msg = FormatError(err)
1721 5bbd3f7f Michael Hanselmann
    logging.exception("Error during command processing")
1722 46fbdd04 Iustin Pop
    ToStderr(err_msg)
1723 a8083063 Iustin Pop
1724 a8083063 Iustin Pop
  return result
1725 137161c9 Michael Hanselmann
1726 137161c9 Michael Hanselmann
1727 d77490c5 Iustin Pop
def GenericInstanceCreate(mode, opts, args):
1728 d77490c5 Iustin Pop
  """Add an instance to the cluster via either creation or import.
1729 d77490c5 Iustin Pop

1730 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
1731 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
1732 d77490c5 Iustin Pop
  @type args: list
1733 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
1734 d77490c5 Iustin Pop
  @rtype: int
1735 d77490c5 Iustin Pop
  @return: the desired exit code
1736 d77490c5 Iustin Pop

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

1869 7e49b6ce Michael Hanselmann
  """
1870 7e49b6ce Michael Hanselmann
  def __init__(self, feedback_fn, cluster_name, master_node, online_nodes):
1871 7e49b6ce Michael Hanselmann
    """Initializes this class.
1872 7e49b6ce Michael Hanselmann

1873 7e49b6ce Michael Hanselmann
    @type feedback_fn: callable
1874 7e49b6ce Michael Hanselmann
    @param feedback_fn: Feedback function
1875 7e49b6ce Michael Hanselmann
    @type cluster_name: string
1876 7e49b6ce Michael Hanselmann
    @param cluster_name: Cluster name
1877 7e49b6ce Michael Hanselmann
    @type master_node: string
1878 7e49b6ce Michael Hanselmann
    @param master_node Master node name
1879 7e49b6ce Michael Hanselmann
    @type online_nodes: list
1880 7e49b6ce Michael Hanselmann
    @param online_nodes: List of names of online nodes
1881 7e49b6ce Michael Hanselmann

1882 7e49b6ce Michael Hanselmann
    """
1883 7e49b6ce Michael Hanselmann
    self.feedback_fn = feedback_fn
1884 7e49b6ce Michael Hanselmann
    self.cluster_name = cluster_name
1885 7e49b6ce Michael Hanselmann
    self.master_node = master_node
1886 7e49b6ce Michael Hanselmann
    self.online_nodes = online_nodes
1887 7e49b6ce Michael Hanselmann
1888 7e49b6ce Michael Hanselmann
    self.ssh = ssh.SshRunner(self.cluster_name)
1889 7e49b6ce Michael Hanselmann
1890 7e49b6ce Michael Hanselmann
    self.nonmaster_nodes = [name for name in online_nodes
1891 7e49b6ce Michael Hanselmann
                            if name != master_node]
1892 7e49b6ce Michael Hanselmann
1893 7e49b6ce Michael Hanselmann
    assert self.master_node not in self.nonmaster_nodes
1894 7e49b6ce Michael Hanselmann
1895 7e49b6ce Michael Hanselmann
  def _RunCmd(self, node_name, cmd):
1896 7e49b6ce Michael Hanselmann
    """Runs a command on the local or a remote machine.
1897 7e49b6ce Michael Hanselmann

1898 7e49b6ce Michael Hanselmann
    @type node_name: string
1899 7e49b6ce Michael Hanselmann
    @param node_name: Machine name
1900 7e49b6ce Michael Hanselmann
    @type cmd: list
1901 7e49b6ce Michael Hanselmann
    @param cmd: Command
1902 7e49b6ce Michael Hanselmann

1903 7e49b6ce Michael Hanselmann
    """
1904 7e49b6ce Michael Hanselmann
    if node_name is None or node_name == self.master_node:
1905 7e49b6ce Michael Hanselmann
      # No need to use SSH
1906 7e49b6ce Michael Hanselmann
      result = utils.RunCmd(cmd)
1907 7e49b6ce Michael Hanselmann
    else:
1908 7e49b6ce Michael Hanselmann
      result = self.ssh.Run(node_name, "root", utils.ShellQuoteArgs(cmd))
1909 7e49b6ce Michael Hanselmann
1910 7e49b6ce Michael Hanselmann
    if result.failed:
1911 7e49b6ce Michael Hanselmann
      errmsg = ["Failed to run command %s" % result.cmd]
1912 7e49b6ce Michael Hanselmann
      if node_name:
1913 7e49b6ce Michael Hanselmann
        errmsg.append("on node %s" % node_name)
1914 7e49b6ce Michael Hanselmann
      errmsg.append(": exitcode %s and error %s" %
1915 7e49b6ce Michael Hanselmann
                    (result.exit_code, result.output))
1916 7e49b6ce Michael Hanselmann
      raise errors.OpExecError(" ".join(errmsg))
1917 7e49b6ce Michael Hanselmann
1918 7e49b6ce Michael Hanselmann
  def Call(self, fn, *args):
1919 7e49b6ce Michael Hanselmann
    """Call function while all daemons are stopped.
1920 7e49b6ce Michael Hanselmann

1921 7e49b6ce Michael Hanselmann
    @type fn: callable
1922 7e49b6ce Michael Hanselmann
    @param fn: Function to be called
1923 7e49b6ce Michael Hanselmann

1924 7e49b6ce Michael Hanselmann
    """
1925 7e49b6ce Michael Hanselmann
    # Pause watcher by acquiring an exclusive lock on watcher state file
1926 7e49b6ce Michael Hanselmann
    self.feedback_fn("Blocking watcher")
1927 7e49b6ce Michael Hanselmann
    watcher_block = utils.FileLock.Open(constants.WATCHER_STATEFILE)
1928 7e49b6ce Michael Hanselmann
    try:
1929 7e49b6ce Michael Hanselmann
      # TODO: Currently, this just blocks. There's no timeout.
1930 7e49b6ce Michael Hanselmann
      # TODO: Should it be a shared lock?
1931 7e49b6ce Michael Hanselmann
      watcher_block.Exclusive(blocking=True)
1932 7e49b6ce Michael Hanselmann
1933 7e49b6ce Michael Hanselmann
      # Stop master daemons, so that no new jobs can come in and all running
1934 7e49b6ce Michael Hanselmann
      # ones are finished
1935 7e49b6ce Michael Hanselmann
      self.feedback_fn("Stopping master daemons")
1936 7e49b6ce Michael Hanselmann
      self._RunCmd(None, [constants.DAEMON_UTIL, "stop-master"])
1937 7e49b6ce Michael Hanselmann
      try:
1938 7e49b6ce Michael Hanselmann
        # Stop daemons on all nodes
1939 7e49b6ce Michael Hanselmann
        for node_name in self.online_nodes:
1940 7e49b6ce Michael Hanselmann
          self.feedback_fn("Stopping daemons on %s" % node_name)
1941 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "stop-all"])
1942 7e49b6ce Michael Hanselmann
1943 7e49b6ce Michael Hanselmann
        # All daemons are shut down now
1944 7e49b6ce Michael Hanselmann
        try:
1945 7e49b6ce Michael Hanselmann
          return fn(self, *args)
1946 d512e84b Michael Hanselmann
        except Exception, err:
1947 d512e84b Michael Hanselmann
          _, errmsg = FormatError(err)
1948 7e49b6ce Michael Hanselmann
          logging.exception("Caught exception")
1949 d512e84b Michael Hanselmann
          self.feedback_fn(errmsg)
1950 7e49b6ce Michael Hanselmann
          raise
1951 7e49b6ce Michael Hanselmann
      finally:
1952 7e49b6ce Michael Hanselmann
        # Start cluster again, master node last
1953 7e49b6ce Michael Hanselmann
        for node_name in self.nonmaster_nodes + [self.master_node]:
1954 7e49b6ce Michael Hanselmann
          self.feedback_fn("Starting daemons on %s" % node_name)
1955 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "start-all"])
1956 7e49b6ce Michael Hanselmann
    finally:
1957 7e49b6ce Michael Hanselmann
      # Resume watcher
1958 7e49b6ce Michael Hanselmann
      watcher_block.Close()
1959 7e49b6ce Michael Hanselmann
1960 7e49b6ce Michael Hanselmann
1961 7e49b6ce Michael Hanselmann
def RunWhileClusterStopped(feedback_fn, fn, *args):
1962 7e49b6ce Michael Hanselmann
  """Calls a function while all cluster daemons are stopped.
1963 7e49b6ce Michael Hanselmann

1964 7e49b6ce Michael Hanselmann
  @type feedback_fn: callable
1965 7e49b6ce Michael Hanselmann
  @param feedback_fn: Feedback function
1966 7e49b6ce Michael Hanselmann
  @type fn: callable
1967 7e49b6ce Michael Hanselmann
  @param fn: Function to be called when daemons are stopped
1968 7e49b6ce Michael Hanselmann

1969 7e49b6ce Michael Hanselmann
  """
1970 7e49b6ce Michael Hanselmann
  feedback_fn("Gathering cluster information")
1971 7e49b6ce Michael Hanselmann
1972 7e49b6ce Michael Hanselmann
  # This ensures we're running on the master daemon
1973 7e49b6ce Michael Hanselmann
  cl = GetClient()
1974 7e49b6ce Michael Hanselmann
1975 7e49b6ce Michael Hanselmann
  (cluster_name, master_node) = \
1976 7e49b6ce Michael Hanselmann
    cl.QueryConfigValues(["cluster_name", "master_node"])
1977 7e49b6ce Michael Hanselmann
1978 7e49b6ce Michael Hanselmann
  online_nodes = GetOnlineNodes([], cl=cl)
1979 7e49b6ce Michael Hanselmann
1980 7e49b6ce Michael Hanselmann
  # Don't keep a reference to the client. The master daemon will go away.
1981 7e49b6ce Michael Hanselmann
  del cl
1982 7e49b6ce Michael Hanselmann
1983 7e49b6ce Michael Hanselmann
  assert master_node in online_nodes
1984 7e49b6ce Michael Hanselmann
1985 7e49b6ce Michael Hanselmann
  return _RunWhileClusterStoppedHelper(feedback_fn, cluster_name, master_node,
1986 7e49b6ce Michael Hanselmann
                                       online_nodes).Call(fn, *args)
1987 7e49b6ce Michael Hanselmann
1988 7e49b6ce Michael Hanselmann
1989 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
1990 9fbfbb7b Iustin Pop
                  numfields=None, unitfields=None,
1991 9fbfbb7b Iustin Pop
                  units=None):
1992 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
1993 137161c9 Michael Hanselmann

1994 9fbfbb7b Iustin Pop
  @type headers: dict
1995 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
1996 9fbfbb7b Iustin Pop
      the table
1997 9fbfbb7b Iustin Pop
  @type fields: list
1998 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
1999 9fbfbb7b Iustin Pop
      the data field
2000 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
2001 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
2002 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
2003 9fbfbb7b Iustin Pop
      each field
2004 9fbfbb7b Iustin Pop
  @type data: list
2005 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
2006 9fbfbb7b Iustin Pop
  @type numfields: list
2007 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
2008 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
2009 9fbfbb7b Iustin Pop
  @type unitfields: list
2010 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
2011 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
2012 9fbfbb7b Iustin Pop
  @type units: string or None
2013 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
2014 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
2015 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
2016 137161c9 Michael Hanselmann

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

2100 3386e7a9 Iustin Pop
  @type ts: timestamp
2101 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
2102 3386e7a9 Iustin Pop

2103 3386e7a9 Iustin Pop
  @rtype: string
2104 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
2105 3386e7a9 Iustin Pop

2106 3386e7a9 Iustin Pop
  """
2107 e0ec0ff6 Iustin Pop
  if not isinstance (ts, (tuple, list)) or len(ts) != 2:
2108 e0ec0ff6 Iustin Pop
    return '?'
2109 3386e7a9 Iustin Pop
  sec, usec = ts
2110 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
2111 2241e2b9 Iustin Pop
2112 2241e2b9 Iustin Pop
2113 2241e2b9 Iustin Pop
def ParseTimespec(value):
2114 2241e2b9 Iustin Pop
  """Parse a time specification.
2115 2241e2b9 Iustin Pop

2116 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
2117 2241e2b9 Iustin Pop

2118 2241e2b9 Iustin Pop
    - s: seconds
2119 2241e2b9 Iustin Pop
    - m: minutes
2120 2241e2b9 Iustin Pop
    - h: hours
2121 2241e2b9 Iustin Pop
    - d: day
2122 2241e2b9 Iustin Pop
    - w: weeks
2123 2241e2b9 Iustin Pop

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

2126 2241e2b9 Iustin Pop
  """
2127 2241e2b9 Iustin Pop
  value = str(value)
2128 2241e2b9 Iustin Pop
  if not value:
2129 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
2130 2241e2b9 Iustin Pop
  suffix_map = {
2131 2241e2b9 Iustin Pop
    's': 1,
2132 2241e2b9 Iustin Pop
    'm': 60,
2133 2241e2b9 Iustin Pop
    'h': 3600,
2134 2241e2b9 Iustin Pop
    'd': 86400,
2135 2241e2b9 Iustin Pop
    'w': 604800,
2136 2241e2b9 Iustin Pop
    }
2137 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
2138 2241e2b9 Iustin Pop
    try:
2139 2241e2b9 Iustin Pop
      value = int(value)
2140 691744c4 Iustin Pop
    except (TypeError, ValueError):
2141 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2142 2241e2b9 Iustin Pop
  else:
2143 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
2144 2241e2b9 Iustin Pop
    value = value[:-1]
2145 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
2146 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
2147 2241e2b9 Iustin Pop
                                 " suffix passed)")
2148 2241e2b9 Iustin Pop
    try:
2149 2241e2b9 Iustin Pop
      value = int(value) * multiplier
2150 691744c4 Iustin Pop
    except (TypeError, ValueError):
2151 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2152 2241e2b9 Iustin Pop
  return value
2153 46fbdd04 Iustin Pop
2154 46fbdd04 Iustin Pop
2155 e9e26bb3 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False, secondary_ips=False,
2156 e9e26bb3 Iustin Pop
                   filter_master=False):
2157 4040a784 Iustin Pop
  """Returns the names of online nodes.
2158 4040a784 Iustin Pop

2159 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
2160 4040a784 Iustin Pop
  the online nodes.
2161 4040a784 Iustin Pop

2162 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
2163 4040a784 Iustin Pop
      offline ones)
2164 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
2165 4040a784 Iustin Pop
  @type nowarn: boolean
2166 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
2167 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
2168 4040a784 Iustin Pop
      note is not displayed
2169 e9e26bb3 Iustin Pop
  @type secondary_ips: boolean
2170 e9e26bb3 Iustin Pop
  @param secondary_ips: if True, return the secondary IPs instead of the
2171 e9e26bb3 Iustin Pop
      names, useful for doing network traffic over the replication interface
2172 e9e26bb3 Iustin Pop
      (if any)
2173 e9e26bb3 Iustin Pop
  @type filter_master: boolean
2174 e9e26bb3 Iustin Pop
  @param filter_master: if True, do not return the master node in the list
2175 e9e26bb3 Iustin Pop
      (useful in coordination with secondary_ips where we cannot check our
2176 e9e26bb3 Iustin Pop
      node name against the list)
2177 4040a784 Iustin Pop

2178 4040a784 Iustin Pop
  """
2179 4040a784 Iustin Pop
  if cl is None:
2180 4040a784 Iustin Pop
    cl = GetClient()
2181 4040a784 Iustin Pop
2182 e9e26bb3 Iustin Pop
  if secondary_ips:
2183 e9e26bb3 Iustin Pop
    name_idx = 2
2184 e9e26bb3 Iustin Pop
  else:
2185 e9e26bb3 Iustin Pop
    name_idx = 0
2186 e9e26bb3 Iustin Pop
2187 e9e26bb3 Iustin Pop
  if filter_master:
2188 e9e26bb3 Iustin Pop
    master_node = cl.QueryConfigValues(["master_node"])[0]
2189 e9e26bb3 Iustin Pop
    filter_fn = lambda x: x != master_node
2190 e9e26bb3 Iustin Pop
  else:
2191 e9e26bb3 Iustin Pop
    filter_fn = lambda _: True
2192 e9e26bb3 Iustin Pop
2193 e9e26bb3 Iustin Pop
  result = cl.QueryNodes(names=nodes, fields=["name", "offline", "sip"],
2194 2e7b8369 Iustin Pop
                         use_locking=False)
2195 4040a784 Iustin Pop
  offline = [row[0] for row in result if row[1]]
2196 4040a784 Iustin Pop
  if offline and not nowarn:
2197 1f864b60 Iustin Pop
    ToStderr("Note: skipping offline node(s): %s" % utils.CommaJoin(offline))
2198 e9e26bb3 Iustin Pop
  return [row[name_idx] for row in result if not row[1] and filter_fn(row[0])]
2199 4040a784 Iustin Pop
2200 4040a784 Iustin Pop
2201 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
2202 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
2203 46fbdd04 Iustin Pop

2204 46fbdd04 Iustin Pop
  @type stream: file object
2205 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
2206 46fbdd04 Iustin Pop
  @type txt: str
2207 46fbdd04 Iustin Pop
  @param txt: the message
2208 46fbdd04 Iustin Pop

2209 46fbdd04 Iustin Pop
  """
2210 46fbdd04 Iustin Pop
  if args:
2211 46fbdd04 Iustin Pop
    args = tuple(args)
2212 46fbdd04 Iustin Pop
    stream.write(txt % args)
2213 46fbdd04 Iustin Pop
  else:
2214 46fbdd04 Iustin Pop
    stream.write(txt)
2215 46fbdd04 Iustin Pop
  stream.write('\n')
2216 46fbdd04 Iustin Pop
  stream.flush()
2217 46fbdd04 Iustin Pop
2218 46fbdd04 Iustin Pop
2219 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
2220 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
2221 46fbdd04 Iustin Pop

2222 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2223 46fbdd04 Iustin Pop

2224 46fbdd04 Iustin Pop
  @type txt: str
2225 46fbdd04 Iustin Pop
  @param txt: the message
2226 46fbdd04 Iustin Pop

2227 46fbdd04 Iustin Pop
  """
2228 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
2229 46fbdd04 Iustin Pop
2230 46fbdd04 Iustin Pop
2231 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
2232 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
2233 46fbdd04 Iustin Pop

2234 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2235 46fbdd04 Iustin Pop

2236 46fbdd04 Iustin Pop
  @type txt: str
2237 46fbdd04 Iustin Pop
  @param txt: the message
2238 46fbdd04 Iustin Pop

2239 46fbdd04 Iustin Pop
  """
2240 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
2241 479636a3 Iustin Pop
2242 479636a3 Iustin Pop
2243 479636a3 Iustin Pop
class JobExecutor(object):
2244 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
2245 479636a3 Iustin Pop

2246 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
2247 479636a3 Iustin Pop
  GetResults() calls.
2248 479636a3 Iustin Pop

2249 479636a3 Iustin Pop
  """
2250 919ca415 Iustin Pop
  def __init__(self, cl=None, verbose=True, opts=None, feedback_fn=None):
2251 479636a3 Iustin Pop
    self.queue = []
2252 479636a3 Iustin Pop
    if cl is None:
2253 479636a3 Iustin Pop
      cl = GetClient()
2254 479636a3 Iustin Pop
    self.cl = cl
2255 479636a3 Iustin Pop
    self.verbose = verbose
2256 23b4b983 Iustin Pop
    self.jobs = []
2257 cff5fa7f Iustin Pop
    self.opts = opts
2258 919ca415 Iustin Pop
    self.feedback_fn = feedback_fn
2259 479636a3 Iustin Pop
2260 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
2261 23b4b983 Iustin Pop
    """Record a job for later submit.
2262 479636a3 Iustin Pop

2263 479636a3 Iustin Pop
    @type name: string
2264 479636a3 Iustin Pop
    @param name: a description of the job, will be used in WaitJobSet
2265 479636a3 Iustin Pop
    """
2266 cff5fa7f Iustin Pop
    SetGenericOpcodeOpts(ops, self.opts)
2267 23b4b983 Iustin Pop
    self.queue.append((name, ops))
2268 23b4b983 Iustin Pop
2269 66ecc479 Guido Trotter
  def SubmitPending(self, each=False):
2270 23b4b983 Iustin Pop
    """Submit all pending jobs.
2271 23b4b983 Iustin Pop

2272 23b4b983 Iustin Pop
    """
2273 66ecc479 Guido Trotter
    if each:
2274 66ecc479 Guido Trotter
      results = []
2275 66ecc479 Guido Trotter
      for row in self.queue:
2276 66ecc479 Guido Trotter
        # SubmitJob will remove the success status, but raise an exception if
2277 66ecc479 Guido Trotter
        # the submission fails, so we'll notice that anyway.
2278 66ecc479 Guido Trotter
        results.append([True, self.cl.SubmitJob(row[1])])
2279 66ecc479 Guido Trotter
    else:
2280 66ecc479 Guido Trotter
      results = self.cl.SubmitManyJobs([row[1] for row in self.queue])
2281 5299e61f Iustin Pop
    for (idx, ((status, data), (name, _))) in enumerate(zip(results,
2282 5299e61f Iustin Pop
                                                            self.queue)):
2283 5299e61f Iustin Pop
      self.jobs.append((idx, status, data, name))
2284 5299e61f Iustin Pop
2285 5299e61f Iustin Pop
  def _ChooseJob(self):
2286 5299e61f Iustin Pop
    """Choose a non-waiting/queued job to poll next.
2287 5299e61f Iustin Pop

2288 5299e61f Iustin Pop
    """
2289 5299e61f Iustin Pop
    assert self.jobs, "_ChooseJob called with empty job list"
2290 5299e61f Iustin Pop
2291 5299e61f Iustin Pop
    result = self.cl.QueryJobs([i[2] for i in self.jobs], ["status"])
2292 5299e61f Iustin Pop
    assert result
2293 5299e61f Iustin Pop
2294 5299e61f Iustin Pop
    for job_data, status in zip(self.jobs, result):
2295 5299e61f Iustin Pop
      if status[0] in (constants.JOB_STATUS_QUEUED,
2296 5299e61f Iustin Pop
                    constants.JOB_STATUS_WAITLOCK,
2297 5299e61f Iustin Pop
                    constants.JOB_STATUS_CANCELING):
2298 5299e61f Iustin Pop
        # job is still waiting
2299 5299e61f Iustin Pop
        continue
2300 5299e61f Iustin Pop
      # good candidate found
2301 5299e61f Iustin Pop
      self.jobs.remove(job_data)
2302 5299e61f Iustin Pop
      return job_data
2303 5299e61f Iustin Pop
2304 5299e61f Iustin Pop
    # no job found
2305 5299e61f Iustin Pop
    return self.jobs.pop(0)
2306 479636a3 Iustin Pop
2307 479636a3 Iustin Pop
  def GetResults(self):
2308 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
2309 479636a3 Iustin Pop

2310 479636a3 Iustin Pop
    @rtype: list
2311 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
2312 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
2313 479636a3 Iustin Pop
        there will be the error message
2314 479636a3 Iustin Pop

2315 479636a3 Iustin Pop
    """
2316 23b4b983 Iustin Pop
    if not self.jobs:
2317 23b4b983 Iustin Pop
      self.SubmitPending()
2318 479636a3 Iustin Pop
    results = []
2319 479636a3 Iustin Pop
    if self.verbose:
2320 5299e61f Iustin Pop
      ok_jobs = [row[2] for row in self.jobs if row[1]]
2321 23b4b983 Iustin Pop
      if ok_jobs:
2322 1f864b60 Iustin Pop
        ToStdout("Submitted jobs %s", utils.CommaJoin(ok_jobs))
2323 5299e61f Iustin Pop
2324 5299e61f Iustin Pop
    # first, remove any non-submitted jobs
2325 cea881e5 Michael Hanselmann
    self.jobs, failures = compat.partition(self.jobs, lambda x: x[1])
2326 5299e61f Iustin Pop
    for idx, _, jid, name in failures:
2327 c63355f2 Iustin Pop
      ToStderr("Failed to submit job for %s: %s", name, jid)
2328 c63355f2 Iustin Pop
      results.append((idx, False, jid))
2329 5299e61f Iustin Pop
2330 5299e61f Iustin Pop
    while self.jobs:
2331 5299e61f Iustin Pop
      (idx, _, jid, name) = self._ChooseJob()
2332 5299e61f Iustin Pop
      ToStdout("Waiting for job %s for %s...", jid, name)
2333 479636a3 Iustin Pop
      try:
2334 919ca415 Iustin Pop
        job_result = PollJob(jid, cl=self.cl, feedback_fn=self.feedback_fn)
2335 479636a3 Iustin Pop
        success = True
2336 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
2337 479636a3 Iustin Pop
        _, job_result = FormatError(err)
2338 479636a3 Iustin Pop
        success = False
2339 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
2340 479636a3 Iustin Pop
        ToStderr("Job %s for %s has failed: %s", jid, name, job_result)
2341 479636a3 Iustin Pop
2342 5299e61f Iustin Pop
      results.append((idx, success, job_result))
2343 5299e61f Iustin Pop
2344 5299e61f Iustin Pop
    # sort based on the index, then drop it
2345 5299e61f Iustin Pop
    results.sort()
2346 5299e61f Iustin Pop
    results = [i[1:] for i in results]
2347 5299e61f Iustin Pop
2348 479636a3 Iustin Pop
    return results
2349 479636a3 Iustin Pop
2350 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
2351 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
2352 479636a3 Iustin Pop

2353 479636a3 Iustin Pop
    @type wait: boolean
2354 479636a3 Iustin Pop
    @param wait: whether to wait or not
2355 479636a3 Iustin Pop

2356 479636a3 Iustin Pop
    """
2357 479636a3 Iustin Pop
    if wait:
2358 479636a3 Iustin Pop
      return self.GetResults()
2359 479636a3 Iustin Pop
    else:
2360 23b4b983 Iustin Pop
      if not self.jobs:
2361 23b4b983 Iustin Pop
        self.SubmitPending()
2362 71834b2a Guido Trotter
      for _, status, result, name in self.jobs:
2363 23b4b983 Iustin Pop
        if status:
2364 23b4b983 Iustin Pop
          ToStdout("%s: %s", result, name)
2365 23b4b983 Iustin Pop
        else:
2366 23b4b983 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)
2367 53a8a54d Iustin Pop
      return [row[1:3] for row in self.jobs]