Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ 919ca415

History | View | Annotate | Download (60.9 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 4c61d894 Iustin Pop
  "AUTO_PROMOTE_OPT",
49 e00f7a05 Iustin Pop
  "AUTO_REPLACE_OPT",
50 087ed2ed Iustin Pop
  "BACKEND_OPT",
51 baef337d Iustin Pop
  "CLEANUP_OPT",
52 4abc4f1e Iustin Pop
  "CONFIRM_OPT",
53 e32df528 Iustin Pop
  "CP_SIZE_OPT",
54 4abc4f1e Iustin Pop
  "DEBUG_OPT",
55 a0c9776a Iustin Pop
  "DEBUG_SIMERR_OPT",
56 4b038a1e Iustin Pop
  "DISKIDX_OPT",
57 e3876ccb Iustin Pop
  "DISK_OPT",
58 4b038a1e Iustin Pop
  "DISK_TEMPLATE_OPT",
59 771734c9 Iustin Pop
  "DRAINED_OPT",
60 7ea7bcf6 Iustin Pop
  "EARLY_RELEASE_OPT",
61 383a3591 Iustin Pop
  "ENABLED_HV_OPT",
62 14e9e7f3 Iustin Pop
  "ERROR_CODES_OPT",
63 4abc4f1e Iustin Pop
  "FIELDS_OPT",
64 4a25828c Iustin Pop
  "FILESTORE_DIR_OPT",
65 0f87c43e Iustin Pop
  "FILESTORE_DRIVER_OPT",
66 06073e85 Guido Trotter
  "FORCE_OPT",
67 06073e85 Guido Trotter
  "FORCE_VARIANT_OPT",
68 29392516 Iustin Pop
  "GLOBAL_FILEDIR_OPT",
69 073271f6 Iustin Pop
  "HVLIST_OPT",
70 48f212d7 Iustin Pop
  "HVOPTS_OPT",
71 236fd9c4 Iustin Pop
  "HYPERVISOR_OPT",
72 4eb62659 Iustin Pop
  "IALLOCATOR_OPT",
73 82a786d5 Iustin Pop
  "IGNORE_CONSIST_OPT",
74 b6e841a8 Iustin Pop
  "IGNORE_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 8d823629 Iustin Pop
  "SECONDARY_IP_OPT",
107 67840b40 Iustin Pop
  "SELECT_OS_OPT",
108 4abc4f1e Iustin Pop
  "SEP_OPT",
109 fdcf4d84 Iustin Pop
  "SHOWCMD_OPT",
110 7e5eaaa8 Guido Trotter
  "SHUTDOWN_TIMEOUT_OPT",
111 f36d7d81 Iustin Pop
  "SINGLE_NODE_OPT",
112 df62e5db Iustin Pop
  "SRC_DIR_OPT",
113 df62e5db Iustin Pop
  "SRC_NODE_OPT",
114 4abc4f1e Iustin Pop
  "SUBMIT_OPT",
115 99a8c799 Iustin Pop
  "STATIC_OPT",
116 4abc4f1e Iustin Pop
  "SYNC_OPT",
117 4abc4f1e Iustin Pop
  "TAG_SRC_OPT",
118 b5762e2a Guido Trotter
  "TIMEOUT_OPT",
119 4abc4f1e Iustin Pop
  "USEUNITS_OPT",
120 9cdb9578 Iustin Pop
  "VERBOSE_OPT",
121 b58726e8 Iustin Pop
  "VG_NAME_OPT",
122 1f587d3d Iustin Pop
  "YES_DOIT_OPT",
123 4abc4f1e Iustin Pop
  # Generic functions for CLI programs
124 4abc4f1e Iustin Pop
  "GenericMain",
125 d77490c5 Iustin Pop
  "GenericInstanceCreate",
126 4abc4f1e Iustin Pop
  "GetClient",
127 4abc4f1e Iustin Pop
  "GetOnlineNodes",
128 4abc4f1e Iustin Pop
  "JobExecutor",
129 4abc4f1e Iustin Pop
  "JobSubmittedException",
130 4abc4f1e Iustin Pop
  "ParseTimespec",
131 4abc4f1e Iustin Pop
  "SubmitOpCode",
132 4abc4f1e Iustin Pop
  "SubmitOrSend",
133 4abc4f1e Iustin Pop
  "UsesRPC",
134 4abc4f1e Iustin Pop
  # Formatting functions
135 4abc4f1e Iustin Pop
  "ToStderr", "ToStdout",
136 4abc4f1e Iustin Pop
  "FormatError",
137 4abc4f1e Iustin Pop
  "GenerateTable",
138 4abc4f1e Iustin Pop
  "AskUser",
139 4abc4f1e Iustin Pop
  "FormatTimestamp",
140 4abc4f1e Iustin Pop
  # Tags functions
141 4abc4f1e Iustin Pop
  "ListTags",
142 4abc4f1e Iustin Pop
  "AddTags",
143 4abc4f1e Iustin Pop
  "RemoveTags",
144 4abc4f1e Iustin Pop
  # command line options support infrastructure
145 4abc4f1e Iustin Pop
  "ARGS_MANY_INSTANCES",
146 4abc4f1e Iustin Pop
  "ARGS_MANY_NODES",
147 4abc4f1e Iustin Pop
  "ARGS_NONE",
148 4abc4f1e Iustin Pop
  "ARGS_ONE_INSTANCE",
149 4abc4f1e Iustin Pop
  "ARGS_ONE_NODE",
150 f9faf9c3 Renรฉ Nussbaumer
  "ARGS_ONE_OS",
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 f9faf9c3 Renรฉ Nussbaumer
  "ArgOs",
159 4abc4f1e Iustin Pop
  "ArgSuggest",
160 4abc4f1e Iustin Pop
  "ArgUnknown",
161 4abc4f1e Iustin Pop
  "OPT_COMPL_INST_ADD_NODES",
162 4abc4f1e Iustin Pop
  "OPT_COMPL_MANY_NODES",
163 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_IALLOCATOR",
164 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_INSTANCE",
165 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_NODE",
166 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_OS",
167 4abc4f1e Iustin Pop
  "cli_option",
168 4abc4f1e Iustin Pop
  "SplitNodeOption",
169 07150497 Guido Trotter
  "CalculateOSNames",
170 4abc4f1e Iustin Pop
  ]
171 846baef9 Iustin Pop
172 8b46606c Guido Trotter
NO_PREFIX = "no_"
173 8b46606c Guido Trotter
UN_PREFIX = "-"
174 846baef9 Iustin Pop
175 03298ebe Michael Hanselmann
176 863d7f46 Michael Hanselmann
class _Argument:
177 7260cfbe Iustin Pop
  def __init__(self, min=0, max=None): # pylint: disable-msg=W0622
178 863d7f46 Michael Hanselmann
    self.min = min
179 863d7f46 Michael Hanselmann
    self.max = max
180 863d7f46 Michael Hanselmann
181 863d7f46 Michael Hanselmann
  def __repr__(self):
182 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s>" %
183 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max))
184 863d7f46 Michael Hanselmann
185 863d7f46 Michael Hanselmann
186 863d7f46 Michael Hanselmann
class ArgSuggest(_Argument):
187 863d7f46 Michael Hanselmann
  """Suggesting argument.
188 863d7f46 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

249 83ec7961 Michael Hanselmann
  """
250 83ec7961 Michael Hanselmann
251 83ec7961 Michael Hanselmann
252 f9faf9c3 Renรฉ Nussbaumer
class ArgOs(_Argument):
253 f9faf9c3 Renรฉ Nussbaumer
  """OS argument.
254 f9faf9c3 Renรฉ Nussbaumer

255 f9faf9c3 Renรฉ Nussbaumer
  """
256 f9faf9c3 Renรฉ Nussbaumer
257 f9faf9c3 Renรฉ Nussbaumer
258 4a265c08 Michael Hanselmann
ARGS_NONE = []
259 4a265c08 Michael Hanselmann
ARGS_MANY_INSTANCES = [ArgInstance()]
260 4a265c08 Michael Hanselmann
ARGS_MANY_NODES = [ArgNode()]
261 4a265c08 Michael Hanselmann
ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
262 4a265c08 Michael Hanselmann
ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
263 f9faf9c3 Renรฉ Nussbaumer
ARGS_ONE_OS = [ArgOs(min=1, max=1)]
264 4a265c08 Michael Hanselmann
265 4a265c08 Michael Hanselmann
266 846baef9 Iustin Pop
def _ExtractTagsObject(opts, args):
267 846baef9 Iustin Pop
  """Extract the tag type object.
268 846baef9 Iustin Pop

269 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
270 846baef9 Iustin Pop

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

290 810c50b7 Iustin Pop
  This function will extend the tags with the contents of the file
291 810c50b7 Iustin Pop
  passed in the 'tags_source' attribute of the opts parameter. A file
292 810c50b7 Iustin Pop
  named '-' will be replaced by stdin.
293 810c50b7 Iustin Pop

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

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

324 846baef9 Iustin Pop
  """
325 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
326 7699c3af Iustin Pop
  cl = GetClient()
327 7699c3af Iustin Pop
  result = cl.QueryTags(kind, name)
328 846baef9 Iustin Pop
  result = list(result)
329 846baef9 Iustin Pop
  result.sort()
330 846baef9 Iustin Pop
  for tag in result:
331 03298ebe Michael Hanselmann
    ToStdout(tag)
332 846baef9 Iustin Pop
333 846baef9 Iustin Pop
334 846baef9 Iustin Pop
def AddTags(opts, args):
335 846baef9 Iustin Pop
  """Add tags on a given object.
336 846baef9 Iustin Pop

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

342 846baef9 Iustin Pop
  """
343 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
344 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
345 846baef9 Iustin Pop
  if not args:
346 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be added")
347 846baef9 Iustin Pop
  op = opcodes.OpAddTags(kind=kind, name=name, tags=args)
348 846baef9 Iustin Pop
  SubmitOpCode(op)
349 846baef9 Iustin Pop
350 846baef9 Iustin Pop
351 846baef9 Iustin Pop
def RemoveTags(opts, args):
352 846baef9 Iustin Pop
  """Remove tags from a given object.
353 846baef9 Iustin Pop

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

359 846baef9 Iustin Pop
  """
360 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
361 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
362 846baef9 Iustin Pop
  if not args:
363 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be removed")
364 846baef9 Iustin Pop
  op = opcodes.OpDelTags(kind=kind, name=name, tags=args)
365 846baef9 Iustin Pop
  SubmitOpCode(op)
366 846baef9 Iustin Pop
367 a8083063 Iustin Pop
368 8929d28c Iustin Pop
def check_unit(option, opt, value): # pylint: disable-msg=W0613
369 65fe4693 Iustin Pop
  """OptParsers custom converter for units.
370 65fe4693 Iustin Pop

371 65fe4693 Iustin Pop
  """
372 a8083063 Iustin Pop
  try:
373 a8083063 Iustin Pop
    return utils.ParseUnit(value)
374 a8083063 Iustin Pop
  except errors.UnitParseError, err:
375 3ecf6786 Iustin Pop
    raise OptionValueError("option %s: %s" % (opt, err))
376 a8083063 Iustin Pop
377 a8083063 Iustin Pop
378 a8469393 Iustin Pop
def _SplitKeyVal(opt, data):
379 a8469393 Iustin Pop
  """Convert a KeyVal string into a dict.
380 a8469393 Iustin Pop

381 a8469393 Iustin Pop
  This function will convert a key=val[,...] string into a dict. Empty
382 a8469393 Iustin Pop
  values will be converted specially: keys which have the prefix 'no_'
383 a8469393 Iustin Pop
  will have the value=False and the prefix stripped, the others will
384 a8469393 Iustin Pop
  have value=True.
385 a8469393 Iustin Pop

386 a8469393 Iustin Pop
  @type opt: string
387 a8469393 Iustin Pop
  @param opt: a string holding the option name for which we process the
388 a8469393 Iustin Pop
      data, used in building error messages
389 a8469393 Iustin Pop
  @type data: string
390 a8469393 Iustin Pop
  @param data: a string of the format key=val,key=val,...
391 a8469393 Iustin Pop
  @rtype: dict
392 a8469393 Iustin Pop
  @return: {key=val, key=val}
393 a8469393 Iustin Pop
  @raises errors.ParameterError: if there are duplicate keys
394 a8469393 Iustin Pop

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

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

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

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

448 a8469393 Iustin Pop
  """
449 a8469393 Iustin Pop
  return _SplitKeyVal(opt, value)
450 a8469393 Iustin Pop
451 a8469393 Iustin Pop
452 63d44c55 Michael Hanselmann
# completion_suggestion is normally a list. Using numeric values not evaluating
453 63d44c55 Michael Hanselmann
# to False for dynamic completion.
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 2d3ed64b Michael Hanselmann
 OPT_COMPL_ONE_IALLOCATOR,
459 2d3ed64b Michael Hanselmann
 OPT_COMPL_INST_ADD_NODES) = range(100, 106)
460 63d44c55 Michael Hanselmann
461 63d44c55 Michael Hanselmann
OPT_COMPL_ALL = frozenset([
462 63d44c55 Michael Hanselmann
  OPT_COMPL_MANY_NODES,
463 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_NODE,
464 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_INSTANCE,
465 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_OS,
466 63d44c55 Michael Hanselmann
  OPT_COMPL_ONE_IALLOCATOR,
467 2d3ed64b Michael Hanselmann
  OPT_COMPL_INST_ADD_NODES,
468 63d44c55 Michael Hanselmann
  ])
469 63d44c55 Michael Hanselmann
470 63d44c55 Michael Hanselmann
471 552c8dff Michael Hanselmann
class CliOption(Option):
472 552c8dff Michael Hanselmann
  """Custom option class for optparse.
473 a8469393 Iustin Pop

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

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

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

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

943 a8005e17 Michael Hanselmann
  Algorithm:
944 a8005e17 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1225 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1226 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1227 0a1e74d9 Iustin Pop
  interaction functions.
1228 0a1e74d9 Iustin Pop

1229 0a1e74d9 Iustin Pop
  """
1230 0a1e74d9 Iustin Pop
  if cl is None:
1231 0a1e74d9 Iustin Pop
    cl = GetClient()
1232 0a1e74d9 Iustin Pop
1233 293ba2d8 Iustin Pop
  SetGenericOpcodeOpts([op], opts)
1234 293ba2d8 Iustin Pop
1235 0a1e74d9 Iustin Pop
  job_id = SendJob([op], cl)
1236 0a1e74d9 Iustin Pop
1237 53c04d04 Iustin Pop
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn)
1238 53c04d04 Iustin Pop
1239 53c04d04 Iustin Pop
  return op_results[0]
1240 0a1e74d9 Iustin Pop
1241 0a1e74d9 Iustin Pop
1242 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1243 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1244 94428652 Iustin Pop

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

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

1253 94428652 Iustin Pop
  """
1254 94428652 Iustin Pop
  if opts and opts.submit_only:
1255 293ba2d8 Iustin Pop
    job = [op]
1256 293ba2d8 Iustin Pop
    SetGenericOpcodeOpts(job, opts)
1257 293ba2d8 Iustin Pop
    job_id = SendJob(job, cl=cl)
1258 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
1259 94428652 Iustin Pop
  else:
1260 293ba2d8 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
1261 293ba2d8 Iustin Pop
1262 293ba2d8 Iustin Pop
1263 293ba2d8 Iustin Pop
def SetGenericOpcodeOpts(opcode_list, options):
1264 293ba2d8 Iustin Pop
  """Processor for generic options.
1265 293ba2d8 Iustin Pop

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

1269 293ba2d8 Iustin Pop
  @param opcode_list: list of opcodes
1270 293ba2d8 Iustin Pop
  @param options: command line options or None
1271 293ba2d8 Iustin Pop
  @return: None (in-place modification)
1272 293ba2d8 Iustin Pop

1273 293ba2d8 Iustin Pop
  """
1274 293ba2d8 Iustin Pop
  if not options:
1275 293ba2d8 Iustin Pop
    return
1276 293ba2d8 Iustin Pop
  for op in opcode_list:
1277 293ba2d8 Iustin Pop
    op.dry_run = options.dry_run
1278 293ba2d8 Iustin Pop
    op.debug_level = options.debug
1279 94428652 Iustin Pop
1280 94428652 Iustin Pop
1281 af30b2fd Michael Hanselmann
def GetClient():
1282 af30b2fd Michael Hanselmann
  # TODO: Cache object?
1283 b33e986b Iustin Pop
  try:
1284 b33e986b Iustin Pop
    client = luxi.Client()
1285 b33e986b Iustin Pop
  except luxi.NoMasterError:
1286 d9a51679 Michael Hanselmann
    ss = ssconf.SimpleStore()
1287 d9a51679 Michael Hanselmann
1288 d9a51679 Michael Hanselmann
    # Try to read ssconf file
1289 d9a51679 Michael Hanselmann
    try:
1290 d9a51679 Michael Hanselmann
      ss.GetMasterNode()
1291 d9a51679 Michael Hanselmann
    except errors.ConfigurationError:
1292 d9a51679 Michael Hanselmann
      raise errors.OpPrereqError("Cluster not initialized or this machine is"
1293 d9a51679 Michael Hanselmann
                                 " not part of a cluster")
1294 d9a51679 Michael Hanselmann
1295 d9a51679 Michael Hanselmann
    master, myself = ssconf.GetMasterAndMyself(ss=ss)
1296 b33e986b Iustin Pop
    if master != myself:
1297 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
1298 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
1299 b33e986b Iustin Pop
                                 master)
1300 d9a51679 Michael Hanselmann
    raise
1301 b33e986b Iustin Pop
  return client
1302 af30b2fd Michael Hanselmann
1303 af30b2fd Michael Hanselmann
1304 73702ee7 Iustin Pop
def FormatError(err):
1305 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
1306 73702ee7 Iustin Pop

1307 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
1308 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
1309 73702ee7 Iustin Pop
  second, a string describing the error message (not
1310 73702ee7 Iustin Pop
  newline-terminated).
1311 73702ee7 Iustin Pop

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

1384 334d1483 Iustin Pop
  Arguments:
1385 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
1386 334d1483 Iustin Pop
                for command line handling.
1387 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
1388 334d1483 Iustin Pop
                override command line options; this can be used to pass
1389 334d1483 Iustin Pop
                options from the scripts to generic functions
1390 de47cf8f Guido Trotter
    - aliases: dictionary with command aliases {'alias': 'target, ...}
1391 a8083063 Iustin Pop

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

1444 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
1445 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
1446 d77490c5 Iustin Pop
  @type args: list
1447 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
1448 d77490c5 Iustin Pop
  @rtype: int
1449 d77490c5 Iustin Pop
  @return: the desired exit code
1450 d77490c5 Iustin Pop

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

1557 9fbfbb7b Iustin Pop
  @type headers: dict
1558 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
1559 9fbfbb7b Iustin Pop
      the table
1560 9fbfbb7b Iustin Pop
  @type fields: list
1561 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
1562 9fbfbb7b Iustin Pop
      the data field
1563 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
1564 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
1565 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
1566 9fbfbb7b Iustin Pop
      each field
1567 9fbfbb7b Iustin Pop
  @type data: list
1568 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
1569 9fbfbb7b Iustin Pop
  @type numfields: list
1570 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
1571 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
1572 9fbfbb7b Iustin Pop
  @type unitfields: list
1573 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
1574 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
1575 9fbfbb7b Iustin Pop
  @type units: string or None
1576 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
1577 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
1578 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
1579 137161c9 Michael Hanselmann

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

1663 3386e7a9 Iustin Pop
  @type ts: timestamp
1664 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
1665 3386e7a9 Iustin Pop

1666 3386e7a9 Iustin Pop
  @rtype: string
1667 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
1668 3386e7a9 Iustin Pop

1669 3386e7a9 Iustin Pop
  """
1670 e0ec0ff6 Iustin Pop
  if not isinstance (ts, (tuple, list)) or len(ts) != 2:
1671 e0ec0ff6 Iustin Pop
    return '?'
1672 3386e7a9 Iustin Pop
  sec, usec = ts
1673 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
1674 2241e2b9 Iustin Pop
1675 2241e2b9 Iustin Pop
1676 2241e2b9 Iustin Pop
def ParseTimespec(value):
1677 2241e2b9 Iustin Pop
  """Parse a time specification.
1678 2241e2b9 Iustin Pop

1679 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
1680 2241e2b9 Iustin Pop

1681 2241e2b9 Iustin Pop
    - s: seconds
1682 2241e2b9 Iustin Pop
    - m: minutes
1683 2241e2b9 Iustin Pop
    - h: hours
1684 2241e2b9 Iustin Pop
    - d: day
1685 2241e2b9 Iustin Pop
    - w: weeks
1686 2241e2b9 Iustin Pop

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

1689 2241e2b9 Iustin Pop
  """
1690 2241e2b9 Iustin Pop
  value = str(value)
1691 2241e2b9 Iustin Pop
  if not value:
1692 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
1693 2241e2b9 Iustin Pop
  suffix_map = {
1694 2241e2b9 Iustin Pop
    's': 1,
1695 2241e2b9 Iustin Pop
    'm': 60,
1696 2241e2b9 Iustin Pop
    'h': 3600,
1697 2241e2b9 Iustin Pop
    'd': 86400,
1698 2241e2b9 Iustin Pop
    'w': 604800,
1699 2241e2b9 Iustin Pop
    }
1700 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
1701 2241e2b9 Iustin Pop
    try:
1702 2241e2b9 Iustin Pop
      value = int(value)
1703 691744c4 Iustin Pop
    except (TypeError, ValueError):
1704 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
1705 2241e2b9 Iustin Pop
  else:
1706 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
1707 2241e2b9 Iustin Pop
    value = value[:-1]
1708 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
1709 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
1710 2241e2b9 Iustin Pop
                                 " suffix passed)")
1711 2241e2b9 Iustin Pop
    try:
1712 2241e2b9 Iustin Pop
      value = int(value) * multiplier
1713 691744c4 Iustin Pop
    except (TypeError, ValueError):
1714 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
1715 2241e2b9 Iustin Pop
  return value
1716 46fbdd04 Iustin Pop
1717 46fbdd04 Iustin Pop
1718 4040a784 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False):
1719 4040a784 Iustin Pop
  """Returns the names of online nodes.
1720 4040a784 Iustin Pop

1721 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
1722 4040a784 Iustin Pop
  the online nodes.
1723 4040a784 Iustin Pop

1724 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
1725 4040a784 Iustin Pop
      offline ones)
1726 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
1727 4040a784 Iustin Pop
  @type nowarn: boolean
1728 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
1729 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
1730 4040a784 Iustin Pop
      note is not displayed
1731 4040a784 Iustin Pop

1732 4040a784 Iustin Pop
  """
1733 4040a784 Iustin Pop
  if cl is None:
1734 4040a784 Iustin Pop
    cl = GetClient()
1735 4040a784 Iustin Pop
1736 2e7b8369 Iustin Pop
  result = cl.QueryNodes(names=nodes, fields=["name", "offline"],
1737 2e7b8369 Iustin Pop
                         use_locking=False)
1738 4040a784 Iustin Pop
  offline = [row[0] for row in result if row[1]]
1739 4040a784 Iustin Pop
  if offline and not nowarn:
1740 1f864b60 Iustin Pop
    ToStderr("Note: skipping offline node(s): %s" % utils.CommaJoin(offline))
1741 4040a784 Iustin Pop
  return [row[0] for row in result if not row[1]]
1742 4040a784 Iustin Pop
1743 4040a784 Iustin Pop
1744 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
1745 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
1746 46fbdd04 Iustin Pop

1747 46fbdd04 Iustin Pop
  @type stream: file object
1748 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
1749 46fbdd04 Iustin Pop
  @type txt: str
1750 46fbdd04 Iustin Pop
  @param txt: the message
1751 46fbdd04 Iustin Pop

1752 46fbdd04 Iustin Pop
  """
1753 46fbdd04 Iustin Pop
  if args:
1754 46fbdd04 Iustin Pop
    args = tuple(args)
1755 46fbdd04 Iustin Pop
    stream.write(txt % args)
1756 46fbdd04 Iustin Pop
  else:
1757 46fbdd04 Iustin Pop
    stream.write(txt)
1758 46fbdd04 Iustin Pop
  stream.write('\n')
1759 46fbdd04 Iustin Pop
  stream.flush()
1760 46fbdd04 Iustin Pop
1761 46fbdd04 Iustin Pop
1762 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
1763 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
1764 46fbdd04 Iustin Pop

1765 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
1766 46fbdd04 Iustin Pop

1767 46fbdd04 Iustin Pop
  @type txt: str
1768 46fbdd04 Iustin Pop
  @param txt: the message
1769 46fbdd04 Iustin Pop

1770 46fbdd04 Iustin Pop
  """
1771 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
1772 46fbdd04 Iustin Pop
1773 46fbdd04 Iustin Pop
1774 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
1775 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
1776 46fbdd04 Iustin Pop

1777 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
1778 46fbdd04 Iustin Pop

1779 46fbdd04 Iustin Pop
  @type txt: str
1780 46fbdd04 Iustin Pop
  @param txt: the message
1781 46fbdd04 Iustin Pop

1782 46fbdd04 Iustin Pop
  """
1783 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
1784 479636a3 Iustin Pop
1785 479636a3 Iustin Pop
1786 479636a3 Iustin Pop
class JobExecutor(object):
1787 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
1788 479636a3 Iustin Pop

1789 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
1790 479636a3 Iustin Pop
  GetResults() calls.
1791 479636a3 Iustin Pop

1792 479636a3 Iustin Pop
  """
1793 919ca415 Iustin Pop
  def __init__(self, cl=None, verbose=True, opts=None, feedback_fn=None):
1794 479636a3 Iustin Pop
    self.queue = []
1795 479636a3 Iustin Pop
    if cl is None:
1796 479636a3 Iustin Pop
      cl = GetClient()
1797 479636a3 Iustin Pop
    self.cl = cl
1798 479636a3 Iustin Pop
    self.verbose = verbose
1799 23b4b983 Iustin Pop
    self.jobs = []
1800 cff5fa7f Iustin Pop
    self.opts = opts
1801 919ca415 Iustin Pop
    self.feedback_fn = feedback_fn
1802 479636a3 Iustin Pop
1803 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
1804 23b4b983 Iustin Pop
    """Record a job for later submit.
1805 479636a3 Iustin Pop

1806 479636a3 Iustin Pop
    @type name: string
1807 479636a3 Iustin Pop
    @param name: a description of the job, will be used in WaitJobSet
1808 479636a3 Iustin Pop
    """
1809 cff5fa7f Iustin Pop
    SetGenericOpcodeOpts(ops, self.opts)
1810 23b4b983 Iustin Pop
    self.queue.append((name, ops))
1811 23b4b983 Iustin Pop
1812 23b4b983 Iustin Pop
  def SubmitPending(self):
1813 23b4b983 Iustin Pop
    """Submit all pending jobs.
1814 23b4b983 Iustin Pop

1815 23b4b983 Iustin Pop
    """
1816 23b4b983 Iustin Pop
    results = self.cl.SubmitManyJobs([row[1] for row in self.queue])
1817 5299e61f Iustin Pop
    for (idx, ((status, data), (name, _))) in enumerate(zip(results,
1818 5299e61f Iustin Pop
                                                            self.queue)):
1819 5299e61f Iustin Pop
      self.jobs.append((idx, status, data, name))
1820 5299e61f Iustin Pop
1821 5299e61f Iustin Pop
  def _ChooseJob(self):
1822 5299e61f Iustin Pop
    """Choose a non-waiting/queued job to poll next.
1823 5299e61f Iustin Pop

1824 5299e61f Iustin Pop
    """
1825 5299e61f Iustin Pop
    assert self.jobs, "_ChooseJob called with empty job list"
1826 5299e61f Iustin Pop
1827 5299e61f Iustin Pop
    result = self.cl.QueryJobs([i[2] for i in self.jobs], ["status"])
1828 5299e61f Iustin Pop
    assert result
1829 5299e61f Iustin Pop
1830 5299e61f Iustin Pop
    for job_data, status in zip(self.jobs, result):
1831 5299e61f Iustin Pop
      if status[0] in (constants.JOB_STATUS_QUEUED,
1832 5299e61f Iustin Pop
                    constants.JOB_STATUS_WAITLOCK,
1833 5299e61f Iustin Pop
                    constants.JOB_STATUS_CANCELING):
1834 5299e61f Iustin Pop
        # job is still waiting
1835 5299e61f Iustin Pop
        continue
1836 5299e61f Iustin Pop
      # good candidate found
1837 5299e61f Iustin Pop
      self.jobs.remove(job_data)
1838 5299e61f Iustin Pop
      return job_data
1839 5299e61f Iustin Pop
1840 5299e61f Iustin Pop
    # no job found
1841 5299e61f Iustin Pop
    return self.jobs.pop(0)
1842 479636a3 Iustin Pop
1843 479636a3 Iustin Pop
  def GetResults(self):
1844 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
1845 479636a3 Iustin Pop

1846 479636a3 Iustin Pop
    @rtype: list
1847 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
1848 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
1849 479636a3 Iustin Pop
        there will be the error message
1850 479636a3 Iustin Pop

1851 479636a3 Iustin Pop
    """
1852 23b4b983 Iustin Pop
    if not self.jobs:
1853 23b4b983 Iustin Pop
      self.SubmitPending()
1854 479636a3 Iustin Pop
    results = []
1855 479636a3 Iustin Pop
    if self.verbose:
1856 5299e61f Iustin Pop
      ok_jobs = [row[2] for row in self.jobs if row[1]]
1857 23b4b983 Iustin Pop
      if ok_jobs:
1858 1f864b60 Iustin Pop
        ToStdout("Submitted jobs %s", utils.CommaJoin(ok_jobs))
1859 5299e61f Iustin Pop
1860 5299e61f Iustin Pop
    # first, remove any non-submitted jobs
1861 5299e61f Iustin Pop
    self.jobs, failures = utils.partition(self.jobs, lambda x: x[1])
1862 5299e61f Iustin Pop
    for idx, _, jid, name in failures:
1863 23b4b983 Iustin Pop
        ToStderr("Failed to submit job for %s: %s", name, jid)
1864 5299e61f Iustin Pop
        results.append((idx, False, jid))
1865 5299e61f Iustin Pop
1866 5299e61f Iustin Pop
    while self.jobs:
1867 5299e61f Iustin Pop
      (idx, _, jid, name) = self._ChooseJob()
1868 5299e61f Iustin Pop
      ToStdout("Waiting for job %s for %s...", jid, name)
1869 479636a3 Iustin Pop
      try:
1870 919ca415 Iustin Pop
        job_result = PollJob(jid, cl=self.cl, feedback_fn=self.feedback_fn)
1871 479636a3 Iustin Pop
        success = True
1872 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
1873 479636a3 Iustin Pop
        _, job_result = FormatError(err)
1874 479636a3 Iustin Pop
        success = False
1875 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
1876 479636a3 Iustin Pop
        ToStderr("Job %s for %s has failed: %s", jid, name, job_result)
1877 479636a3 Iustin Pop
1878 5299e61f Iustin Pop
      results.append((idx, success, job_result))
1879 5299e61f Iustin Pop
1880 5299e61f Iustin Pop
    # sort based on the index, then drop it
1881 5299e61f Iustin Pop
    results.sort()
1882 5299e61f Iustin Pop
    results = [i[1:] for i in results]
1883 5299e61f Iustin Pop
1884 479636a3 Iustin Pop
    return results
1885 479636a3 Iustin Pop
1886 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
1887 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
1888 479636a3 Iustin Pop

1889 479636a3 Iustin Pop
    @type wait: boolean
1890 479636a3 Iustin Pop
    @param wait: whether to wait or not
1891 479636a3 Iustin Pop

1892 479636a3 Iustin Pop
    """
1893 479636a3 Iustin Pop
    if wait:
1894 479636a3 Iustin Pop
      return self.GetResults()
1895 479636a3 Iustin Pop
    else:
1896 23b4b983 Iustin Pop
      if not self.jobs:
1897 23b4b983 Iustin Pop
        self.SubmitPending()
1898 23b4b983 Iustin Pop
      for status, result, name in self.jobs:
1899 23b4b983 Iustin Pop
        if status:
1900 23b4b983 Iustin Pop
          ToStdout("%s: %s", result, name)
1901 23b4b983 Iustin Pop
        else:
1902 23b4b983 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)