Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ 92b61ec7

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

188 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor.
189 863d7f46 Michael Hanselmann

190 863d7f46 Michael Hanselmann
  """
191 7260cfbe Iustin Pop
  # pylint: disable-msg=W0622
192 863d7f46 Michael Hanselmann
  def __init__(self, min=0, max=None, choices=None):
193 863d7f46 Michael Hanselmann
    _Argument.__init__(self, min=min, max=max)
194 863d7f46 Michael Hanselmann
    self.choices = choices
195 863d7f46 Michael Hanselmann
196 863d7f46 Michael Hanselmann
  def __repr__(self):
197 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s choices=%r>" %
198 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max, self.choices))
199 863d7f46 Michael Hanselmann
200 863d7f46 Michael Hanselmann
201 863d7f46 Michael Hanselmann
class ArgChoice(ArgSuggest):
202 863d7f46 Michael Hanselmann
  """Choice argument.
203 863d7f46 Michael Hanselmann

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

207 863d7f46 Michael Hanselmann
  """
208 863d7f46 Michael Hanselmann
209 863d7f46 Michael Hanselmann
210 863d7f46 Michael Hanselmann
class ArgUnknown(_Argument):
211 863d7f46 Michael Hanselmann
  """Unknown argument to program (e.g. determined at runtime).
212 863d7f46 Michael Hanselmann

213 863d7f46 Michael Hanselmann
  """
214 863d7f46 Michael Hanselmann
215 863d7f46 Michael Hanselmann
216 863d7f46 Michael Hanselmann
class ArgInstance(_Argument):
217 863d7f46 Michael Hanselmann
  """Instances argument.
218 863d7f46 Michael Hanselmann

219 863d7f46 Michael Hanselmann
  """
220 863d7f46 Michael Hanselmann
221 863d7f46 Michael Hanselmann
222 863d7f46 Michael Hanselmann
class ArgNode(_Argument):
223 863d7f46 Michael Hanselmann
  """Node argument.
224 863d7f46 Michael Hanselmann

225 863d7f46 Michael Hanselmann
  """
226 863d7f46 Michael Hanselmann
227 863d7f46 Michael Hanselmann
class ArgJobId(_Argument):
228 863d7f46 Michael Hanselmann
  """Job ID argument.
229 863d7f46 Michael Hanselmann

230 863d7f46 Michael Hanselmann
  """
231 863d7f46 Michael Hanselmann
232 863d7f46 Michael Hanselmann
233 863d7f46 Michael Hanselmann
class ArgFile(_Argument):
234 863d7f46 Michael Hanselmann
  """File path argument.
235 863d7f46 Michael Hanselmann

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

242 863d7f46 Michael Hanselmann
  """
243 863d7f46 Michael Hanselmann
244 863d7f46 Michael Hanselmann
245 83ec7961 Michael Hanselmann
class ArgHost(_Argument):
246 83ec7961 Michael Hanselmann
  """Host argument.
247 83ec7961 Michael Hanselmann

248 83ec7961 Michael Hanselmann
  """
249 83ec7961 Michael Hanselmann
250 83ec7961 Michael Hanselmann
251 4a265c08 Michael Hanselmann
ARGS_NONE = []
252 4a265c08 Michael Hanselmann
ARGS_MANY_INSTANCES = [ArgInstance()]
253 4a265c08 Michael Hanselmann
ARGS_MANY_NODES = [ArgNode()]
254 4a265c08 Michael Hanselmann
ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
255 4a265c08 Michael Hanselmann
ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
256 4a265c08 Michael Hanselmann
257 4a265c08 Michael Hanselmann
258 846baef9 Iustin Pop
def _ExtractTagsObject(opts, args):
259 846baef9 Iustin Pop
  """Extract the tag type object.
260 846baef9 Iustin Pop

261 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
262 846baef9 Iustin Pop

263 846baef9 Iustin Pop
  """
264 846baef9 Iustin Pop
  if not hasattr(opts, "tag_type"):
265 846baef9 Iustin Pop
    raise errors.ProgrammerError("tag_type not passed to _ExtractTagsObject")
266 846baef9 Iustin Pop
  kind = opts.tag_type
267 846baef9 Iustin Pop
  if kind == constants.TAG_CLUSTER:
268 846baef9 Iustin Pop
    retval = kind, kind
269 846baef9 Iustin Pop
  elif kind == constants.TAG_NODE or kind == constants.TAG_INSTANCE:
270 846baef9 Iustin Pop
    if not args:
271 0c434948 Iustin Pop
      raise errors.OpPrereqError("no arguments passed to the command")
272 846baef9 Iustin Pop
    name = args.pop(0)
273 846baef9 Iustin Pop
    retval = kind, name
274 846baef9 Iustin Pop
  else:
275 846baef9 Iustin Pop
    raise errors.ProgrammerError("Unhandled tag type '%s'" % kind)
276 846baef9 Iustin Pop
  return retval
277 846baef9 Iustin Pop
278 846baef9 Iustin Pop
279 810c50b7 Iustin Pop
def _ExtendTags(opts, args):
280 810c50b7 Iustin Pop
  """Extend the args if a source file has been given.
281 810c50b7 Iustin Pop

282 810c50b7 Iustin Pop
  This function will extend the tags with the contents of the file
283 810c50b7 Iustin Pop
  passed in the 'tags_source' attribute of the opts parameter. A file
284 810c50b7 Iustin Pop
  named '-' will be replaced by stdin.
285 810c50b7 Iustin Pop

286 810c50b7 Iustin Pop
  """
287 810c50b7 Iustin Pop
  fname = opts.tags_source
288 810c50b7 Iustin Pop
  if fname is None:
289 810c50b7 Iustin Pop
    return
290 810c50b7 Iustin Pop
  if fname == "-":
291 810c50b7 Iustin Pop
    new_fh = sys.stdin
292 810c50b7 Iustin Pop
  else:
293 810c50b7 Iustin Pop
    new_fh = open(fname, "r")
294 810c50b7 Iustin Pop
  new_data = []
295 810c50b7 Iustin Pop
  try:
296 810c50b7 Iustin Pop
    # we don't use the nice 'new_data = [line.strip() for line in fh]'
297 810c50b7 Iustin Pop
    # because of python bug 1633941
298 810c50b7 Iustin Pop
    while True:
299 810c50b7 Iustin Pop
      line = new_fh.readline()
300 810c50b7 Iustin Pop
      if not line:
301 810c50b7 Iustin Pop
        break
302 810c50b7 Iustin Pop
      new_data.append(line.strip())
303 810c50b7 Iustin Pop
  finally:
304 810c50b7 Iustin Pop
    new_fh.close()
305 810c50b7 Iustin Pop
  args.extend(new_data)
306 810c50b7 Iustin Pop
307 810c50b7 Iustin Pop
308 846baef9 Iustin Pop
def ListTags(opts, args):
309 846baef9 Iustin Pop
  """List the tags on a given object.
310 846baef9 Iustin Pop

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

316 846baef9 Iustin Pop
  """
317 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
318 7699c3af Iustin Pop
  cl = GetClient()
319 7699c3af Iustin Pop
  result = cl.QueryTags(kind, name)
320 846baef9 Iustin Pop
  result = list(result)
321 846baef9 Iustin Pop
  result.sort()
322 846baef9 Iustin Pop
  for tag in result:
323 03298ebe Michael Hanselmann
    ToStdout(tag)
324 846baef9 Iustin Pop
325 846baef9 Iustin Pop
326 846baef9 Iustin Pop
def AddTags(opts, args):
327 846baef9 Iustin Pop
  """Add tags on a given object.
328 846baef9 Iustin Pop

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

334 846baef9 Iustin Pop
  """
335 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
336 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
337 846baef9 Iustin Pop
  if not args:
338 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be added")
339 846baef9 Iustin Pop
  op = opcodes.OpAddTags(kind=kind, name=name, tags=args)
340 846baef9 Iustin Pop
  SubmitOpCode(op)
341 846baef9 Iustin Pop
342 846baef9 Iustin Pop
343 846baef9 Iustin Pop
def RemoveTags(opts, args):
344 846baef9 Iustin Pop
  """Remove tags from a given object.
345 846baef9 Iustin Pop

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

351 846baef9 Iustin Pop
  """
352 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
353 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
354 846baef9 Iustin Pop
  if not args:
355 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be removed")
356 846baef9 Iustin Pop
  op = opcodes.OpDelTags(kind=kind, name=name, tags=args)
357 846baef9 Iustin Pop
  SubmitOpCode(op)
358 846baef9 Iustin Pop
359 a8083063 Iustin Pop
360 8929d28c Iustin Pop
def check_unit(option, opt, value): # pylint: disable-msg=W0613
361 65fe4693 Iustin Pop
  """OptParsers custom converter for units.
362 65fe4693 Iustin Pop

363 65fe4693 Iustin Pop
  """
364 a8083063 Iustin Pop
  try:
365 a8083063 Iustin Pop
    return utils.ParseUnit(value)
366 a8083063 Iustin Pop
  except errors.UnitParseError, err:
367 3ecf6786 Iustin Pop
    raise OptionValueError("option %s: %s" % (opt, err))
368 a8083063 Iustin Pop
369 a8083063 Iustin Pop
370 a8469393 Iustin Pop
def _SplitKeyVal(opt, data):
371 a8469393 Iustin Pop
  """Convert a KeyVal string into a dict.
372 a8469393 Iustin Pop

373 a8469393 Iustin Pop
  This function will convert a key=val[,...] string into a dict. Empty
374 a8469393 Iustin Pop
  values will be converted specially: keys which have the prefix 'no_'
375 a8469393 Iustin Pop
  will have the value=False and the prefix stripped, the others will
376 a8469393 Iustin Pop
  have value=True.
377 a8469393 Iustin Pop

378 a8469393 Iustin Pop
  @type opt: string
379 a8469393 Iustin Pop
  @param opt: a string holding the option name for which we process the
380 a8469393 Iustin Pop
      data, used in building error messages
381 a8469393 Iustin Pop
  @type data: string
382 a8469393 Iustin Pop
  @param data: a string of the format key=val,key=val,...
383 a8469393 Iustin Pop
  @rtype: dict
384 a8469393 Iustin Pop
  @return: {key=val, key=val}
385 a8469393 Iustin Pop
  @raises errors.ParameterError: if there are duplicate keys
386 a8469393 Iustin Pop

387 a8469393 Iustin Pop
  """
388 a8469393 Iustin Pop
  kv_dict = {}
389 4f31882e Guido Trotter
  if data:
390 1b3a7656 Iustin Pop
    for elem in utils.UnescapeAndSplit(data, sep=","):
391 4f31882e Guido Trotter
      if "=" in elem:
392 4f31882e Guido Trotter
        key, val = elem.split("=", 1)
393 a8469393 Iustin Pop
      else:
394 4f31882e Guido Trotter
        if elem.startswith(NO_PREFIX):
395 4f31882e Guido Trotter
          key, val = elem[len(NO_PREFIX):], False
396 4f31882e Guido Trotter
        elif elem.startswith(UN_PREFIX):
397 4f31882e Guido Trotter
          key, val = elem[len(UN_PREFIX):], None
398 4f31882e Guido Trotter
        else:
399 4f31882e Guido Trotter
          key, val = elem, True
400 4f31882e Guido Trotter
      if key in kv_dict:
401 4f31882e Guido Trotter
        raise errors.ParameterError("Duplicate key '%s' in option %s" %
402 4f31882e Guido Trotter
                                    (key, opt))
403 4f31882e Guido Trotter
      kv_dict[key] = val
404 a8469393 Iustin Pop
  return kv_dict
405 a8469393 Iustin Pop
406 a8469393 Iustin Pop
407 8929d28c Iustin Pop
def check_ident_key_val(option, opt, value):  # pylint: disable-msg=W0613
408 552c8dff Michael Hanselmann
  """Custom parser for ident:key=val,key=val options.
409 552c8dff Michael Hanselmann

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

413 a8469393 Iustin Pop
  """
414 a8469393 Iustin Pop
  if ":" not in value:
415 8b46606c Guido Trotter
    ident, rest = value, ''
416 a8469393 Iustin Pop
  else:
417 a8469393 Iustin Pop
    ident, rest = value.split(":", 1)
418 8b46606c Guido Trotter
419 8b46606c Guido Trotter
  if ident.startswith(NO_PREFIX):
420 8b46606c Guido Trotter
    if rest:
421 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
422 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
423 8b46606c Guido Trotter
    retval = (ident[len(NO_PREFIX):], False)
424 8b46606c Guido Trotter
  elif ident.startswith(UN_PREFIX):
425 8b46606c Guido Trotter
    if rest:
426 8b46606c Guido Trotter
      msg = "Cannot pass options when removing parameter groups: %s" % value
427 8b46606c Guido Trotter
      raise errors.ParameterError(msg)
428 8b46606c Guido Trotter
    retval = (ident[len(UN_PREFIX):], None)
429 8b46606c Guido Trotter
  else:
430 a8469393 Iustin Pop
    kv_dict = _SplitKeyVal(opt, rest)
431 a8469393 Iustin Pop
    retval = (ident, kv_dict)
432 a8469393 Iustin Pop
  return retval
433 a8469393 Iustin Pop
434 a8469393 Iustin Pop
435 8929d28c Iustin Pop
def check_key_val(option, opt, value):  # pylint: disable-msg=W0613
436 552c8dff Michael Hanselmann
  """Custom parser class for key=val,key=val options.
437 552c8dff Michael Hanselmann

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

440 a8469393 Iustin Pop
  """
441 a8469393 Iustin Pop
  return _SplitKeyVal(opt, value)
442 a8469393 Iustin Pop
443 a8469393 Iustin Pop
444 63d44c55 Michael Hanselmann
# completion_suggestion is normally a list. Using numeric values not evaluating
445 63d44c55 Michael Hanselmann
# to False for dynamic completion.
446 63d44c55 Michael Hanselmann
(OPT_COMPL_MANY_NODES,
447 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_NODE,
448 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_INSTANCE,
449 63d44c55 Michael Hanselmann
 OPT_COMPL_ONE_OS,
450 2d3ed64b Michael Hanselmann
 OPT_COMPL_ONE_IALLOCATOR,
451 2d3ed64b Michael Hanselmann
 OPT_COMPL_INST_ADD_NODES) = range(100, 106)
452 63d44c55 Michael Hanselmann
453 63d44c55 Michael Hanselmann
OPT_COMPL_ALL = frozenset([
454 63d44c55 Michael Hanselmann
  OPT_COMPL_MANY_NODES,
455 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_NODE,
456 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_INSTANCE,
457 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_OS,
458 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_IALLOCATOR,
459 2d3ed64b Michael Hanselmann
  OPT_COMPL_INST_ADD_NODES,
460 63d44c55 Michael Hanselmann
  ])
461 63d44c55 Michael Hanselmann
462 63d44c55 Michael Hanselmann
463 552c8dff Michael Hanselmann
class CliOption(Option):
464 552c8dff Michael Hanselmann
  """Custom option class for optparse.
465 a8469393 Iustin Pop

466 a8469393 Iustin Pop
  """
467 863d7f46 Michael Hanselmann
  ATTRS = Option.ATTRS + [
468 863d7f46 Michael Hanselmann
    "completion_suggest",
469 863d7f46 Michael Hanselmann
    ]
470 552c8dff Michael Hanselmann
  TYPES = Option.TYPES + (
471 552c8dff Michael Hanselmann
    "identkeyval",
472 552c8dff Michael Hanselmann
    "keyval",
473 552c8dff Michael Hanselmann
    "unit",
474 552c8dff Michael Hanselmann
    )
475 552c8dff Michael Hanselmann
  TYPE_CHECKER = Option.TYPE_CHECKER.copy()
476 552c8dff Michael Hanselmann
  TYPE_CHECKER["identkeyval"] = check_ident_key_val
477 a8469393 Iustin Pop
  TYPE_CHECKER["keyval"] = check_key_val
478 552c8dff Michael Hanselmann
  TYPE_CHECKER["unit"] = check_unit
479 a8469393 Iustin Pop
480 a8469393 Iustin Pop
481 a8083063 Iustin Pop
# optparse.py sets make_option, so we do it for our own option class, too
482 a8083063 Iustin Pop
cli_option = CliOption
483 a8083063 Iustin Pop
484 a8083063 Iustin Pop
485 771734c9 Iustin Pop
_YESNO = ("yes", "no")
486 771734c9 Iustin Pop
_YORNO = "yes|no"
487 771734c9 Iustin Pop
488 ea34193f Iustin Pop
DEBUG_OPT = cli_option("-d", "--debug", default=0, action="count",
489 ea34193f Iustin Pop
                       help="Increase debugging level")
490 c38c44ad Michael Hanselmann
491 c38c44ad Michael Hanselmann
NOHDR_OPT = cli_option("--no-headers", default=False,
492 c38c44ad Michael Hanselmann
                       action="store_true", dest="no_headers",
493 c38c44ad Michael Hanselmann
                       help="Don't display column headers")
494 c38c44ad Michael Hanselmann
495 c38c44ad Michael Hanselmann
SEP_OPT = cli_option("--separator", default=None,
496 c38c44ad Michael Hanselmann
                     action="store", dest="separator",
497 c38c44ad Michael Hanselmann
                     help=("Separator between output fields"
498 c38c44ad Michael Hanselmann
                           " (defaults to one space)"))
499 c38c44ad Michael Hanselmann
500 c38c44ad Michael Hanselmann
USEUNITS_OPT = cli_option("--units", default=None,
501 c38c44ad Michael Hanselmann
                          dest="units", choices=('h', 'm', 'g', 't'),
502 c38c44ad Michael Hanselmann
                          help="Specify units for output (one of hmgt)")
503 c38c44ad Michael Hanselmann
504 c38c44ad Michael Hanselmann
FIELDS_OPT = cli_option("-o", "--output", dest="output", action="store",
505 c38c44ad Michael Hanselmann
                        type="string", metavar="FIELDS",
506 c38c44ad Michael Hanselmann
                        help="Comma separated list of output fields")
507 c38c44ad Michael Hanselmann
508 c38c44ad Michael Hanselmann
FORCE_OPT = cli_option("-f", "--force", dest="force", action="store_true",
509 c38c44ad Michael Hanselmann
                       default=False, help="Force the operation")
510 c38c44ad Michael Hanselmann
511 c38c44ad Michael Hanselmann
CONFIRM_OPT = cli_option("--yes", dest="confirm", action="store_true",
512 c38c44ad Michael Hanselmann
                         default=False, help="Do not require confirmation")
513 c38c44ad Michael Hanselmann
514 c38c44ad Michael Hanselmann
TAG_SRC_OPT = cli_option("--from", dest="tags_source",
515 c38c44ad Michael Hanselmann
                         default=None, help="File with tag names")
516 c38c44ad Michael Hanselmann
517 c38c44ad Michael Hanselmann
SUBMIT_OPT = cli_option("--submit", dest="submit_only",
518 c38c44ad Michael Hanselmann
                        default=False, action="store_true",
519 c38c44ad Michael Hanselmann
                        help=("Submit the job and return the job ID, but"
520 c38c44ad Michael Hanselmann
                              " don't wait for the job to finish"))
521 c38c44ad Michael Hanselmann
522 c38c44ad Michael Hanselmann
SYNC_OPT = cli_option("--sync", dest="do_locking",
523 c38c44ad Michael Hanselmann
                      default=False, action="store_true",
524 c38c44ad Michael Hanselmann
                      help=("Grab locks while doing the queries"
525 c38c44ad Michael Hanselmann
                            " in order to ensure more consistent results"))
526 c38c44ad Michael Hanselmann
527 c38c44ad Michael Hanselmann
_DRY_RUN_OPT = cli_option("--dry-run", default=False,
528 c38c44ad Michael Hanselmann
                          action="store_true",
529 c38c44ad Michael Hanselmann
                          help=("Do not execute the operation, just run the"
530 c38c44ad Michael Hanselmann
                                " check steps and verify it it could be"
531 c38c44ad Michael Hanselmann
                                " executed"))
532 c38c44ad Michael Hanselmann
533 9cdb9578 Iustin Pop
VERBOSE_OPT = cli_option("-v", "--verbose", default=False,
534 9cdb9578 Iustin Pop
                         action="store_true",
535 9cdb9578 Iustin Pop
                         help="Increase the verbosity of the operation")
536 9cdb9578 Iustin Pop
537 a0c9776a Iustin Pop
DEBUG_SIMERR_OPT = cli_option("--debug-simulate-errors", default=False,
538 a0c9776a Iustin Pop
                              action="store_true", dest="simulate_errors",
539 a0c9776a Iustin Pop
                              help="Debugging option that makes the operation"
540 a0c9776a Iustin Pop
                              " treat most runtime checks as failed")
541 a0c9776a Iustin Pop
542 3f75b4f3 Iustin Pop
NWSYNC_OPT = cli_option("--no-wait-for-sync", dest="wait_for_sync",
543 3f75b4f3 Iustin Pop
                        default=True, action="store_false",
544 3f75b4f3 Iustin Pop
                        help="Don't wait for sync (DANGEROUS!)")
545 3f75b4f3 Iustin Pop
546 4f365444 Iustin Pop
DISK_TEMPLATE_OPT = cli_option("-t", "--disk-template", dest="disk_template",
547 4f365444 Iustin Pop
                               help="Custom disk setup (diskless, file,"
548 4f365444 Iustin Pop
                               " plain or drbd)",
549 4f365444 Iustin Pop
                               default=None, metavar="TEMPL",
550 4f365444 Iustin Pop
                               choices=list(constants.DISK_TEMPLATES))
551 4f365444 Iustin Pop
552 26023ecd Iustin Pop
NONICS_OPT = cli_option("--no-nics", default=False, action="store_true",
553 26023ecd Iustin Pop
                        help="Do not create any network cards for"
554 26023ecd Iustin Pop
                        " the instance")
555 26023ecd Iustin Pop
556 4a25828c Iustin Pop
FILESTORE_DIR_OPT = cli_option("--file-storage-dir", dest="file_storage_dir",
557 4a25828c Iustin Pop
                               help="Relative path under default cluster-wide"
558 4a25828c Iustin Pop
                               " file storage dir to store file-based disks",
559 4a25828c Iustin Pop
                               default=None, metavar="<DIR>")
560 4a25828c Iustin Pop
561 0f87c43e Iustin Pop
FILESTORE_DRIVER_OPT = cli_option("--file-driver", dest="file_driver",
562 0f87c43e Iustin Pop
                                  help="Driver to use for image files",
563 0f87c43e Iustin Pop
                                  default="loop", metavar="<DRIVER>",
564 0f87c43e Iustin Pop
                                  choices=list(constants.FILE_DRIVER))
565 0f87c43e Iustin Pop
566 4eb62659 Iustin Pop
IALLOCATOR_OPT = cli_option("-I", "--iallocator", metavar="<NAME>",
567 4eb62659 Iustin Pop
                            help="Select nodes for the instance automatically"
568 4eb62659 Iustin Pop
                            " using the <NAME> iallocator plugin",
569 4eb62659 Iustin Pop
                            default=None, type="string",
570 4eb62659 Iustin Pop
                            completion_suggest=OPT_COMPL_ONE_IALLOCATOR)
571 4eb62659 Iustin Pop
572 d3ed23ff Iustin Pop
OS_OPT = cli_option("-o", "--os-type", dest="os", help="What OS to run",
573 d3ed23ff Iustin Pop
                    metavar="<os>",
574 d3ed23ff Iustin Pop
                    completion_suggest=OPT_COMPL_ONE_OS)
575 d3ed23ff Iustin Pop
576 06073e85 Guido Trotter
FORCE_VARIANT_OPT = cli_option("--force-variant", dest="force_variant",
577 06073e85 Guido Trotter
                               action="store_true", default=False,
578 06073e85 Guido Trotter
                               help="Force an unknown variant")
579 06073e85 Guido Trotter
580 087ed2ed Iustin Pop
BACKEND_OPT = cli_option("-B", "--backend-parameters", dest="beparams",
581 087ed2ed Iustin Pop
                         type="keyval", default={},
582 087ed2ed Iustin Pop
                         help="Backend parameters")
583 48f212d7 Iustin Pop
584 48f212d7 Iustin Pop
HVOPTS_OPT =  cli_option("-H", "--hypervisor-parameters", type="keyval",
585 48f212d7 Iustin Pop
                         default={}, dest="hvparams",
586 48f212d7 Iustin Pop
                         help="Hypervisor parameters")
587 087ed2ed Iustin Pop
588 236fd9c4 Iustin Pop
HYPERVISOR_OPT = cli_option("-H", "--hypervisor-parameters", dest="hypervisor",
589 236fd9c4 Iustin Pop
                            help="Hypervisor and hypervisor options, in the"
590 236fd9c4 Iustin Pop
                            " format hypervisor:option=value,option=value,...",
591 236fd9c4 Iustin Pop
                            default=None, type="identkeyval")
592 073271f6 Iustin Pop
593 073271f6 Iustin Pop
HVLIST_OPT = cli_option("-H", "--hypervisor-parameters", dest="hvparams",
594 073271f6 Iustin Pop
                        help="Hypervisor and hypervisor options, in the"
595 073271f6 Iustin Pop
                        " format hypervisor:option=value,option=value,...",
596 073271f6 Iustin Pop
                        default=[], action="append", type="identkeyval")
597 236fd9c4 Iustin Pop
598 91e0748c Iustin Pop
NOIPCHECK_OPT = cli_option("--no-ip-check", dest="ip_check", default=True,
599 91e0748c Iustin Pop
                           action="store_false",
600 91e0748c Iustin Pop
                           help="Don't check that the instance's IP"
601 91e0748c Iustin Pop
                           " is alive")
602 91e0748c Iustin Pop
603 460d22be Iustin Pop
NONAMECHECK_OPT = cli_option("--no-name-check", dest="name_check",
604 460d22be Iustin Pop
                             default=True, action="store_false",
605 460d22be Iustin Pop
                             help="Don't check that the instance's name"
606 460d22be Iustin Pop
                             " is resolvable")
607 460d22be Iustin Pop
608 7d3a9fab Iustin Pop
NET_OPT = cli_option("--net",
609 7d3a9fab Iustin Pop
                     help="NIC parameters", default=[],
610 7d3a9fab Iustin Pop
                     dest="nics", action="append", type="identkeyval")
611 e3876ccb Iustin Pop
612 e3876ccb Iustin Pop
DISK_OPT = cli_option("--disk", help="Disk parameters", default=[],
613 e3876ccb Iustin Pop
                      dest="disks", action="append", type="identkeyval")
614 91e0748c Iustin Pop
615 4b038a1e Iustin Pop
DISKIDX_OPT = cli_option("--disks", dest="disks", default=None,
616 4b038a1e Iustin Pop
                         help="Comma-separated list of disks"
617 4b038a1e Iustin Pop
                         " indices to act on (e.g. 0,2) (optional,"
618 4b038a1e Iustin Pop
                         " defaults to all disks)")
619 4b038a1e Iustin Pop
620 ff00c1a7 Iustin Pop
OS_SIZE_OPT = cli_option("-s", "--os-size", dest="sd_size",
621 ff00c1a7 Iustin Pop
                         help="Enforces a single-disk configuration using the"
622 ff00c1a7 Iustin Pop
                         " given disk size, in MiB unless a suffix is used",
623 ff00c1a7 Iustin Pop
                         default=None, type="unit", metavar="<size>")
624 ff00c1a7 Iustin Pop
625 82a786d5 Iustin Pop
IGNORE_CONSIST_OPT = cli_option("--ignore-consistency",
626 82a786d5 Iustin Pop
                                dest="ignore_consistency",
627 82a786d5 Iustin Pop
                                action="store_true", default=False,
628 82a786d5 Iustin Pop
                                help="Ignore the consistency of the disks on"
629 82a786d5 Iustin Pop
                                " the secondary")
630 82a786d5 Iustin Pop
631 f2a0828c Iustin Pop
NONLIVE_OPT = cli_option("--non-live", dest="live",
632 f2a0828c Iustin Pop
                         default=True, action="store_false",
633 f2a0828c Iustin Pop
                         help="Do a non-live migration (this usually means"
634 f2a0828c Iustin Pop
                         " freeze the instance, save the state, transfer and"
635 f2a0828c Iustin Pop
                         " only then resume running on the secondary node)")
636 f2a0828c Iustin Pop
637 990b7886 Iustin Pop
NODE_PLACEMENT_OPT = cli_option("-n", "--node", dest="node",
638 990b7886 Iustin Pop
                                help="Target node and optional secondary node",
639 990b7886 Iustin Pop
                                metavar="<pnode>[:<snode>]",
640 990b7886 Iustin Pop
                                completion_suggest=OPT_COMPL_INST_ADD_NODES)
641 990b7886 Iustin Pop
642 7edc4637 Iustin Pop
NODE_LIST_OPT = cli_option("-n", "--node", dest="nodes", default=[],
643 7edc4637 Iustin Pop
                           action="append", metavar="<node>",
644 7edc4637 Iustin Pop
                           help="Use only this node (can be used multiple"
645 7edc4637 Iustin Pop
                           " times, if not given defaults to all nodes)",
646 7edc4637 Iustin Pop
                           completion_suggest=OPT_COMPL_ONE_NODE)
647 f36d7d81 Iustin Pop
648 f36d7d81 Iustin Pop
SINGLE_NODE_OPT = cli_option("-n", "--node", dest="node", help="Target node",
649 f36d7d81 Iustin Pop
                             metavar="<node>",
650 f36d7d81 Iustin Pop
                             completion_suggest=OPT_COMPL_ONE_NODE)
651 7edc4637 Iustin Pop
652 edeb878a Iustin Pop
NOSTART_OPT = cli_option("--no-start", dest="start", default=True,
653 edeb878a Iustin Pop
                         action="store_false",
654 edeb878a Iustin Pop
                         help="Don't start the instance after creation")
655 edeb878a Iustin Pop
656 fdcf4d84 Iustin Pop
SHOWCMD_OPT = cli_option("--show-cmd", dest="show_command",
657 fdcf4d84 Iustin Pop
                         action="store_true", default=False,
658 fdcf4d84 Iustin Pop
                         help="Show command instead of executing it")
659 fdcf4d84 Iustin Pop
660 baef337d Iustin Pop
CLEANUP_OPT = cli_option("--cleanup", dest="cleanup",
661 baef337d Iustin Pop
                         default=False, action="store_true",
662 baef337d Iustin Pop
                         help="Instead of performing the migration, try to"
663 baef337d Iustin Pop
                         " recover from a failed cleanup. This is safe"
664 baef337d Iustin Pop
                         " to run even if the instance is healthy, but it"
665 baef337d Iustin Pop
                         " will create extra replication traffic and "
666 baef337d Iustin Pop
                         " disrupt briefly the replication (like during the"
667 baef337d Iustin Pop
                         " migration")
668 baef337d Iustin Pop
669 99a8c799 Iustin Pop
STATIC_OPT = cli_option("-s", "--static", dest="static",
670 99a8c799 Iustin Pop
                        action="store_true", default=False,
671 99a8c799 Iustin Pop
                        help="Only show configuration data, not runtime data")
672 99a8c799 Iustin Pop
673 2d5e7ae1 Iustin Pop
ALL_OPT = cli_option("--all", dest="show_all",
674 2d5e7ae1 Iustin Pop
                     default=False, action="store_true",
675 2d5e7ae1 Iustin Pop
                     help="Show info on all instances on the cluster."
676 2d5e7ae1 Iustin Pop
                     " This can take a long time to run, use wisely")
677 2d5e7ae1 Iustin Pop
678 67840b40 Iustin Pop
SELECT_OS_OPT = cli_option("--select-os", dest="select_os",
679 67840b40 Iustin Pop
                           action="store_true", default=False,
680 67840b40 Iustin Pop
                           help="Interactive OS reinstall, lists available"
681 67840b40 Iustin Pop
                           " OS templates for selection")
682 2d5e7ae1 Iustin Pop
683 b6e841a8 Iustin Pop
IGNORE_FAILURES_OPT = cli_option("--ignore-failures", dest="ignore_failures",
684 b6e841a8 Iustin Pop
                                 action="store_true", default=False,
685 b6e841a8 Iustin Pop
                                 help="Remove the instance from the cluster"
686 b6e841a8 Iustin Pop
                                 " configuration even if there are failures"
687 b6e841a8 Iustin Pop
                                 " during the removal process")
688 b6e841a8 Iustin Pop
689 8d8d650c Michael Hanselmann
IGNORE_REMOVE_FAILURES_OPT = cli_option("--ignore-remove-failures",
690 8d8d650c Michael Hanselmann
                                        dest="ignore_remove_failures",
691 8d8d650c Michael Hanselmann
                                        action="store_true", default=False,
692 8d8d650c Michael Hanselmann
                                        help="Remove the instance from the"
693 8d8d650c Michael Hanselmann
                                        " cluster configuration even if there"
694 8d8d650c Michael Hanselmann
                                        " are failures during the removal"
695 8d8d650c Michael Hanselmann
                                        " process")
696 8d8d650c Michael Hanselmann
697 8d8d650c Michael Hanselmann
REMOVE_INSTANCE_OPT = cli_option("--remove-instance", dest="remove_instance",
698 8d8d650c Michael Hanselmann
                                 action="store_true", default=False,
699 8d8d650c Michael Hanselmann
                                 help="Remove the instance from the cluster")
700 8d8d650c Michael Hanselmann
701 a14db5ff Iustin Pop
NEW_SECONDARY_OPT = cli_option("-n", "--new-secondary", dest="dst_node",
702 a14db5ff Iustin Pop
                               help="Specifies the new secondary node",
703 a14db5ff Iustin Pop
                               metavar="NODE", default=None,
704 a14db5ff Iustin Pop
                               completion_suggest=OPT_COMPL_ONE_NODE)
705 a14db5ff Iustin Pop
706 a72d0a79 Iustin Pop
ON_PRIMARY_OPT = cli_option("-p", "--on-primary", dest="on_primary",
707 a72d0a79 Iustin Pop
                            default=False, action="store_true",
708 a72d0a79 Iustin Pop
                            help="Replace the disk(s) on the primary"
709 a72d0a79 Iustin Pop
                            " node (only for the drbd template)")
710 feb09e6a Iustin Pop
711 feb09e6a Iustin Pop
ON_SECONDARY_OPT = cli_option("-s", "--on-secondary", dest="on_secondary",
712 feb09e6a Iustin Pop
                              default=False, action="store_true",
713 feb09e6a Iustin Pop
                              help="Replace the disk(s) on the secondary"
714 feb09e6a Iustin Pop
                              " node (only for the drbd template)")
715 e00f7a05 Iustin Pop
716 e00f7a05 Iustin Pop
AUTO_REPLACE_OPT = cli_option("-a", "--auto", dest="auto",
717 e00f7a05 Iustin Pop
                              default=False, action="store_true",
718 e00f7a05 Iustin Pop
                              help="Automatically replace faulty disks"
719 e00f7a05 Iustin Pop
                              " (only for the drbd template)")
720 a72d0a79 Iustin Pop
721 05586c90 Iustin Pop
IGNORE_SIZE_OPT = cli_option("--ignore-size", dest="ignore_size",
722 05586c90 Iustin Pop
                             default=False, action="store_true",
723 05586c90 Iustin Pop
                             help="Ignore current recorded size"
724 05586c90 Iustin Pop
                             " (useful for forcing activation when"
725 05586c90 Iustin Pop
                             " the recorded size is wrong)")
726 05586c90 Iustin Pop
727 df62e5db Iustin Pop
SRC_NODE_OPT = cli_option("--src-node", dest="src_node", help="Source node",
728 df62e5db Iustin Pop
                          metavar="<node>",
729 df62e5db Iustin Pop
                          completion_suggest=OPT_COMPL_ONE_NODE)
730 df62e5db Iustin Pop
731 df62e5db Iustin Pop
SRC_DIR_OPT = cli_option("--src-dir", dest="src_dir", help="Source directory",
732 df62e5db Iustin Pop
                         metavar="<dir>")
733 df62e5db Iustin Pop
734 8d823629 Iustin Pop
SECONDARY_IP_OPT = cli_option("-s", "--secondary-ip", dest="secondary_ip",
735 8d823629 Iustin Pop
                              help="Specify the secondary ip for the node",
736 8d823629 Iustin Pop
                              metavar="ADDRESS", default=None)
737 8d823629 Iustin Pop
738 b8d0f938 Iustin Pop
READD_OPT = cli_option("--readd", dest="readd",
739 b8d0f938 Iustin Pop
                       default=False, action="store_true",
740 b8d0f938 Iustin Pop
                       help="Readd old node after replacing it")
741 b8d0f938 Iustin Pop
742 fcdde7f2 Iustin Pop
NOSSH_KEYCHECK_OPT = cli_option("--no-ssh-key-check", dest="ssh_key_check",
743 fcdde7f2 Iustin Pop
                                default=True, action="store_false",
744 fcdde7f2 Iustin Pop
                                help="Disable SSH key fingerprint checking")
745 fcdde7f2 Iustin Pop
746 c38c44ad Michael Hanselmann
747 771734c9 Iustin Pop
MC_OPT = cli_option("-C", "--master-candidate", dest="master_candidate",
748 771734c9 Iustin Pop
                    choices=_YESNO, default=None, metavar=_YORNO,
749 771734c9 Iustin Pop
                    help="Set the master_candidate flag on the node")
750 771734c9 Iustin Pop
751 771734c9 Iustin Pop
OFFLINE_OPT = cli_option("-O", "--offline", dest="offline", metavar=_YORNO,
752 771734c9 Iustin Pop
                         choices=_YESNO, default=None,
753 771734c9 Iustin Pop
                         help="Set the offline flag on the node")
754 771734c9 Iustin Pop
755 771734c9 Iustin Pop
DRAINED_OPT = cli_option("-D", "--drained", dest="drained", metavar=_YORNO,
756 771734c9 Iustin Pop
                         choices=_YESNO, default=None,
757 771734c9 Iustin Pop
                         help="Set the drained flag on the node")
758 771734c9 Iustin Pop
759 e7e09483 Iustin Pop
ALLOCATABLE_OPT = cli_option("--allocatable", dest="allocatable",
760 e7e09483 Iustin Pop
                             choices=_YESNO, default=None, metavar=_YORNO,
761 e7e09483 Iustin Pop
                             help="Set the allocatable flag on a volume")
762 e7e09483 Iustin Pop
763 831040bf Iustin Pop
NOLVM_STORAGE_OPT = cli_option("--no-lvm-storage", dest="lvm_storage",
764 831040bf Iustin Pop
                               help="Disable support for lvm based instances"
765 831040bf Iustin Pop
                               " (cluster-wide)",
766 831040bf Iustin Pop
                               action="store_false", default=True)
767 831040bf Iustin Pop
768 383a3591 Iustin Pop
ENABLED_HV_OPT = cli_option("--enabled-hypervisors",
769 383a3591 Iustin Pop
                            dest="enabled_hypervisors",
770 383a3591 Iustin Pop
                            help="Comma-separated list of hypervisors",
771 383a3591 Iustin Pop
                            type="string", default=None)
772 383a3591 Iustin Pop
773 4fbc93dd Iustin Pop
NIC_PARAMS_OPT = cli_option("-N", "--nic-parameters", dest="nicparams",
774 4fbc93dd Iustin Pop
                            type="keyval", default={},
775 4fbc93dd Iustin Pop
                            help="NIC parameters")
776 4fbc93dd Iustin Pop
777 e32df528 Iustin Pop
CP_SIZE_OPT = cli_option("-C", "--candidate-pool-size", default=None,
778 e32df528 Iustin Pop
                         dest="candidate_pool_size", type="int",
779 e32df528 Iustin Pop
                         help="Set the candidate pool size")
780 e32df528 Iustin Pop
781 b58726e8 Iustin Pop
VG_NAME_OPT = cli_option("-g", "--vg-name", dest="vg_name",
782 b58726e8 Iustin Pop
                         help="Enables LVM and specifies the volume group"
783 b58726e8 Iustin Pop
                         " name (cluster-wide) for disk allocation [xenvg]",
784 b58726e8 Iustin Pop
                         metavar="VG", default=None)
785 b58726e8 Iustin Pop
786 1f587d3d Iustin Pop
YES_DOIT_OPT = cli_option("--yes-do-it", dest="yes_do_it",
787 1f587d3d Iustin Pop
                          help="Destroy cluster", action="store_true")
788 b58726e8 Iustin Pop
789 58371861 Iustin Pop
NOVOTING_OPT = cli_option("--no-voting", dest="no_voting",
790 58371861 Iustin Pop
                          help="Skip node agreement check (dangerous)",
791 58371861 Iustin Pop
                          action="store_true", default=False)
792 58371861 Iustin Pop
793 e3646f22 Iustin Pop
MAC_PREFIX_OPT = cli_option("-m", "--mac-prefix", dest="mac_prefix",
794 e3646f22 Iustin Pop
                            help="Specify the mac prefix for the instance IP"
795 e3646f22 Iustin Pop
                            " addresses, in the format XX:XX:XX",
796 e3646f22 Iustin Pop
                            metavar="PREFIX",
797 e3646f22 Iustin Pop
                            default=None)
798 e3646f22 Iustin Pop
799 29392516 Iustin Pop
MASTER_NETDEV_OPT = cli_option("--master-netdev", dest="master_netdev",
800 29392516 Iustin Pop
                               help="Specify the node interface (cluster-wide)"
801 29392516 Iustin Pop
                               " on which the master IP address will be added "
802 29392516 Iustin Pop
                               " [%s]" % constants.DEFAULT_BRIDGE,
803 29392516 Iustin Pop
                               metavar="NETDEV",
804 29392516 Iustin Pop
                               default=constants.DEFAULT_BRIDGE)
805 29392516 Iustin Pop
806 29392516 Iustin Pop
807 29392516 Iustin Pop
GLOBAL_FILEDIR_OPT = cli_option("--file-storage-dir", dest="file_storage_dir",
808 29392516 Iustin Pop
                                help="Specify the default directory (cluster-"
809 29392516 Iustin Pop
                                "wide) for storing the file-based disks [%s]" %
810 29392516 Iustin Pop
                                constants.DEFAULT_FILE_STORAGE_DIR,
811 29392516 Iustin Pop
                                metavar="DIR",
812 29392516 Iustin Pop
                                default=constants.DEFAULT_FILE_STORAGE_DIR)
813 29392516 Iustin Pop
814 29392516 Iustin Pop
NOMODIFY_ETCHOSTS_OPT = cli_option("--no-etc-hosts", dest="modify_etc_hosts",
815 29392516 Iustin Pop
                                   help="Don't modify /etc/hosts",
816 29392516 Iustin Pop
                                   action="store_false", default=True)
817 29392516 Iustin Pop
818 b989b9d9 Ken Wehr
NOMODIFY_SSH_SETUP_OPT = cli_option("--no-ssh-init", dest="modify_ssh_setup",
819 b989b9d9 Ken Wehr
                                    help="Don't initialize SSH keys",
820 b989b9d9 Ken Wehr
                                    action="store_false", default=True)
821 b989b9d9 Ken Wehr
822 14e9e7f3 Iustin Pop
ERROR_CODES_OPT = cli_option("--error-codes", dest="error_codes",
823 14e9e7f3 Iustin Pop
                             help="Enable parseable error messages",
824 14e9e7f3 Iustin Pop
                             action="store_true", default=False)
825 14e9e7f3 Iustin Pop
826 14e9e7f3 Iustin Pop
NONPLUS1_OPT = cli_option("--no-nplus1-mem", dest="skip_nplusone_mem",
827 14e9e7f3 Iustin Pop
                          help="Skip N+1 memory redundancy tests",
828 14e9e7f3 Iustin Pop
                          action="store_true", default=False)
829 14e9e7f3 Iustin Pop
830 12054861 Iustin Pop
REBOOT_TYPE_OPT = cli_option("-t", "--type", dest="reboot_type",
831 12054861 Iustin Pop
                             help="Type of reboot: soft/hard/full",
832 12054861 Iustin Pop
                             default=constants.INSTANCE_REBOOT_HARD,
833 12054861 Iustin Pop
                             metavar="<REBOOT>",
834 12054861 Iustin Pop
                             choices=list(constants.REBOOT_TYPES))
835 12054861 Iustin Pop
836 ee3f9578 Iustin Pop
IGNORE_SECONDARIES_OPT = cli_option("--ignore-secondaries",
837 ee3f9578 Iustin Pop
                                    dest="ignore_secondaries",
838 ee3f9578 Iustin Pop
                                    default=False, action="store_true",
839 ee3f9578 Iustin Pop
                                    help="Ignore errors from secondaries")
840 ee3f9578 Iustin Pop
841 69b99987 Michael Hanselmann
NOSHUTDOWN_OPT = cli_option("--noshutdown", dest="shutdown",
842 44c44832 Iustin Pop
                            action="store_false", default=True,
843 44c44832 Iustin Pop
                            help="Don't shutdown the instance (unsafe)")
844 44c44832 Iustin Pop
845 b5762e2a Guido Trotter
TIMEOUT_OPT = cli_option("--timeout", dest="timeout", type="int",
846 b5762e2a Guido Trotter
                         default=constants.DEFAULT_SHUTDOWN_TIMEOUT,
847 b5762e2a Guido Trotter
                         help="Maximum time to wait")
848 44c44832 Iustin Pop
849 4d98c565 Guido Trotter
SHUTDOWN_TIMEOUT_OPT = cli_option("--shutdown-timeout",
850 4d98c565 Guido Trotter
                         dest="shutdown_timeout", type="int",
851 7e5eaaa8 Guido Trotter
                         default=constants.DEFAULT_SHUTDOWN_TIMEOUT,
852 7e5eaaa8 Guido Trotter
                         help="Maximum time to wait for instance shutdown")
853 7e5eaaa8 Guido Trotter
854 7ea7bcf6 Iustin Pop
EARLY_RELEASE_OPT = cli_option("--early-release",
855 7ea7bcf6 Iustin Pop
                               dest="early_release", default=False,
856 7ea7bcf6 Iustin Pop
                               action="store_true",
857 7ea7bcf6 Iustin Pop
                               help="Release the locks on the secondary"
858 7ea7bcf6 Iustin Pop
                               " node(s) early")
859 7ea7bcf6 Iustin Pop
860 771734c9 Iustin Pop
861 de47cf8f Guido Trotter
def _ParseArgs(argv, commands, aliases):
862 c41eea6e Iustin Pop
  """Parser for the command line arguments.
863 a8083063 Iustin Pop

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

867 c41eea6e Iustin Pop
  @param argv: the command line
868 c41eea6e Iustin Pop
  @param commands: dictionary with special contents, see the design
869 c41eea6e Iustin Pop
      doc for cmdline handling
870 c41eea6e Iustin Pop
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
871 098c0958 Michael Hanselmann

872 a8083063 Iustin Pop
  """
873 a8083063 Iustin Pop
  if len(argv) == 0:
874 a8083063 Iustin Pop
    binary = "<command>"
875 a8083063 Iustin Pop
  else:
876 a8083063 Iustin Pop
    binary = argv[0].split("/")[-1]
877 a8083063 Iustin Pop
878 a8083063 Iustin Pop
  if len(argv) > 1 and argv[1] == "--version":
879 03298ebe Michael Hanselmann
    ToStdout("%s (ganeti) %s", binary, constants.RELEASE_VERSION)
880 a8083063 Iustin Pop
    # Quit right away. That way we don't have to care about this special
881 a8083063 Iustin Pop
    # argument. optparse.py does it the same.
882 a8083063 Iustin Pop
    sys.exit(0)
883 a8083063 Iustin Pop
884 de47cf8f Guido Trotter
  if len(argv) < 2 or not (argv[1] in commands or
885 70a35b6f Guido Trotter
                           argv[1] in aliases):
886 a8083063 Iustin Pop
    # let's do a nice thing
887 a8083063 Iustin Pop
    sortedcmds = commands.keys()
888 a8083063 Iustin Pop
    sortedcmds.sort()
889 03298ebe Michael Hanselmann
890 03298ebe Michael Hanselmann
    ToStdout("Usage: %s {command} [options...] [argument...]", binary)
891 03298ebe Michael Hanselmann
    ToStdout("%s <command> --help to see details, or man %s", binary, binary)
892 03298ebe Michael Hanselmann
    ToStdout("")
893 03298ebe Michael Hanselmann
894 a8083063 Iustin Pop
    # compute the max line length for cmd + usage
895 4e713df6 Iustin Pop
    mlen = max([len(" %s" % cmd) for cmd in commands])
896 a8083063 Iustin Pop
    mlen = min(60, mlen) # should not get here...
897 03298ebe Michael Hanselmann
898 a8083063 Iustin Pop
    # and format a nice command list
899 03298ebe Michael Hanselmann
    ToStdout("Commands:")
900 a8083063 Iustin Pop
    for cmd in sortedcmds:
901 4e713df6 Iustin Pop
      cmdstr = " %s" % (cmd,)
902 9a033156 Iustin Pop
      help_text = commands[cmd][4]
903 03298ebe Michael Hanselmann
      help_lines = textwrap.wrap(help_text, 79 - 3 - mlen)
904 03298ebe Michael Hanselmann
      ToStdout("%-*s - %s", mlen, cmdstr, help_lines.pop(0))
905 a8083063 Iustin Pop
      for line in help_lines:
906 03298ebe Michael Hanselmann
        ToStdout("%-*s   %s", mlen, "", line)
907 03298ebe Michael Hanselmann
908 03298ebe Michael Hanselmann
    ToStdout("")
909 03298ebe Michael Hanselmann
910 a8083063 Iustin Pop
    return None, None, None
911 de47cf8f Guido Trotter
912 de47cf8f Guido Trotter
  # get command, unalias it, and look it up in commands
913 a8083063 Iustin Pop
  cmd = argv.pop(1)
914 de47cf8f Guido Trotter
  if cmd in aliases:
915 de47cf8f Guido Trotter
    if cmd in commands:
916 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' overrides an existing"
917 de47cf8f Guido Trotter
                                   " command" % cmd)
918 de47cf8f Guido Trotter
919 de47cf8f Guido Trotter
    if aliases[cmd] not in commands:
920 de47cf8f Guido Trotter
      raise errors.ProgrammerError("Alias '%s' maps to non-existing"
921 de47cf8f Guido Trotter
                                   " command '%s'" % (cmd, aliases[cmd]))
922 de47cf8f Guido Trotter
923 de47cf8f Guido Trotter
    cmd = aliases[cmd]
924 de47cf8f Guido Trotter
925 a8005e17 Michael Hanselmann
  func, args_def, parser_opts, usage, description = commands[cmd]
926 064c21f8 Iustin Pop
  parser = OptionParser(option_list=parser_opts + [_DRY_RUN_OPT, DEBUG_OPT],
927 a8083063 Iustin Pop
                        description=description,
928 a8083063 Iustin Pop
                        formatter=TitledHelpFormatter(),
929 a8083063 Iustin Pop
                        usage="%%prog %s %s" % (cmd, usage))
930 a8083063 Iustin Pop
  parser.disable_interspersed_args()
931 a8083063 Iustin Pop
  options, args = parser.parse_args()
932 a8005e17 Michael Hanselmann
933 a8005e17 Michael Hanselmann
  if not _CheckArguments(cmd, args_def, args):
934 a8083063 Iustin Pop
    return None, None, None
935 a8083063 Iustin Pop
936 a8083063 Iustin Pop
  return func, options, args
937 a8083063 Iustin Pop
938 a8083063 Iustin Pop
939 a8005e17 Michael Hanselmann
def _CheckArguments(cmd, args_def, args):
940 a8005e17 Michael Hanselmann
  """Verifies the arguments using the argument definition.
941 a8005e17 Michael Hanselmann

942 a8005e17 Michael Hanselmann
  Algorithm:
943 a8005e17 Michael Hanselmann

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

946 a8005e17 Michael Hanselmann
    1. For each argument in definition
947 a8005e17 Michael Hanselmann

948 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
949 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
950 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
951 a8005e17 Michael Hanselmann

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

954 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
955 a8005e17 Michael Hanselmann

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

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

960 a8005e17 Michael Hanselmann
  """
961 a8005e17 Michael Hanselmann
  if args and not args_def:
962 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects no arguments", cmd)
963 a8005e17 Michael Hanselmann
    return False
964 a8005e17 Michael Hanselmann
965 a8005e17 Michael Hanselmann
  min_count = None
966 a8005e17 Michael Hanselmann
  max_count = None
967 a8005e17 Michael Hanselmann
  check_max = None
968 a8005e17 Michael Hanselmann
969 a8005e17 Michael Hanselmann
  last_idx = len(args_def) - 1
970 a8005e17 Michael Hanselmann
971 a8005e17 Michael Hanselmann
  for idx, arg in enumerate(args_def):
972 a8005e17 Michael Hanselmann
    if min_count is None:
973 a8005e17 Michael Hanselmann
      min_count = arg.min
974 a8005e17 Michael Hanselmann
    elif arg.min is not None:
975 a8005e17 Michael Hanselmann
      min_count += arg.min
976 a8005e17 Michael Hanselmann
977 a8005e17 Michael Hanselmann
    if max_count is None:
978 a8005e17 Michael Hanselmann
      max_count = arg.max
979 a8005e17 Michael Hanselmann
    elif arg.max is not None:
980 a8005e17 Michael Hanselmann
      max_count += arg.max
981 a8005e17 Michael Hanselmann
982 a8005e17 Michael Hanselmann
    if idx == last_idx:
983 a8005e17 Michael Hanselmann
      check_max = (arg.max is not None)
984 a8005e17 Michael Hanselmann
985 a8005e17 Michael Hanselmann
    elif arg.max is None:
986 a8005e17 Michael Hanselmann
      raise errors.ProgrammerError("Only the last argument can have max=None")
987 a8005e17 Michael Hanselmann
988 a8005e17 Michael Hanselmann
  if check_max:
989 a8005e17 Michael Hanselmann
    # Command with exact number of arguments
990 a8005e17 Michael Hanselmann
    if (min_count is not None and max_count is not None and
991 a8005e17 Michael Hanselmann
        min_count == max_count and len(args) != min_count):
992 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects %d argument(s)", cmd, min_count)
993 a8005e17 Michael Hanselmann
      return False
994 a8005e17 Michael Hanselmann
995 a8005e17 Michael Hanselmann
    # Command with limited number of arguments
996 a8005e17 Michael Hanselmann
    if max_count is not None and len(args) > max_count:
997 a8005e17 Michael Hanselmann
      ToStderr("Error: Command %s expects only %d argument(s)",
998 a8005e17 Michael Hanselmann
               cmd, max_count)
999 a8005e17 Michael Hanselmann
      return False
1000 a8005e17 Michael Hanselmann
1001 a8005e17 Michael Hanselmann
  # Command with some required arguments
1002 a8005e17 Michael Hanselmann
  if min_count is not None and len(args) < min_count:
1003 a8005e17 Michael Hanselmann
    ToStderr("Error: Command %s expects at least %d argument(s)",
1004 a8005e17 Michael Hanselmann
             cmd, min_count)
1005 a8005e17 Michael Hanselmann
    return False
1006 a8005e17 Michael Hanselmann
1007 a8005e17 Michael Hanselmann
  return True
1008 a8005e17 Michael Hanselmann
1009 a8005e17 Michael Hanselmann
1010 60d49723 Michael Hanselmann
def SplitNodeOption(value):
1011 60d49723 Michael Hanselmann
  """Splits the value of a --node option.
1012 60d49723 Michael Hanselmann

1013 60d49723 Michael Hanselmann
  """
1014 60d49723 Michael Hanselmann
  if value and ':' in value:
1015 60d49723 Michael Hanselmann
    return value.split(':', 1)
1016 60d49723 Michael Hanselmann
  else:
1017 60d49723 Michael Hanselmann
    return (value, None)
1018 60d49723 Michael Hanselmann
1019 60d49723 Michael Hanselmann
1020 07150497 Guido Trotter
def CalculateOSNames(os_name, os_variants):
1021 07150497 Guido Trotter
  """Calculates all the names an OS can be called, according to its variants.
1022 07150497 Guido Trotter

1023 07150497 Guido Trotter
  @type os_name: string
1024 07150497 Guido Trotter
  @param os_name: base name of the os
1025 07150497 Guido Trotter
  @type os_variants: list or None
1026 07150497 Guido Trotter
  @param os_variants: list of supported variants
1027 07150497 Guido Trotter
  @rtype: list
1028 07150497 Guido Trotter
  @return: list of valid names
1029 07150497 Guido Trotter

1030 07150497 Guido Trotter
  """
1031 07150497 Guido Trotter
  if os_variants:
1032 07150497 Guido Trotter
    return ['%s+%s' % (os_name, v) for v in os_variants]
1033 07150497 Guido Trotter
  else:
1034 07150497 Guido Trotter
    return [os_name]
1035 07150497 Guido Trotter
1036 07150497 Guido Trotter
1037 4331f6cd Michael Hanselmann
def UsesRPC(fn):
1038 4331f6cd Michael Hanselmann
  def wrapper(*args, **kwargs):
1039 4331f6cd Michael Hanselmann
    rpc.Init()
1040 4331f6cd Michael Hanselmann
    try:
1041 4331f6cd Michael Hanselmann
      return fn(*args, **kwargs)
1042 4331f6cd Michael Hanselmann
    finally:
1043 4331f6cd Michael Hanselmann
      rpc.Shutdown()
1044 4331f6cd Michael Hanselmann
  return wrapper
1045 4331f6cd Michael Hanselmann
1046 4331f6cd Michael Hanselmann
1047 47988778 Iustin Pop
def AskUser(text, choices=None):
1048 47988778 Iustin Pop
  """Ask the user a question.
1049 a8083063 Iustin Pop

1050 c41eea6e Iustin Pop
  @param text: the question to ask
1051 a8083063 Iustin Pop

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

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

1061 a8083063 Iustin Pop
  """
1062 47988778 Iustin Pop
  if choices is None:
1063 47988778 Iustin Pop
    choices = [('y', True, 'Perform the operation'),
1064 47988778 Iustin Pop
               ('n', False, 'Do not perform the operation')]
1065 47988778 Iustin Pop
  if not choices or not isinstance(choices, list):
1066 5bbd3f7f Michael Hanselmann
    raise errors.ProgrammerError("Invalid choices argument to AskUser")
1067 47988778 Iustin Pop
  for entry in choices:
1068 47988778 Iustin Pop
    if not isinstance(entry, tuple) or len(entry) < 3 or entry[0] == '?':
1069 5bbd3f7f Michael Hanselmann
      raise errors.ProgrammerError("Invalid choices element to AskUser")
1070 47988778 Iustin Pop
1071 47988778 Iustin Pop
  answer = choices[-1][1]
1072 47988778 Iustin Pop
  new_text = []
1073 47988778 Iustin Pop
  for line in text.splitlines():
1074 47988778 Iustin Pop
    new_text.append(textwrap.fill(line, 70, replace_whitespace=False))
1075 47988778 Iustin Pop
  text = "\n".join(new_text)
1076 a8083063 Iustin Pop
  try:
1077 3023170f Iustin Pop
    f = file("/dev/tty", "a+")
1078 a8083063 Iustin Pop
  except IOError:
1079 47988778 Iustin Pop
    return answer
1080 a8083063 Iustin Pop
  try:
1081 47988778 Iustin Pop
    chars = [entry[0] for entry in choices]
1082 47988778 Iustin Pop
    chars[-1] = "[%s]" % chars[-1]
1083 47988778 Iustin Pop
    chars.append('?')
1084 47988778 Iustin Pop
    maps = dict([(entry[0], entry[1]) for entry in choices])
1085 47988778 Iustin Pop
    while True:
1086 47988778 Iustin Pop
      f.write(text)
1087 47988778 Iustin Pop
      f.write('\n')
1088 47988778 Iustin Pop
      f.write("/".join(chars))
1089 47988778 Iustin Pop
      f.write(": ")
1090 47988778 Iustin Pop
      line = f.readline(2).strip().lower()
1091 47988778 Iustin Pop
      if line in maps:
1092 47988778 Iustin Pop
        answer = maps[line]
1093 47988778 Iustin Pop
        break
1094 47988778 Iustin Pop
      elif line == '?':
1095 47988778 Iustin Pop
        for entry in choices:
1096 47988778 Iustin Pop
          f.write(" %s - %s\n" % (entry[0], entry[2]))
1097 47988778 Iustin Pop
        f.write("\n")
1098 47988778 Iustin Pop
        continue
1099 a8083063 Iustin Pop
  finally:
1100 a8083063 Iustin Pop
    f.close()
1101 a8083063 Iustin Pop
  return answer
1102 a8083063 Iustin Pop
1103 a8083063 Iustin Pop
1104 e9d741b6 Iustin Pop
class JobSubmittedException(Exception):
1105 e9d741b6 Iustin Pop
  """Job was submitted, client should exit.
1106 e9d741b6 Iustin Pop

1107 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1108 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1109 e9d741b6 Iustin Pop

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

1112 e9d741b6 Iustin Pop
  """
1113 e9d741b6 Iustin Pop
1114 e9d741b6 Iustin Pop
1115 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1116 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1117 a8083063 Iustin Pop

1118 0a1e74d9 Iustin Pop
  @type ops: list
1119 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1120 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1121 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1122 0a1e74d9 Iustin Pop
             if None, a new client will be created
1123 a8083063 Iustin Pop

1124 a8083063 Iustin Pop
  """
1125 e2212007 Iustin Pop
  if cl is None:
1126 b33e986b Iustin Pop
    cl = GetClient()
1127 685ee993 Iustin Pop
1128 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1129 0a1e74d9 Iustin Pop
1130 0a1e74d9 Iustin Pop
  return job_id
1131 0a1e74d9 Iustin Pop
1132 0a1e74d9 Iustin Pop
1133 281606c1 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None):
1134 0a1e74d9 Iustin Pop
  """Function to poll for the result of a job.
1135 0a1e74d9 Iustin Pop

1136 0a1e74d9 Iustin Pop
  @type job_id: job identified
1137 0a1e74d9 Iustin Pop
  @param job_id: the job to poll for results
1138 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1139 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1140 0a1e74d9 Iustin Pop
             if None, a new client will be created
1141 0a1e74d9 Iustin Pop

1142 0a1e74d9 Iustin Pop
  """
1143 0a1e74d9 Iustin Pop
  if cl is None:
1144 0a1e74d9 Iustin Pop
    cl = GetClient()
1145 685ee993 Iustin Pop
1146 6c5a7090 Michael Hanselmann
  prev_job_info = None
1147 6c5a7090 Michael Hanselmann
  prev_logmsg_serial = None
1148 6c5a7090 Michael Hanselmann
1149 685ee993 Iustin Pop
  while True:
1150 6c5a7090 Michael Hanselmann
    result = cl.WaitForJobChange(job_id, ["status"], prev_job_info,
1151 6c5a7090 Michael Hanselmann
                                 prev_logmsg_serial)
1152 6c5a7090 Michael Hanselmann
    if not result:
1153 685ee993 Iustin Pop
      # job not found, go away!
1154 0bbe448c Michael Hanselmann
      raise errors.JobLost("Job with id %s lost" % job_id)
1155 685ee993 Iustin Pop
1156 6c5a7090 Michael Hanselmann
    # Split result, a tuple of (field values, log entries)
1157 6c5a7090 Michael Hanselmann
    (job_info, log_entries) = result
1158 6c5a7090 Michael Hanselmann
    (status, ) = job_info
1159 6c5a7090 Michael Hanselmann
1160 6c5a7090 Michael Hanselmann
    if log_entries:
1161 6c5a7090 Michael Hanselmann
      for log_entry in log_entries:
1162 6c5a7090 Michael Hanselmann
        (serial, timestamp, _, message) = log_entry
1163 6c5a7090 Michael Hanselmann
        if callable(feedback_fn):
1164 6c5a7090 Michael Hanselmann
          feedback_fn(log_entry[1:])
1165 6c5a7090 Michael Hanselmann
        else:
1166 26f15862 Iustin Pop
          encoded = utils.SafeEncode(message)
1167 03298ebe Michael Hanselmann
          ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)), encoded)
1168 6c5a7090 Michael Hanselmann
        prev_logmsg_serial = max(prev_logmsg_serial, serial)
1169 6c5a7090 Michael Hanselmann
1170 0bbe448c Michael Hanselmann
    # TODO: Handle canceled and archived jobs
1171 fbf0262f Michael Hanselmann
    elif status in (constants.JOB_STATUS_SUCCESS,
1172 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_ERROR,
1173 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELING,
1174 fbf0262f Michael Hanselmann
                    constants.JOB_STATUS_CANCELED):
1175 685ee993 Iustin Pop
      break
1176 6c5a7090 Michael Hanselmann
1177 6c5a7090 Michael Hanselmann
    prev_job_info = job_info
1178 685ee993 Iustin Pop
1179 0e050889 Iustin Pop
  jobs = cl.QueryJobs([job_id], ["status", "opstatus", "opresult"])
1180 0bbe448c Michael Hanselmann
  if not jobs:
1181 0bbe448c Michael Hanselmann
    raise errors.JobLost("Job with id %s lost" % job_id)
1182 685ee993 Iustin Pop
1183 0e050889 Iustin Pop
  status, opstatus, result = jobs[0]
1184 0bbe448c Michael Hanselmann
  if status == constants.JOB_STATUS_SUCCESS:
1185 53c04d04 Iustin Pop
    return result
1186 fbf0262f Michael Hanselmann
  elif status in (constants.JOB_STATUS_CANCELING,
1187 fbf0262f Michael Hanselmann
                  constants.JOB_STATUS_CANCELED):
1188 fbf0262f Michael Hanselmann
    raise errors.OpExecError("Job was canceled")
1189 0bbe448c Michael Hanselmann
  else:
1190 0e050889 Iustin Pop
    has_ok = False
1191 0e050889 Iustin Pop
    for idx, (status, msg) in enumerate(zip(opstatus, result)):
1192 0e050889 Iustin Pop
      if status == constants.OP_STATUS_SUCCESS:
1193 0e050889 Iustin Pop
        has_ok = True
1194 0e050889 Iustin Pop
      elif status == constants.OP_STATUS_ERROR:
1195 bcb66fca Iustin Pop
        errors.MaybeRaise(msg)
1196 0e050889 Iustin Pop
        if has_ok:
1197 0e050889 Iustin Pop
          raise errors.OpExecError("partial failure (opcode %d): %s" %
1198 0e050889 Iustin Pop
                                   (idx, msg))
1199 0e050889 Iustin Pop
        else:
1200 0e050889 Iustin Pop
          raise errors.OpExecError(str(msg))
1201 0e050889 Iustin Pop
    # default failure mode
1202 0bbe448c Michael Hanselmann
    raise errors.OpExecError(result)
1203 ceab32dd Iustin Pop
1204 ceab32dd Iustin Pop
1205 293ba2d8 Iustin Pop
def SubmitOpCode(op, cl=None, feedback_fn=None, opts=None):
1206 0a1e74d9 Iustin Pop
  """Legacy function to submit an opcode.
1207 0a1e74d9 Iustin Pop

1208 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1209 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1210 0a1e74d9 Iustin Pop
  interaction functions.
1211 0a1e74d9 Iustin Pop

1212 0a1e74d9 Iustin Pop
  """
1213 0a1e74d9 Iustin Pop
  if cl is None:
1214 0a1e74d9 Iustin Pop
    cl = GetClient()
1215 0a1e74d9 Iustin Pop
1216 293ba2d8 Iustin Pop
  SetGenericOpcodeOpts([op], opts)
1217 293ba2d8 Iustin Pop
1218 0a1e74d9 Iustin Pop
  job_id = SendJob([op], cl)
1219 0a1e74d9 Iustin Pop
1220 53c04d04 Iustin Pop
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn)
1221 53c04d04 Iustin Pop
1222 53c04d04 Iustin Pop
  return op_results[0]
1223 0a1e74d9 Iustin Pop
1224 0a1e74d9 Iustin Pop
1225 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1226 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1227 94428652 Iustin Pop

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

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

1236 94428652 Iustin Pop
  """
1237 94428652 Iustin Pop
  if opts and opts.submit_only:
1238 293ba2d8 Iustin Pop
    job = [op]
1239 293ba2d8 Iustin Pop
    SetGenericOpcodeOpts(job, opts)
1240 293ba2d8 Iustin Pop
    job_id = SendJob(job, cl=cl)
1241 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
1242 94428652 Iustin Pop
  else:
1243 293ba2d8 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
1244 293ba2d8 Iustin Pop
1245 293ba2d8 Iustin Pop
1246 293ba2d8 Iustin Pop
def SetGenericOpcodeOpts(opcode_list, options):
1247 293ba2d8 Iustin Pop
  """Processor for generic options.
1248 293ba2d8 Iustin Pop

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

1252 293ba2d8 Iustin Pop
  @param opcode_list: list of opcodes
1253 293ba2d8 Iustin Pop
  @param options: command line options or None
1254 293ba2d8 Iustin Pop
  @return: None (in-place modification)
1255 293ba2d8 Iustin Pop

1256 293ba2d8 Iustin Pop
  """
1257 293ba2d8 Iustin Pop
  if not options:
1258 293ba2d8 Iustin Pop
    return
1259 293ba2d8 Iustin Pop
  for op in opcode_list:
1260 293ba2d8 Iustin Pop
    op.dry_run = options.dry_run
1261 293ba2d8 Iustin Pop
    op.debug_level = options.debug
1262 94428652 Iustin Pop
1263 94428652 Iustin Pop
1264 af30b2fd Michael Hanselmann
def GetClient():
1265 af30b2fd Michael Hanselmann
  # TODO: Cache object?
1266 b33e986b Iustin Pop
  try:
1267 b33e986b Iustin Pop
    client = luxi.Client()
1268 b33e986b Iustin Pop
  except luxi.NoMasterError:
1269 d9a51679 Michael Hanselmann
    ss = ssconf.SimpleStore()
1270 d9a51679 Michael Hanselmann
1271 d9a51679 Michael Hanselmann
    # Try to read ssconf file
1272 d9a51679 Michael Hanselmann
    try:
1273 d9a51679 Michael Hanselmann
      ss.GetMasterNode()
1274 d9a51679 Michael Hanselmann
    except errors.ConfigurationError:
1275 d9a51679 Michael Hanselmann
      raise errors.OpPrereqError("Cluster not initialized or this machine is"
1276 d9a51679 Michael Hanselmann
                                 " not part of a cluster")
1277 d9a51679 Michael Hanselmann
1278 d9a51679 Michael Hanselmann
    master, myself = ssconf.GetMasterAndMyself(ss=ss)
1279 b33e986b Iustin Pop
    if master != myself:
1280 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
1281 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
1282 b33e986b Iustin Pop
                                 master)
1283 d9a51679 Michael Hanselmann
    raise
1284 b33e986b Iustin Pop
  return client
1285 af30b2fd Michael Hanselmann
1286 af30b2fd Michael Hanselmann
1287 73702ee7 Iustin Pop
def FormatError(err):
1288 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
1289 73702ee7 Iustin Pop

1290 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
1291 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
1292 73702ee7 Iustin Pop
  second, a string describing the error message (not
1293 73702ee7 Iustin Pop
  newline-terminated).
1294 73702ee7 Iustin Pop

1295 73702ee7 Iustin Pop
  """
1296 73702ee7 Iustin Pop
  retcode = 1
1297 73702ee7 Iustin Pop
  obuf = StringIO()
1298 e2e521d0 Iustin Pop
  msg = str(err)
1299 73702ee7 Iustin Pop
  if isinstance(err, errors.ConfigurationError):
1300 e2e521d0 Iustin Pop
    txt = "Corrupt configuration file: %s" % msg
1301 46fbdd04 Iustin Pop
    logging.error(txt)
1302 e2e521d0 Iustin Pop
    obuf.write(txt + "\n")
1303 73702ee7 Iustin Pop
    obuf.write("Aborting.")
1304 73702ee7 Iustin Pop
    retcode = 2
1305 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksAbort):
1306 73702ee7 Iustin Pop
    obuf.write("Failure: hooks execution failed:\n")
1307 73702ee7 Iustin Pop
    for node, script, out in err.args[0]:
1308 73702ee7 Iustin Pop
      if out:
1309 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s, output: %s\n" %
1310 73702ee7 Iustin Pop
                   (node, script, out))
1311 73702ee7 Iustin Pop
      else:
1312 73702ee7 Iustin Pop
        obuf.write("  node: %s, script: %s (no output)\n" %
1313 73702ee7 Iustin Pop
                   (node, script))
1314 73702ee7 Iustin Pop
  elif isinstance(err, errors.HooksFailure):
1315 e2e521d0 Iustin Pop
    obuf.write("Failure: hooks general failure: %s" % msg)
1316 73702ee7 Iustin Pop
  elif isinstance(err, errors.ResolverError):
1317 73702ee7 Iustin Pop
    this_host = utils.HostInfo.SysName()
1318 73702ee7 Iustin Pop
    if err.args[0] == this_host:
1319 73702ee7 Iustin Pop
      msg = "Failure: can't resolve my own hostname ('%s')"
1320 73702ee7 Iustin Pop
    else:
1321 73702ee7 Iustin Pop
      msg = "Failure: can't resolve hostname '%s'"
1322 73702ee7 Iustin Pop
    obuf.write(msg % err.args[0])
1323 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpPrereqError):
1324 5c983ee5 Iustin Pop
    if len(err.args) == 2:
1325 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
1326 5c983ee5 Iustin Pop
               " operation:\nerror type: %s, error details:\n%s" %
1327 5c983ee5 Iustin Pop
                 (err.args[1], err.args[0]))
1328 5c983ee5 Iustin Pop
    else:
1329 5c983ee5 Iustin Pop
      obuf.write("Failure: prerequisites not met for this"
1330 5c983ee5 Iustin Pop
                 " operation:\n%s" % msg)
1331 73702ee7 Iustin Pop
  elif isinstance(err, errors.OpExecError):
1332 e2e521d0 Iustin Pop
    obuf.write("Failure: command execution error:\n%s" % msg)
1333 73702ee7 Iustin Pop
  elif isinstance(err, errors.TagError):
1334 e2e521d0 Iustin Pop
    obuf.write("Failure: invalid tag(s) given:\n%s" % msg)
1335 686d7433 Iustin Pop
  elif isinstance(err, errors.JobQueueDrainError):
1336 686d7433 Iustin Pop
    obuf.write("Failure: the job queue is marked for drain and doesn't"
1337 686d7433 Iustin Pop
               " accept new requests\n")
1338 f87b405e Michael Hanselmann
  elif isinstance(err, errors.JobQueueFull):
1339 f87b405e Michael Hanselmann
    obuf.write("Failure: the job queue is full and doesn't accept new"
1340 f87b405e Michael Hanselmann
               " job submissions until old jobs are archived\n")
1341 a5728081 Guido Trotter
  elif isinstance(err, errors.TypeEnforcementError):
1342 a5728081 Guido Trotter
    obuf.write("Parameter Error: %s" % msg)
1343 c1ce76bb Iustin Pop
  elif isinstance(err, errors.ParameterError):
1344 c1ce76bb Iustin Pop
    obuf.write("Failure: unknown/wrong parameter name '%s'" % msg)
1345 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.NoMasterError):
1346 03a8dbdc Iustin Pop
    obuf.write("Cannot communicate with the master daemon.\nIs it running"
1347 082c5adb Michael Hanselmann
               " and listening for connections?")
1348 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.TimeoutError):
1349 03a8dbdc Iustin Pop
    obuf.write("Timeout while talking to the master daemon. Error:\n"
1350 03a8dbdc Iustin Pop
               "%s" % msg)
1351 03a8dbdc Iustin Pop
  elif isinstance(err, luxi.ProtocolError):
1352 03a8dbdc Iustin Pop
    obuf.write("Unhandled protocol error while talking to the master daemon:\n"
1353 03a8dbdc Iustin Pop
               "%s" % msg)
1354 797506fc Michael Hanselmann
  elif isinstance(err, errors.GenericError):
1355 797506fc Michael Hanselmann
    obuf.write("Unhandled Ganeti error: %s" % msg)
1356 e9d741b6 Iustin Pop
  elif isinstance(err, JobSubmittedException):
1357 e9d741b6 Iustin Pop
    obuf.write("JobID: %s\n" % err.args[0])
1358 e9d741b6 Iustin Pop
    retcode = 0
1359 73702ee7 Iustin Pop
  else:
1360 e2e521d0 Iustin Pop
    obuf.write("Unhandled exception: %s" % msg)
1361 73702ee7 Iustin Pop
  return retcode, obuf.getvalue().rstrip('\n')
1362 73702ee7 Iustin Pop
1363 73702ee7 Iustin Pop
1364 de47cf8f Guido Trotter
def GenericMain(commands, override=None, aliases=None):
1365 a8083063 Iustin Pop
  """Generic main function for all the gnt-* commands.
1366 a8083063 Iustin Pop

1367 334d1483 Iustin Pop
  Arguments:
1368 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
1369 334d1483 Iustin Pop
                for command line handling.
1370 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
1371 334d1483 Iustin Pop
                override command line options; this can be used to pass
1372 334d1483 Iustin Pop
                options from the scripts to generic functions
1373 de47cf8f Guido Trotter
    - aliases: dictionary with command aliases {'alias': 'target, ...}
1374 a8083063 Iustin Pop

1375 a8083063 Iustin Pop
  """
1376 a8083063 Iustin Pop
  # save the program name and the entire command line for later logging
1377 a8083063 Iustin Pop
  if sys.argv:
1378 a8083063 Iustin Pop
    binary = os.path.basename(sys.argv[0]) or sys.argv[0]
1379 a8083063 Iustin Pop
    if len(sys.argv) >= 2:
1380 a8083063 Iustin Pop
      binary += " " + sys.argv[1]
1381 a8083063 Iustin Pop
      old_cmdline = " ".join(sys.argv[2:])
1382 a8083063 Iustin Pop
    else:
1383 a8083063 Iustin Pop
      old_cmdline = ""
1384 a8083063 Iustin Pop
  else:
1385 a8083063 Iustin Pop
    binary = "<unknown program>"
1386 a8083063 Iustin Pop
    old_cmdline = ""
1387 a8083063 Iustin Pop
1388 de47cf8f Guido Trotter
  if aliases is None:
1389 de47cf8f Guido Trotter
    aliases = {}
1390 de47cf8f Guido Trotter
1391 3126878d Guido Trotter
  try:
1392 3126878d Guido Trotter
    func, options, args = _ParseArgs(sys.argv, commands, aliases)
1393 3126878d Guido Trotter
  except errors.ParameterError, err:
1394 3126878d Guido Trotter
    result, err_msg = FormatError(err)
1395 3126878d Guido Trotter
    ToStderr(err_msg)
1396 3126878d Guido Trotter
    return 1
1397 3126878d Guido Trotter
1398 a8083063 Iustin Pop
  if func is None: # parse error
1399 a8083063 Iustin Pop
    return 1
1400 a8083063 Iustin Pop
1401 334d1483 Iustin Pop
  if override is not None:
1402 334d1483 Iustin Pop
    for key, val in override.iteritems():
1403 334d1483 Iustin Pop
      setattr(options, key, val)
1404 334d1483 Iustin Pop
1405 82d9caef Iustin Pop
  utils.SetupLogging(constants.LOG_COMMANDS, debug=options.debug,
1406 82d9caef Iustin Pop
                     stderr_logging=True, program=binary)
1407 a8083063 Iustin Pop
1408 a8083063 Iustin Pop
  if old_cmdline:
1409 46fbdd04 Iustin Pop
    logging.info("run with arguments '%s'", old_cmdline)
1410 a8083063 Iustin Pop
  else:
1411 46fbdd04 Iustin Pop
    logging.info("run with no arguments")
1412 a8083063 Iustin Pop
1413 a8083063 Iustin Pop
  try:
1414 a4af651e Iustin Pop
    result = func(options, args)
1415 d8353c3a Iustin Pop
  except (errors.GenericError, luxi.ProtocolError,
1416 d8353c3a Iustin Pop
          JobSubmittedException), err:
1417 a4af651e Iustin Pop
    result, err_msg = FormatError(err)
1418 5bbd3f7f Michael Hanselmann
    logging.exception("Error during command processing")
1419 46fbdd04 Iustin Pop
    ToStderr(err_msg)
1420 a8083063 Iustin Pop
1421 a8083063 Iustin Pop
  return result
1422 137161c9 Michael Hanselmann
1423 137161c9 Michael Hanselmann
1424 d77490c5 Iustin Pop
def GenericInstanceCreate(mode, opts, args):
1425 d77490c5 Iustin Pop
  """Add an instance to the cluster via either creation or import.
1426 d77490c5 Iustin Pop

1427 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
1428 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
1429 d77490c5 Iustin Pop
  @type args: list
1430 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
1431 d77490c5 Iustin Pop
  @rtype: int
1432 d77490c5 Iustin Pop
  @return: the desired exit code
1433 d77490c5 Iustin Pop

1434 d77490c5 Iustin Pop
  """
1435 d77490c5 Iustin Pop
  instance = args[0]
1436 d77490c5 Iustin Pop
1437 d77490c5 Iustin Pop
  (pnode, snode) = SplitNodeOption(opts.node)
1438 d77490c5 Iustin Pop
1439 d77490c5 Iustin Pop
  hypervisor = None
1440 d77490c5 Iustin Pop
  hvparams = {}
1441 d77490c5 Iustin Pop
  if opts.hypervisor:
1442 d77490c5 Iustin Pop
    hypervisor, hvparams = opts.hypervisor
1443 d77490c5 Iustin Pop
1444 d77490c5 Iustin Pop
  if opts.nics:
1445 d77490c5 Iustin Pop
    try:
1446 21bcb9aa Michael Hanselmann
      nic_max = max(int(nidx[0]) + 1 for nidx in opts.nics)
1447 d77490c5 Iustin Pop
    except ValueError, err:
1448 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Invalid NIC index passed: %s" % str(err))
1449 d77490c5 Iustin Pop
    nics = [{}] * nic_max
1450 d77490c5 Iustin Pop
    for nidx, ndict in opts.nics:
1451 d77490c5 Iustin Pop
      nidx = int(nidx)
1452 d77490c5 Iustin Pop
      if not isinstance(ndict, dict):
1453 d77490c5 Iustin Pop
        msg = "Invalid nic/%d value: expected dict, got %s" % (nidx, ndict)
1454 d77490c5 Iustin Pop
        raise errors.OpPrereqError(msg)
1455 d77490c5 Iustin Pop
      nics[nidx] = ndict
1456 d77490c5 Iustin Pop
  elif opts.no_nics:
1457 d77490c5 Iustin Pop
    # no nics
1458 d77490c5 Iustin Pop
    nics = []
1459 d77490c5 Iustin Pop
  else:
1460 d77490c5 Iustin Pop
    # default of one nic, all auto
1461 d77490c5 Iustin Pop
    nics = [{}]
1462 d77490c5 Iustin Pop
1463 d77490c5 Iustin Pop
  if opts.disk_template == constants.DT_DISKLESS:
1464 d77490c5 Iustin Pop
    if opts.disks or opts.sd_size is not None:
1465 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Diskless instance but disk"
1466 d77490c5 Iustin Pop
                                 " information passed")
1467 d77490c5 Iustin Pop
    disks = []
1468 d77490c5 Iustin Pop
  else:
1469 d77490c5 Iustin Pop
    if not opts.disks and not opts.sd_size:
1470 d77490c5 Iustin Pop
      raise errors.OpPrereqError("No disk information specified")
1471 d77490c5 Iustin Pop
    if opts.disks and opts.sd_size is not None:
1472 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Please use either the '--disk' or"
1473 d77490c5 Iustin Pop
                                 " '-s' option")
1474 d77490c5 Iustin Pop
    if opts.sd_size is not None:
1475 d77490c5 Iustin Pop
      opts.disks = [(0, {"size": opts.sd_size})]
1476 d77490c5 Iustin Pop
    try:
1477 21bcb9aa Michael Hanselmann
      disk_max = max(int(didx[0]) + 1 for didx in opts.disks)
1478 d77490c5 Iustin Pop
    except ValueError, err:
1479 d77490c5 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err))
1480 d77490c5 Iustin Pop
    disks = [{}] * disk_max
1481 d77490c5 Iustin Pop
    for didx, ddict in opts.disks:
1482 d77490c5 Iustin Pop
      didx = int(didx)
1483 d77490c5 Iustin Pop
      if not isinstance(ddict, dict):
1484 d77490c5 Iustin Pop
        msg = "Invalid disk/%d value: expected dict, got %s" % (didx, ddict)
1485 d77490c5 Iustin Pop
        raise errors.OpPrereqError(msg)
1486 d77490c5 Iustin Pop
      elif "size" not in ddict:
1487 d77490c5 Iustin Pop
        raise errors.OpPrereqError("Missing size for disk %d" % didx)
1488 d77490c5 Iustin Pop
      try:
1489 d77490c5 Iustin Pop
        ddict["size"] = utils.ParseUnit(ddict["size"])
1490 d77490c5 Iustin Pop
      except ValueError, err:
1491 d77490c5 Iustin Pop
        raise errors.OpPrereqError("Invalid disk size for disk %d: %s" %
1492 d77490c5 Iustin Pop
                                   (didx, err))
1493 d77490c5 Iustin Pop
      disks[didx] = ddict
1494 d77490c5 Iustin Pop
1495 d77490c5 Iustin Pop
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_TYPES)
1496 d77490c5 Iustin Pop
  utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
1497 d77490c5 Iustin Pop
1498 d77490c5 Iustin Pop
  if mode == constants.INSTANCE_CREATE:
1499 d77490c5 Iustin Pop
    start = opts.start
1500 d77490c5 Iustin Pop
    os_type = opts.os
1501 d77490c5 Iustin Pop
    src_node = None
1502 d77490c5 Iustin Pop
    src_path = None
1503 d77490c5 Iustin Pop
  elif mode == constants.INSTANCE_IMPORT:
1504 d77490c5 Iustin Pop
    start = False
1505 d77490c5 Iustin Pop
    os_type = None
1506 d77490c5 Iustin Pop
    src_node = opts.src_node
1507 d77490c5 Iustin Pop
    src_path = opts.src_dir
1508 d77490c5 Iustin Pop
  else:
1509 d77490c5 Iustin Pop
    raise errors.ProgrammerError("Invalid creation mode %s" % mode)
1510 d77490c5 Iustin Pop
1511 d77490c5 Iustin Pop
  op = opcodes.OpCreateInstance(instance_name=instance,
1512 d77490c5 Iustin Pop
                                disks=disks,
1513 d77490c5 Iustin Pop
                                disk_template=opts.disk_template,
1514 d77490c5 Iustin Pop
                                nics=nics,
1515 d77490c5 Iustin Pop
                                pnode=pnode, snode=snode,
1516 d77490c5 Iustin Pop
                                ip_check=opts.ip_check,
1517 460d22be Iustin Pop
                                name_check=opts.name_check,
1518 d77490c5 Iustin Pop
                                wait_for_sync=opts.wait_for_sync,
1519 d77490c5 Iustin Pop
                                file_storage_dir=opts.file_storage_dir,
1520 d77490c5 Iustin Pop
                                file_driver=opts.file_driver,
1521 d77490c5 Iustin Pop
                                iallocator=opts.iallocator,
1522 d77490c5 Iustin Pop
                                hypervisor=hypervisor,
1523 d77490c5 Iustin Pop
                                hvparams=hvparams,
1524 d77490c5 Iustin Pop
                                beparams=opts.beparams,
1525 d77490c5 Iustin Pop
                                mode=mode,
1526 d77490c5 Iustin Pop
                                start=start,
1527 d77490c5 Iustin Pop
                                os_type=os_type,
1528 d77490c5 Iustin Pop
                                src_node=src_node,
1529 d77490c5 Iustin Pop
                                src_path=src_path)
1530 d77490c5 Iustin Pop
1531 d77490c5 Iustin Pop
  SubmitOrSend(op, opts)
1532 d77490c5 Iustin Pop
  return 0
1533 d77490c5 Iustin Pop
1534 d77490c5 Iustin Pop
1535 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
1536 9fbfbb7b Iustin Pop
                  numfields=None, unitfields=None,
1537 9fbfbb7b Iustin Pop
                  units=None):
1538 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
1539 137161c9 Michael Hanselmann

1540 9fbfbb7b Iustin Pop
  @type headers: dict
1541 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
1542 9fbfbb7b Iustin Pop
      the table
1543 9fbfbb7b Iustin Pop
  @type fields: list
1544 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
1545 9fbfbb7b Iustin Pop
      the data field
1546 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
1547 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
1548 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
1549 9fbfbb7b Iustin Pop
      each field
1550 9fbfbb7b Iustin Pop
  @type data: list
1551 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
1552 9fbfbb7b Iustin Pop
  @type numfields: list
1553 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
1554 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
1555 9fbfbb7b Iustin Pop
  @type unitfields: list
1556 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
1557 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
1558 9fbfbb7b Iustin Pop
  @type units: string or None
1559 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
1560 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
1561 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
1562 137161c9 Michael Hanselmann

1563 137161c9 Michael Hanselmann
  """
1564 9fbfbb7b Iustin Pop
  if units is None:
1565 9fbfbb7b Iustin Pop
    if separator:
1566 9fbfbb7b Iustin Pop
      units = "m"
1567 9fbfbb7b Iustin Pop
    else:
1568 9fbfbb7b Iustin Pop
      units = "h"
1569 9fbfbb7b Iustin Pop
1570 137161c9 Michael Hanselmann
  if numfields is None:
1571 137161c9 Michael Hanselmann
    numfields = []
1572 137161c9 Michael Hanselmann
  if unitfields is None:
1573 137161c9 Michael Hanselmann
    unitfields = []
1574 137161c9 Michael Hanselmann
1575 fe267188 Iustin Pop
  numfields = utils.FieldSet(*numfields)   # pylint: disable-msg=W0142
1576 fe267188 Iustin Pop
  unitfields = utils.FieldSet(*unitfields) # pylint: disable-msg=W0142
1577 00430f8e Iustin Pop
1578 137161c9 Michael Hanselmann
  format_fields = []
1579 137161c9 Michael Hanselmann
  for field in fields:
1580 01ca31ae Iustin Pop
    if headers and field not in headers:
1581 ea5a5b74 Guido Trotter
      # TODO: handle better unknown fields (either revert to old
1582 71c1af58 Iustin Pop
      # style of raising exception, or deal more intelligently with
1583 71c1af58 Iustin Pop
      # variable fields)
1584 71c1af58 Iustin Pop
      headers[field] = field
1585 137161c9 Michael Hanselmann
    if separator is not None:
1586 137161c9 Michael Hanselmann
      format_fields.append("%s")
1587 00430f8e Iustin Pop
    elif numfields.Matches(field):
1588 137161c9 Michael Hanselmann
      format_fields.append("%*s")
1589 137161c9 Michael Hanselmann
    else:
1590 137161c9 Michael Hanselmann
      format_fields.append("%-*s")
1591 137161c9 Michael Hanselmann
1592 137161c9 Michael Hanselmann
  if separator is None:
1593 137161c9 Michael Hanselmann
    mlens = [0 for name in fields]
1594 137161c9 Michael Hanselmann
    format = ' '.join(format_fields)
1595 137161c9 Michael Hanselmann
  else:
1596 137161c9 Michael Hanselmann
    format = separator.replace("%", "%%").join(format_fields)
1597 137161c9 Michael Hanselmann
1598 137161c9 Michael Hanselmann
  for row in data:
1599 dcbd6288 Guido Trotter
    if row is None:
1600 dcbd6288 Guido Trotter
      continue
1601 137161c9 Michael Hanselmann
    for idx, val in enumerate(row):
1602 00430f8e Iustin Pop
      if unitfields.Matches(fields[idx]):
1603 137161c9 Michael Hanselmann
        try:
1604 137161c9 Michael Hanselmann
          val = int(val)
1605 691744c4 Iustin Pop
        except (TypeError, ValueError):
1606 137161c9 Michael Hanselmann
          pass
1607 137161c9 Michael Hanselmann
        else:
1608 9fbfbb7b Iustin Pop
          val = row[idx] = utils.FormatUnit(val, units)
1609 01ca31ae Iustin Pop
      val = row[idx] = str(val)
1610 137161c9 Michael Hanselmann
      if separator is None:
1611 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(val))
1612 137161c9 Michael Hanselmann
1613 16be8703 Iustin Pop
  result = []
1614 137161c9 Michael Hanselmann
  if headers:
1615 137161c9 Michael Hanselmann
    args = []
1616 137161c9 Michael Hanselmann
    for idx, name in enumerate(fields):
1617 137161c9 Michael Hanselmann
      hdr = headers[name]
1618 137161c9 Michael Hanselmann
      if separator is None:
1619 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(hdr))
1620 137161c9 Michael Hanselmann
        args.append(mlens[idx])
1621 137161c9 Michael Hanselmann
      args.append(hdr)
1622 16be8703 Iustin Pop
    result.append(format % tuple(args))
1623 137161c9 Michael Hanselmann
1624 ec39d63c Michael Hanselmann
  if separator is None:
1625 ec39d63c Michael Hanselmann
    assert len(mlens) == len(fields)
1626 ec39d63c Michael Hanselmann
1627 ec39d63c Michael Hanselmann
    if fields and not numfields.Matches(fields[-1]):
1628 ec39d63c Michael Hanselmann
      mlens[-1] = 0
1629 ec39d63c Michael Hanselmann
1630 137161c9 Michael Hanselmann
  for line in data:
1631 137161c9 Michael Hanselmann
    args = []
1632 dcbd6288 Guido Trotter
    if line is None:
1633 dcbd6288 Guido Trotter
      line = ['-' for _ in fields]
1634 f1501b3f Michael Hanselmann
    for idx in range(len(fields)):
1635 137161c9 Michael Hanselmann
      if separator is None:
1636 137161c9 Michael Hanselmann
        args.append(mlens[idx])
1637 137161c9 Michael Hanselmann
      args.append(line[idx])
1638 16be8703 Iustin Pop
    result.append(format % tuple(args))
1639 16be8703 Iustin Pop
1640 16be8703 Iustin Pop
  return result
1641 3386e7a9 Iustin Pop
1642 3386e7a9 Iustin Pop
1643 3386e7a9 Iustin Pop
def FormatTimestamp(ts):
1644 3386e7a9 Iustin Pop
  """Formats a given timestamp.
1645 3386e7a9 Iustin Pop

1646 3386e7a9 Iustin Pop
  @type ts: timestamp
1647 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
1648 3386e7a9 Iustin Pop

1649 3386e7a9 Iustin Pop
  @rtype: string
1650 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
1651 3386e7a9 Iustin Pop

1652 3386e7a9 Iustin Pop
  """
1653 e0ec0ff6 Iustin Pop
  if not isinstance (ts, (tuple, list)) or len(ts) != 2:
1654 e0ec0ff6 Iustin Pop
    return '?'
1655 3386e7a9 Iustin Pop
  sec, usec = ts
1656 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
1657 2241e2b9 Iustin Pop
1658 2241e2b9 Iustin Pop
1659 2241e2b9 Iustin Pop
def ParseTimespec(value):
1660 2241e2b9 Iustin Pop
  """Parse a time specification.
1661 2241e2b9 Iustin Pop

1662 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
1663 2241e2b9 Iustin Pop

1664 2241e2b9 Iustin Pop
    - s: seconds
1665 2241e2b9 Iustin Pop
    - m: minutes
1666 2241e2b9 Iustin Pop
    - h: hours
1667 2241e2b9 Iustin Pop
    - d: day
1668 2241e2b9 Iustin Pop
    - w: weeks
1669 2241e2b9 Iustin Pop

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

1672 2241e2b9 Iustin Pop
  """
1673 2241e2b9 Iustin Pop
  value = str(value)
1674 2241e2b9 Iustin Pop
  if not value:
1675 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
1676 2241e2b9 Iustin Pop
  suffix_map = {
1677 2241e2b9 Iustin Pop
    's': 1,
1678 2241e2b9 Iustin Pop
    'm': 60,
1679 2241e2b9 Iustin Pop
    'h': 3600,
1680 2241e2b9 Iustin Pop
    'd': 86400,
1681 2241e2b9 Iustin Pop
    'w': 604800,
1682 2241e2b9 Iustin Pop
    }
1683 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
1684 2241e2b9 Iustin Pop
    try:
1685 2241e2b9 Iustin Pop
      value = int(value)
1686 691744c4 Iustin Pop
    except (TypeError, ValueError):
1687 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
1688 2241e2b9 Iustin Pop
  else:
1689 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
1690 2241e2b9 Iustin Pop
    value = value[:-1]
1691 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
1692 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
1693 2241e2b9 Iustin Pop
                                 " suffix passed)")
1694 2241e2b9 Iustin Pop
    try:
1695 2241e2b9 Iustin Pop
      value = int(value) * multiplier
1696 691744c4 Iustin Pop
    except (TypeError, ValueError):
1697 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
1698 2241e2b9 Iustin Pop
  return value
1699 46fbdd04 Iustin Pop
1700 46fbdd04 Iustin Pop
1701 4040a784 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False):
1702 4040a784 Iustin Pop
  """Returns the names of online nodes.
1703 4040a784 Iustin Pop

1704 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
1705 4040a784 Iustin Pop
  the online nodes.
1706 4040a784 Iustin Pop

1707 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
1708 4040a784 Iustin Pop
      offline ones)
1709 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
1710 4040a784 Iustin Pop
  @type nowarn: boolean
1711 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
1712 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
1713 4040a784 Iustin Pop
      note is not displayed
1714 4040a784 Iustin Pop

1715 4040a784 Iustin Pop
  """
1716 4040a784 Iustin Pop
  if cl is None:
1717 4040a784 Iustin Pop
    cl = GetClient()
1718 4040a784 Iustin Pop
1719 2e7b8369 Iustin Pop
  result = cl.QueryNodes(names=nodes, fields=["name", "offline"],
1720 2e7b8369 Iustin Pop
                         use_locking=False)
1721 4040a784 Iustin Pop
  offline = [row[0] for row in result if row[1]]
1722 4040a784 Iustin Pop
  if offline and not nowarn:
1723 1f864b60 Iustin Pop
    ToStderr("Note: skipping offline node(s): %s" % utils.CommaJoin(offline))
1724 4040a784 Iustin Pop
  return [row[0] for row in result if not row[1]]
1725 4040a784 Iustin Pop
1726 4040a784 Iustin Pop
1727 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
1728 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
1729 46fbdd04 Iustin Pop

1730 46fbdd04 Iustin Pop
  @type stream: file object
1731 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
1732 46fbdd04 Iustin Pop
  @type txt: str
1733 46fbdd04 Iustin Pop
  @param txt: the message
1734 46fbdd04 Iustin Pop

1735 46fbdd04 Iustin Pop
  """
1736 46fbdd04 Iustin Pop
  if args:
1737 46fbdd04 Iustin Pop
    args = tuple(args)
1738 46fbdd04 Iustin Pop
    stream.write(txt % args)
1739 46fbdd04 Iustin Pop
  else:
1740 46fbdd04 Iustin Pop
    stream.write(txt)
1741 46fbdd04 Iustin Pop
  stream.write('\n')
1742 46fbdd04 Iustin Pop
  stream.flush()
1743 46fbdd04 Iustin Pop
1744 46fbdd04 Iustin Pop
1745 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
1746 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
1747 46fbdd04 Iustin Pop

1748 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
1749 46fbdd04 Iustin Pop

1750 46fbdd04 Iustin Pop
  @type txt: str
1751 46fbdd04 Iustin Pop
  @param txt: the message
1752 46fbdd04 Iustin Pop

1753 46fbdd04 Iustin Pop
  """
1754 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
1755 46fbdd04 Iustin Pop
1756 46fbdd04 Iustin Pop
1757 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
1758 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
1759 46fbdd04 Iustin Pop

1760 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
1761 46fbdd04 Iustin Pop

1762 46fbdd04 Iustin Pop
  @type txt: str
1763 46fbdd04 Iustin Pop
  @param txt: the message
1764 46fbdd04 Iustin Pop

1765 46fbdd04 Iustin Pop
  """
1766 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
1767 479636a3 Iustin Pop
1768 479636a3 Iustin Pop
1769 479636a3 Iustin Pop
class JobExecutor(object):
1770 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
1771 479636a3 Iustin Pop

1772 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
1773 479636a3 Iustin Pop
  GetResults() calls.
1774 479636a3 Iustin Pop

1775 479636a3 Iustin Pop
  """
1776 cff5fa7f Iustin Pop
  def __init__(self, cl=None, verbose=True, opts=None):
1777 479636a3 Iustin Pop
    self.queue = []
1778 479636a3 Iustin Pop
    if cl is None:
1779 479636a3 Iustin Pop
      cl = GetClient()
1780 479636a3 Iustin Pop
    self.cl = cl
1781 479636a3 Iustin Pop
    self.verbose = verbose
1782 23b4b983 Iustin Pop
    self.jobs = []
1783 cff5fa7f Iustin Pop
    self.opts = opts
1784 479636a3 Iustin Pop
1785 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
1786 23b4b983 Iustin Pop
    """Record a job for later submit.
1787 479636a3 Iustin Pop

1788 479636a3 Iustin Pop
    @type name: string
1789 479636a3 Iustin Pop
    @param name: a description of the job, will be used in WaitJobSet
1790 479636a3 Iustin Pop
    """
1791 cff5fa7f Iustin Pop
    SetGenericOpcodeOpts(ops, self.opts)
1792 23b4b983 Iustin Pop
    self.queue.append((name, ops))
1793 23b4b983 Iustin Pop
1794 23b4b983 Iustin Pop
  def SubmitPending(self):
1795 23b4b983 Iustin Pop
    """Submit all pending jobs.
1796 23b4b983 Iustin Pop

1797 23b4b983 Iustin Pop
    """
1798 23b4b983 Iustin Pop
    results = self.cl.SubmitManyJobs([row[1] for row in self.queue])
1799 23b4b983 Iustin Pop
    for ((status, data), (name, _)) in zip(results, self.queue):
1800 23b4b983 Iustin Pop
      self.jobs.append((status, data, name))
1801 479636a3 Iustin Pop
1802 479636a3 Iustin Pop
  def GetResults(self):
1803 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
1804 479636a3 Iustin Pop

1805 479636a3 Iustin Pop
    @rtype: list
1806 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
1807 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
1808 479636a3 Iustin Pop
        there will be the error message
1809 479636a3 Iustin Pop

1810 479636a3 Iustin Pop
    """
1811 23b4b983 Iustin Pop
    if not self.jobs:
1812 23b4b983 Iustin Pop
      self.SubmitPending()
1813 479636a3 Iustin Pop
    results = []
1814 479636a3 Iustin Pop
    if self.verbose:
1815 23b4b983 Iustin Pop
      ok_jobs = [row[1] for row in self.jobs if row[0]]
1816 23b4b983 Iustin Pop
      if ok_jobs:
1817 1f864b60 Iustin Pop
        ToStdout("Submitted jobs %s", utils.CommaJoin(ok_jobs))
1818 23b4b983 Iustin Pop
    for submit_status, jid, name in self.jobs:
1819 23b4b983 Iustin Pop
      if not submit_status:
1820 23b4b983 Iustin Pop
        ToStderr("Failed to submit job for %s: %s", name, jid)
1821 23b4b983 Iustin Pop
        results.append((False, jid))
1822 23b4b983 Iustin Pop
        continue
1823 479636a3 Iustin Pop
      if self.verbose:
1824 479636a3 Iustin Pop
        ToStdout("Waiting for job %s for %s...", jid, name)
1825 479636a3 Iustin Pop
      try:
1826 479636a3 Iustin Pop
        job_result = PollJob(jid, cl=self.cl)
1827 479636a3 Iustin Pop
        success = True
1828 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
1829 479636a3 Iustin Pop
        _, job_result = FormatError(err)
1830 479636a3 Iustin Pop
        success = False
1831 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
1832 479636a3 Iustin Pop
        ToStderr("Job %s for %s has failed: %s", jid, name, job_result)
1833 479636a3 Iustin Pop
1834 479636a3 Iustin Pop
      results.append((success, job_result))
1835 479636a3 Iustin Pop
    return results
1836 479636a3 Iustin Pop
1837 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
1838 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
1839 479636a3 Iustin Pop

1840 479636a3 Iustin Pop
    @type wait: boolean
1841 479636a3 Iustin Pop
    @param wait: whether to wait or not
1842 479636a3 Iustin Pop

1843 479636a3 Iustin Pop
    """
1844 479636a3 Iustin Pop
    if wait:
1845 479636a3 Iustin Pop
      return self.GetResults()
1846 479636a3 Iustin Pop
    else:
1847 23b4b983 Iustin Pop
      if not self.jobs:
1848 23b4b983 Iustin Pop
        self.SubmitPending()
1849 23b4b983 Iustin Pop
      for status, result, name in self.jobs:
1850 23b4b983 Iustin Pop
        if status:
1851 23b4b983 Iustin Pop
          ToStdout("%s: %s", result, name)
1852 23b4b983 Iustin Pop
        else:
1853 23b4b983 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)