Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ af1d39b1

History | View | Annotate | Download (75.3 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 a8083063 Iustin Pop
"""Module dealing with command line parsing"""
23 a8083063 Iustin Pop
24 a8083063 Iustin Pop
25 a8083063 Iustin Pop
import sys
26 a8083063 Iustin Pop
import textwrap
27 a8083063 Iustin Pop
import os.path
28 685ee993 Iustin Pop
import time
29 46fbdd04 Iustin Pop
import logging
30 73702ee7 Iustin Pop
from cStringIO import StringIO
31 a8083063 Iustin Pop
32 a8083063 Iustin Pop
from ganeti import utils
33 a8083063 Iustin Pop
from ganeti import errors
34 a8083063 Iustin Pop
from ganeti import constants
35 846baef9 Iustin Pop
from ganeti import opcodes
36 ceab32dd Iustin Pop
from ganeti import luxi
37 b33e986b Iustin Pop
from ganeti import ssconf
38 4331f6cd Michael Hanselmann
from ganeti import rpc
39 7e49b6ce Michael Hanselmann
from ganeti import ssh
40 cea881e5 Michael Hanselmann
from ganeti import compat
41 a8083063 Iustin Pop
42 c38c44ad Michael Hanselmann
from optparse import (OptionParser, TitledHelpFormatter,
43 38206f3c Iustin Pop
                      Option, OptionValueError)
44 a8083063 Iustin Pop
45 03298ebe Michael Hanselmann
46 4abc4f1e Iustin Pop
__all__ = [
47 4abc4f1e Iustin Pop
  # Command line options
48 fdad8c4d Balazs Lecz
  "ADD_UIDS_OPT",
49 e7e09483 Iustin Pop
  "ALLOCATABLE_OPT",
50 2d5e7ae1 Iustin Pop
  "ALL_OPT",
51 4c61d894 Iustin Pop
  "AUTO_PROMOTE_OPT",
52 e00f7a05 Iustin Pop
  "AUTO_REPLACE_OPT",
53 087ed2ed Iustin Pop
  "BACKEND_OPT",
54 baef337d Iustin Pop
  "CLEANUP_OPT",
55 3db3eb2a Michael Hanselmann
  "CLUSTER_DOMAIN_SECRET_OPT",
56 4abc4f1e Iustin Pop
  "CONFIRM_OPT",
57 e32df528 Iustin Pop
  "CP_SIZE_OPT",
58 4abc4f1e Iustin Pop
  "DEBUG_OPT",
59 a0c9776a Iustin Pop
  "DEBUG_SIMERR_OPT",
60 4b038a1e Iustin Pop
  "DISKIDX_OPT",
61 e3876ccb Iustin Pop
  "DISK_OPT",
62 4b038a1e Iustin Pop
  "DISK_TEMPLATE_OPT",
63 771734c9 Iustin Pop
  "DRAINED_OPT",
64 7ea7bcf6 Iustin Pop
  "EARLY_RELEASE_OPT",
65 383a3591 Iustin Pop
  "ENABLED_HV_OPT",
66 14e9e7f3 Iustin Pop
  "ERROR_CODES_OPT",
67 4abc4f1e Iustin Pop
  "FIELDS_OPT",
68 4a25828c Iustin Pop
  "FILESTORE_DIR_OPT",
69 0f87c43e Iustin Pop
  "FILESTORE_DRIVER_OPT",
70 06073e85 Guido Trotter
  "FORCE_OPT",
71 06073e85 Guido Trotter
  "FORCE_VARIANT_OPT",
72 29392516 Iustin Pop
  "GLOBAL_FILEDIR_OPT",
73 073271f6 Iustin Pop
  "HVLIST_OPT",
74 48f212d7 Iustin Pop
  "HVOPTS_OPT",
75 236fd9c4 Iustin Pop
  "HYPERVISOR_OPT",
76 4eb62659 Iustin Pop
  "IALLOCATOR_OPT",
77 e588764d Iustin Pop
  "IDENTIFY_DEFAULTS_OPT",
78 82a786d5 Iustin Pop
  "IGNORE_CONSIST_OPT",
79 b6e841a8 Iustin Pop
  "IGNORE_FAILURES_OPT",
80 8d8d650c Michael Hanselmann
  "IGNORE_REMOVE_FAILURES_OPT",
81 ee3f9578 Iustin Pop
  "IGNORE_SECONDARIES_OPT",
82 05586c90 Iustin Pop
  "IGNORE_SIZE_OPT",
83 e3646f22 Iustin Pop
  "MAC_PREFIX_OPT",
84 3953242f Iustin Pop
  "MAINTAIN_NODE_HEALTH_OPT",
85 29392516 Iustin Pop
  "MASTER_NETDEV_OPT",
86 771734c9 Iustin Pop
  "MC_OPT",
87 7d3a9fab Iustin Pop
  "NET_OPT",
88 6d4a1656 Michael Hanselmann
  "NEW_CLUSTER_CERT_OPT",
89 3db3eb2a Michael Hanselmann
  "NEW_CLUSTER_DOMAIN_SECRET_OPT",
90 6b7d5878 Michael Hanselmann
  "NEW_CONFD_HMAC_KEY_OPT",
91 6d4a1656 Michael Hanselmann
  "NEW_RAPI_CERT_OPT",
92 a14db5ff Iustin Pop
  "NEW_SECONDARY_OPT",
93 4fbc93dd Iustin Pop
  "NIC_PARAMS_OPT",
94 7edc4637 Iustin Pop
  "NODE_LIST_OPT",
95 990b7886 Iustin Pop
  "NODE_PLACEMENT_OPT",
96 4abc4f1e Iustin Pop
  "NOHDR_OPT",
97 91e0748c Iustin Pop
  "NOIPCHECK_OPT",
98 25a8792c Iustin Pop
  "NO_INSTALL_OPT",
99 460d22be Iustin Pop
  "NONAMECHECK_OPT",
100 831040bf Iustin Pop
  "NOLVM_STORAGE_OPT",
101 29392516 Iustin Pop
  "NOMODIFY_ETCHOSTS_OPT",
102 b989b9d9 Ken Wehr
  "NOMODIFY_SSH_SETUP_OPT",
103 26023ecd Iustin Pop
  "NONICS_OPT",
104 f2a0828c Iustin Pop
  "NONLIVE_OPT",
105 14e9e7f3 Iustin Pop
  "NONPLUS1_OPT",
106 44c44832 Iustin Pop
  "NOSHUTDOWN_OPT",
107 edeb878a Iustin Pop
  "NOSTART_OPT",
108 fcdde7f2 Iustin Pop
  "NOSSH_KEYCHECK_OPT",
109 58371861 Iustin Pop
  "NOVOTING_OPT",
110 3f75b4f3 Iustin Pop
  "NWSYNC_OPT",
111 a72d0a79 Iustin Pop
  "ON_PRIMARY_OPT",
112 feb09e6a Iustin Pop
  "ON_SECONDARY_OPT",
113 771734c9 Iustin Pop
  "OFFLINE_OPT",
114 d3ed23ff Iustin Pop
  "OS_OPT",
115 ff00c1a7 Iustin Pop
  "OS_SIZE_OPT",
116 6d4a1656 Michael Hanselmann
  "RAPI_CERT_OPT",
117 b8d0f938 Iustin Pop
  "READD_OPT",
118 12054861 Iustin Pop
  "REBOOT_TYPE_OPT",
119 8d8d650c Michael Hanselmann
  "REMOVE_INSTANCE_OPT",
120 fdad8c4d Balazs Lecz
  "REMOVE_UIDS_OPT",
121 31d97b2a Guido Trotter
  "ROMAN_OPT",
122 8d823629 Iustin Pop
  "SECONDARY_IP_OPT",
123 67840b40 Iustin Pop
  "SELECT_OS_OPT",
124 4abc4f1e Iustin Pop
  "SEP_OPT",
125 fdcf4d84 Iustin Pop
  "SHOWCMD_OPT",
126 7e5eaaa8 Guido Trotter
  "SHUTDOWN_TIMEOUT_OPT",
127 f36d7d81 Iustin Pop
  "SINGLE_NODE_OPT",
128 df62e5db Iustin Pop
  "SRC_DIR_OPT",
129 df62e5db Iustin Pop
  "SRC_NODE_OPT",
130 4abc4f1e Iustin Pop
  "SUBMIT_OPT",
131 99a8c799 Iustin Pop
  "STATIC_OPT",
132 4abc4f1e Iustin Pop
  "SYNC_OPT",
133 4abc4f1e Iustin Pop
  "TAG_SRC_OPT",
134 b5762e2a Guido Trotter
  "TIMEOUT_OPT",
135 1338f2b4 Balazs Lecz
  "UIDPOOL_OPT",
136 4abc4f1e Iustin Pop
  "USEUNITS_OPT",
137 74adc100 Iustin Pop
  "USE_REPL_NET_OPT",
138 9cdb9578 Iustin Pop
  "VERBOSE_OPT",
139 b58726e8 Iustin Pop
  "VG_NAME_OPT",
140 1f587d3d Iustin Pop
  "YES_DOIT_OPT",
141 4abc4f1e Iustin Pop
  # Generic functions for CLI programs
142 4abc4f1e Iustin Pop
  "GenericMain",
143 d77490c5 Iustin Pop
  "GenericInstanceCreate",
144 4abc4f1e Iustin Pop
  "GetClient",
145 4abc4f1e Iustin Pop
  "GetOnlineNodes",
146 4abc4f1e Iustin Pop
  "JobExecutor",
147 4abc4f1e Iustin Pop
  "JobSubmittedException",
148 4abc4f1e Iustin Pop
  "ParseTimespec",
149 7e49b6ce Michael Hanselmann
  "RunWhileClusterStopped",
150 4abc4f1e Iustin Pop
  "SubmitOpCode",
151 4abc4f1e Iustin Pop
  "SubmitOrSend",
152 4abc4f1e Iustin Pop
  "UsesRPC",
153 4abc4f1e Iustin Pop
  # Formatting functions
154 4abc4f1e Iustin Pop
  "ToStderr", "ToStdout",
155 4abc4f1e Iustin Pop
  "FormatError",
156 4abc4f1e Iustin Pop
  "GenerateTable",
157 4abc4f1e Iustin Pop
  "AskUser",
158 4abc4f1e Iustin Pop
  "FormatTimestamp",
159 4abc4f1e Iustin Pop
  # Tags functions
160 4abc4f1e Iustin Pop
  "ListTags",
161 4abc4f1e Iustin Pop
  "AddTags",
162 4abc4f1e Iustin Pop
  "RemoveTags",
163 4abc4f1e Iustin Pop
  # command line options support infrastructure
164 4abc4f1e Iustin Pop
  "ARGS_MANY_INSTANCES",
165 4abc4f1e Iustin Pop
  "ARGS_MANY_NODES",
166 4abc4f1e Iustin Pop
  "ARGS_NONE",
167 4abc4f1e Iustin Pop
  "ARGS_ONE_INSTANCE",
168 4abc4f1e Iustin Pop
  "ARGS_ONE_NODE",
169 f9faf9c3 Renรฉ Nussbaumer
  "ARGS_ONE_OS",
170 4abc4f1e Iustin Pop
  "ArgChoice",
171 4abc4f1e Iustin Pop
  "ArgCommand",
172 4abc4f1e Iustin Pop
  "ArgFile",
173 4abc4f1e Iustin Pop
  "ArgHost",
174 4abc4f1e Iustin Pop
  "ArgInstance",
175 4abc4f1e Iustin Pop
  "ArgJobId",
176 4abc4f1e Iustin Pop
  "ArgNode",
177 f9faf9c3 Renรฉ Nussbaumer
  "ArgOs",
178 4abc4f1e Iustin Pop
  "ArgSuggest",
179 4abc4f1e Iustin Pop
  "ArgUnknown",
180 4abc4f1e Iustin Pop
  "OPT_COMPL_INST_ADD_NODES",
181 4abc4f1e Iustin Pop
  "OPT_COMPL_MANY_NODES",
182 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_IALLOCATOR",
183 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_INSTANCE",
184 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_NODE",
185 4abc4f1e Iustin Pop
  "OPT_COMPL_ONE_OS",
186 4abc4f1e Iustin Pop
  "cli_option",
187 4abc4f1e Iustin Pop
  "SplitNodeOption",
188 07150497 Guido Trotter
  "CalculateOSNames",
189 4abc4f1e Iustin Pop
  ]
190 846baef9 Iustin Pop
191 8b46606c Guido Trotter
NO_PREFIX = "no_"
192 8b46606c Guido Trotter
UN_PREFIX = "-"
193 846baef9 Iustin Pop
194 03298ebe Michael Hanselmann
195 863d7f46 Michael Hanselmann
class _Argument:
196 7260cfbe Iustin Pop
  def __init__(self, min=0, max=None): # pylint: disable-msg=W0622
197 863d7f46 Michael Hanselmann
    self.min = min
198 863d7f46 Michael Hanselmann
    self.max = max
199 863d7f46 Michael Hanselmann
200 863d7f46 Michael Hanselmann
  def __repr__(self):
201 863d7f46 Michael Hanselmann
    return ("<%s min=%s max=%s>" %
202 863d7f46 Michael Hanselmann
            (self.__class__.__name__, self.min, self.max))
203 863d7f46 Michael Hanselmann
204 863d7f46 Michael Hanselmann
205 863d7f46 Michael Hanselmann
class ArgSuggest(_Argument):
206 863d7f46 Michael Hanselmann
  """Suggesting argument.
207 863d7f46 Michael Hanselmann

208 863d7f46 Michael Hanselmann
  Value can be any of the ones passed to the constructor.
209 863d7f46 Michael Hanselmann

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

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

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

233 863d7f46 Michael Hanselmann
  """
234 863d7f46 Michael Hanselmann
235 863d7f46 Michael Hanselmann
236 863d7f46 Michael Hanselmann
class ArgInstance(_Argument):
237 863d7f46 Michael Hanselmann
  """Instances argument.
238 863d7f46 Michael Hanselmann

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

245 863d7f46 Michael Hanselmann
  """
246 863d7f46 Michael Hanselmann
247 863d7f46 Michael Hanselmann
class ArgJobId(_Argument):
248 863d7f46 Michael Hanselmann
  """Job ID argument.
249 863d7f46 Michael Hanselmann

250 863d7f46 Michael Hanselmann
  """
251 863d7f46 Michael Hanselmann
252 863d7f46 Michael Hanselmann
253 863d7f46 Michael Hanselmann
class ArgFile(_Argument):
254 863d7f46 Michael Hanselmann
  """File path argument.
255 863d7f46 Michael Hanselmann

256 863d7f46 Michael Hanselmann
  """
257 863d7f46 Michael Hanselmann
258 863d7f46 Michael Hanselmann
259 863d7f46 Michael Hanselmann
class ArgCommand(_Argument):
260 863d7f46 Michael Hanselmann
  """Command argument.
261 863d7f46 Michael Hanselmann

262 863d7f46 Michael Hanselmann
  """
263 863d7f46 Michael Hanselmann
264 863d7f46 Michael Hanselmann
265 83ec7961 Michael Hanselmann
class ArgHost(_Argument):
266 83ec7961 Michael Hanselmann
  """Host argument.
267 83ec7961 Michael Hanselmann

268 83ec7961 Michael Hanselmann
  """
269 83ec7961 Michael Hanselmann
270 83ec7961 Michael Hanselmann
271 f9faf9c3 Renรฉ Nussbaumer
class ArgOs(_Argument):
272 f9faf9c3 Renรฉ Nussbaumer
  """OS argument.
273 f9faf9c3 Renรฉ Nussbaumer

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

288 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
289 846baef9 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

474 e7b61bb0 Iustin Pop
  This will store the parsed value as either True or False.
475 e7b61bb0 Iustin Pop

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

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

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

994 c41eea6e Iustin Pop
  @param argv: the command line
995 c41eea6e Iustin Pop
  @param commands: dictionary with special contents, see the design
996 c41eea6e Iustin Pop
      doc for cmdline handling
997 c41eea6e Iustin Pop
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
998 098c0958 Michael Hanselmann

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

1069 a8005e17 Michael Hanselmann
  Algorithm:
1070 a8005e17 Michael Hanselmann

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

1073 a8005e17 Michael Hanselmann
    1. For each argument in definition
1074 a8005e17 Michael Hanselmann

1075 a8005e17 Michael Hanselmann
      1. Keep running count of minimum number of values (min_count)
1076 a8005e17 Michael Hanselmann
      1. Keep running count of maximum number of values (max_count)
1077 a8005e17 Michael Hanselmann
      1. If it has an unlimited number of values
1078 a8005e17 Michael Hanselmann

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

1081 a8005e17 Michael Hanselmann
    1. If last argument has limited number of values
1082 a8005e17 Michael Hanselmann

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

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

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

1140 60d49723 Michael Hanselmann
  """
1141 60d49723 Michael Hanselmann
  if value and ':' in value:
1142 60d49723 Michael Hanselmann
    return value.split(':', 1)
1143 60d49723 Michael Hanselmann
  else:
1144 60d49723 Michael Hanselmann
    return (value, None)
1145 60d49723 Michael Hanselmann
1146 60d49723 Michael Hanselmann
1147 07150497 Guido Trotter
def CalculateOSNames(os_name, os_variants):
1148 07150497 Guido Trotter
  """Calculates all the names an OS can be called, according to its variants.
1149 07150497 Guido Trotter

1150 07150497 Guido Trotter
  @type os_name: string
1151 07150497 Guido Trotter
  @param os_name: base name of the os
1152 07150497 Guido Trotter
  @type os_variants: list or None
1153 07150497 Guido Trotter
  @param os_variants: list of supported variants
1154 07150497 Guido Trotter
  @rtype: list
1155 07150497 Guido Trotter
  @return: list of valid names
1156 07150497 Guido Trotter

1157 07150497 Guido Trotter
  """
1158 07150497 Guido Trotter
  if os_variants:
1159 07150497 Guido Trotter
    return ['%s+%s' % (os_name, v) for v in os_variants]
1160 07150497 Guido Trotter
  else:
1161 07150497 Guido Trotter
    return [os_name]
1162 07150497 Guido Trotter
1163 07150497 Guido Trotter
1164 4331f6cd Michael Hanselmann
def UsesRPC(fn):
1165 4331f6cd Michael Hanselmann
  def wrapper(*args, **kwargs):
1166 4331f6cd Michael Hanselmann
    rpc.Init()
1167 4331f6cd Michael Hanselmann
    try:
1168 4331f6cd Michael Hanselmann
      return fn(*args, **kwargs)
1169 4331f6cd Michael Hanselmann
    finally:
1170 4331f6cd Michael Hanselmann
      rpc.Shutdown()
1171 4331f6cd Michael Hanselmann
  return wrapper
1172 4331f6cd Michael Hanselmann
1173 4331f6cd Michael Hanselmann
1174 47988778 Iustin Pop
def AskUser(text, choices=None):
1175 47988778 Iustin Pop
  """Ask the user a question.
1176 a8083063 Iustin Pop

1177 c41eea6e Iustin Pop
  @param text: the question to ask
1178 a8083063 Iustin Pop

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

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

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

1234 e9d741b6 Iustin Pop
  This exception has one argument, the ID of the job that was
1235 e9d741b6 Iustin Pop
  submitted. The handler should print this ID.
1236 e9d741b6 Iustin Pop

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

1239 e9d741b6 Iustin Pop
  """
1240 e9d741b6 Iustin Pop
1241 e9d741b6 Iustin Pop
1242 0a1e74d9 Iustin Pop
def SendJob(ops, cl=None):
1243 0a1e74d9 Iustin Pop
  """Function to submit an opcode without waiting for the results.
1244 a8083063 Iustin Pop

1245 0a1e74d9 Iustin Pop
  @type ops: list
1246 0a1e74d9 Iustin Pop
  @param ops: list of opcodes
1247 0a1e74d9 Iustin Pop
  @type cl: luxi.Client
1248 0a1e74d9 Iustin Pop
  @param cl: the luxi client to use for communicating with the master;
1249 0a1e74d9 Iustin Pop
             if None, a new client will be created
1250 a8083063 Iustin Pop

1251 a8083063 Iustin Pop
  """
1252 e2212007 Iustin Pop
  if cl is None:
1253 b33e986b Iustin Pop
    cl = GetClient()
1254 685ee993 Iustin Pop
1255 0a1e74d9 Iustin Pop
  job_id = cl.SubmitJob(ops)
1256 0a1e74d9 Iustin Pop
1257 0a1e74d9 Iustin Pop
  return job_id
1258 0a1e74d9 Iustin Pop
1259 0a1e74d9 Iustin Pop
1260 4e338533 Michael Hanselmann
def GenericPollJob(job_id, cbs, report_cbs):
1261 4e338533 Michael Hanselmann
  """Generic job-polling function.
1262 0a1e74d9 Iustin Pop

1263 4e338533 Michael Hanselmann
  @type job_id: number
1264 4e338533 Michael Hanselmann
  @param job_id: Job ID
1265 4e338533 Michael Hanselmann
  @type cbs: Instance of L{JobPollCbBase}
1266 4e338533 Michael Hanselmann
  @param cbs: Data callbacks
1267 4e338533 Michael Hanselmann
  @type report_cbs: Instance of L{JobPollReportCbBase}
1268 4e338533 Michael Hanselmann
  @param report_cbs: Reporting callbacks
1269 0a1e74d9 Iustin Pop

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

1341 4e338533 Michael Hanselmann
  """
1342 4e338533 Michael Hanselmann
  def __init__(self):
1343 4e338533 Michael Hanselmann
    """Initializes this class.
1344 4e338533 Michael Hanselmann

1345 4e338533 Michael Hanselmann
    """
1346 4e338533 Michael Hanselmann
1347 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1348 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1349 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1350 4e338533 Michael Hanselmann

1351 4e338533 Michael Hanselmann
    """
1352 4e338533 Michael Hanselmann
    raise NotImplementedError()
1353 4e338533 Michael Hanselmann
1354 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1355 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1356 4e338533 Michael Hanselmann

1357 4e338533 Michael Hanselmann
    @type job_ids: list of numbers
1358 4e338533 Michael Hanselmann
    @param job_ids: Job IDs
1359 4e338533 Michael Hanselmann
    @type fields: list of strings
1360 4e338533 Michael Hanselmann
    @param fields: Fields
1361 4e338533 Michael Hanselmann

1362 4e338533 Michael Hanselmann
    """
1363 4e338533 Michael Hanselmann
    raise NotImplementedError()
1364 4e338533 Michael Hanselmann
1365 4e338533 Michael Hanselmann
1366 4e338533 Michael Hanselmann
class JobPollReportCbBase:
1367 4e338533 Michael Hanselmann
  """Base class for L{GenericPollJob} reporting callbacks.
1368 4e338533 Michael Hanselmann

1369 4e338533 Michael Hanselmann
  """
1370 4e338533 Michael Hanselmann
  def __init__(self):
1371 4e338533 Michael Hanselmann
    """Initializes this class.
1372 4e338533 Michael Hanselmann

1373 4e338533 Michael Hanselmann
    """
1374 4e338533 Michael Hanselmann
1375 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1376 4e338533 Michael Hanselmann
    """Handles a log message.
1377 4e338533 Michael Hanselmann

1378 4e338533 Michael Hanselmann
    """
1379 4e338533 Michael Hanselmann
    raise NotImplementedError()
1380 4e338533 Michael Hanselmann
1381 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1382 4e338533 Michael Hanselmann
    """Called for if a job hasn't changed in a while.
1383 4e338533 Michael Hanselmann

1384 4e338533 Michael Hanselmann
    @type job_id: number
1385 4e338533 Michael Hanselmann
    @param job_id: Job ID
1386 4e338533 Michael Hanselmann
    @type status: string or None
1387 4e338533 Michael Hanselmann
    @param status: Job status if available
1388 4e338533 Michael Hanselmann

1389 4e338533 Michael Hanselmann
    """
1390 4e338533 Michael Hanselmann
    raise NotImplementedError()
1391 4e338533 Michael Hanselmann
1392 4e338533 Michael Hanselmann
1393 4e338533 Michael Hanselmann
class _LuxiJobPollCb(JobPollCbBase):
1394 4e338533 Michael Hanselmann
  def __init__(self, cl):
1395 4e338533 Michael Hanselmann
    """Initializes this class.
1396 4e338533 Michael Hanselmann

1397 4e338533 Michael Hanselmann
    """
1398 4e338533 Michael Hanselmann
    JobPollCbBase.__init__(self)
1399 4e338533 Michael Hanselmann
    self.cl = cl
1400 4e338533 Michael Hanselmann
1401 4e338533 Michael Hanselmann
  def WaitForJobChangeOnce(self, job_id, fields,
1402 4e338533 Michael Hanselmann
                           prev_job_info, prev_log_serial):
1403 4e338533 Michael Hanselmann
    """Waits for changes on a job.
1404 4e338533 Michael Hanselmann

1405 4e338533 Michael Hanselmann
    """
1406 4e338533 Michael Hanselmann
    return self.cl.WaitForJobChangeOnce(job_id, fields,
1407 4e338533 Michael Hanselmann
                                        prev_job_info, prev_log_serial)
1408 4e338533 Michael Hanselmann
1409 4e338533 Michael Hanselmann
  def QueryJobs(self, job_ids, fields):
1410 4e338533 Michael Hanselmann
    """Returns the selected fields for the selected job IDs.
1411 4e338533 Michael Hanselmann

1412 4e338533 Michael Hanselmann
    """
1413 4e338533 Michael Hanselmann
    return self.cl.QueryJobs(job_ids, fields)
1414 4e338533 Michael Hanselmann
1415 4e338533 Michael Hanselmann
1416 4e338533 Michael Hanselmann
class FeedbackFnJobPollReportCb(JobPollReportCbBase):
1417 4e338533 Michael Hanselmann
  def __init__(self, feedback_fn):
1418 4e338533 Michael Hanselmann
    """Initializes this class.
1419 4e338533 Michael Hanselmann

1420 4e338533 Michael Hanselmann
    """
1421 4e338533 Michael Hanselmann
    JobPollReportCbBase.__init__(self)
1422 4e338533 Michael Hanselmann
1423 4e338533 Michael Hanselmann
    self.feedback_fn = feedback_fn
1424 4e338533 Michael Hanselmann
1425 4e338533 Michael Hanselmann
    assert callable(feedback_fn)
1426 4e338533 Michael Hanselmann
1427 4e338533 Michael Hanselmann
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
1428 4e338533 Michael Hanselmann
    """Handles a log message.
1429 4e338533 Michael Hanselmann

1430 4e338533 Michael Hanselmann
    """
1431 4e338533 Michael Hanselmann
    self.feedback_fn((timestamp, log_type, log_msg))
1432 4e338533 Michael Hanselmann
1433 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1434 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1435 4e338533 Michael Hanselmann

1436 4e338533 Michael Hanselmann
    """
1437 4e338533 Michael Hanselmann
    # Ignore
1438 4e338533 Michael Hanselmann
1439 4e338533 Michael Hanselmann
1440 4e338533 Michael Hanselmann
class StdioJobPollReportCb(JobPollReportCbBase):
1441 4e338533 Michael Hanselmann
  def __init__(self):
1442 4e338533 Michael Hanselmann
    """Initializes this class.
1443 4e338533 Michael Hanselmann

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

1453 4e338533 Michael Hanselmann
    """
1454 4e338533 Michael Hanselmann
    ToStdout("%s %s", time.ctime(utils.MergeTime(timestamp)),
1455 4e338533 Michael Hanselmann
             utils.SafeEncode(log_msg))
1456 4e338533 Michael Hanselmann
1457 4e338533 Michael Hanselmann
  def ReportNotChanged(self, job_id, status):
1458 4e338533 Michael Hanselmann
    """Called if a job hasn't changed in a while.
1459 4e338533 Michael Hanselmann

1460 4e338533 Michael Hanselmann
    """
1461 4e338533 Michael Hanselmann
    if status is None:
1462 4e338533 Michael Hanselmann
      return
1463 4e338533 Michael Hanselmann
1464 4e338533 Michael Hanselmann
    if status == constants.JOB_STATUS_QUEUED and not self.notified_queued:
1465 4e338533 Michael Hanselmann
      ToStderr("Job %s is waiting in queue", job_id)
1466 4e338533 Michael Hanselmann
      self.notified_queued = True
1467 4e338533 Michael Hanselmann
1468 4e338533 Michael Hanselmann
    elif status == constants.JOB_STATUS_WAITLOCK and not self.notified_waitlock:
1469 4e338533 Michael Hanselmann
      ToStderr("Job %s is trying to acquire all necessary locks", job_id)
1470 4e338533 Michael Hanselmann
      self.notified_waitlock = True
1471 4e338533 Michael Hanselmann
1472 4e338533 Michael Hanselmann
1473 4e338533 Michael Hanselmann
def PollJob(job_id, cl=None, feedback_fn=None):
1474 4e338533 Michael Hanselmann
  """Function to poll for the result of a job.
1475 4e338533 Michael Hanselmann

1476 4e338533 Michael Hanselmann
  @type job_id: job identified
1477 4e338533 Michael Hanselmann
  @param job_id: the job to poll for results
1478 4e338533 Michael Hanselmann
  @type cl: luxi.Client
1479 4e338533 Michael Hanselmann
  @param cl: the luxi client to use for communicating with the master;
1480 4e338533 Michael Hanselmann
             if None, a new client will be created
1481 4e338533 Michael Hanselmann

1482 4e338533 Michael Hanselmann
  """
1483 4e338533 Michael Hanselmann
  if cl is None:
1484 4e338533 Michael Hanselmann
    cl = GetClient()
1485 4e338533 Michael Hanselmann
1486 4e338533 Michael Hanselmann
  if feedback_fn:
1487 4e338533 Michael Hanselmann
    reporter = FeedbackFnJobPollReportCb(feedback_fn)
1488 0bbe448c Michael Hanselmann
  else:
1489 4e338533 Michael Hanselmann
    reporter = StdioJobPollReportCb()
1490 4e338533 Michael Hanselmann
1491 4e338533 Michael Hanselmann
  return GenericPollJob(job_id, _LuxiJobPollCb(cl), reporter)
1492 ceab32dd Iustin Pop
1493 ceab32dd Iustin Pop
1494 293ba2d8 Iustin Pop
def SubmitOpCode(op, cl=None, feedback_fn=None, opts=None):
1495 0a1e74d9 Iustin Pop
  """Legacy function to submit an opcode.
1496 0a1e74d9 Iustin Pop

1497 0a1e74d9 Iustin Pop
  This is just a simple wrapper over the construction of the processor
1498 0a1e74d9 Iustin Pop
  instance. It should be extended to better handle feedback and
1499 0a1e74d9 Iustin Pop
  interaction functions.
1500 0a1e74d9 Iustin Pop

1501 0a1e74d9 Iustin Pop
  """
1502 0a1e74d9 Iustin Pop
  if cl is None:
1503 0a1e74d9 Iustin Pop
    cl = GetClient()
1504 0a1e74d9 Iustin Pop
1505 293ba2d8 Iustin Pop
  SetGenericOpcodeOpts([op], opts)
1506 293ba2d8 Iustin Pop
1507 0a1e74d9 Iustin Pop
  job_id = SendJob([op], cl)
1508 0a1e74d9 Iustin Pop
1509 53c04d04 Iustin Pop
  op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn)
1510 53c04d04 Iustin Pop
1511 53c04d04 Iustin Pop
  return op_results[0]
1512 0a1e74d9 Iustin Pop
1513 0a1e74d9 Iustin Pop
1514 94428652 Iustin Pop
def SubmitOrSend(op, opts, cl=None, feedback_fn=None):
1515 94428652 Iustin Pop
  """Wrapper around SubmitOpCode or SendJob.
1516 94428652 Iustin Pop

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

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

1525 94428652 Iustin Pop
  """
1526 94428652 Iustin Pop
  if opts and opts.submit_only:
1527 293ba2d8 Iustin Pop
    job = [op]
1528 293ba2d8 Iustin Pop
    SetGenericOpcodeOpts(job, opts)
1529 293ba2d8 Iustin Pop
    job_id = SendJob(job, cl=cl)
1530 e9d741b6 Iustin Pop
    raise JobSubmittedException(job_id)
1531 94428652 Iustin Pop
  else:
1532 293ba2d8 Iustin Pop
    return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
1533 293ba2d8 Iustin Pop
1534 293ba2d8 Iustin Pop
1535 293ba2d8 Iustin Pop
def SetGenericOpcodeOpts(opcode_list, options):
1536 293ba2d8 Iustin Pop
  """Processor for generic options.
1537 293ba2d8 Iustin Pop

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

1541 293ba2d8 Iustin Pop
  @param opcode_list: list of opcodes
1542 293ba2d8 Iustin Pop
  @param options: command line options or None
1543 293ba2d8 Iustin Pop
  @return: None (in-place modification)
1544 293ba2d8 Iustin Pop

1545 293ba2d8 Iustin Pop
  """
1546 293ba2d8 Iustin Pop
  if not options:
1547 293ba2d8 Iustin Pop
    return
1548 293ba2d8 Iustin Pop
  for op in opcode_list:
1549 293ba2d8 Iustin Pop
    op.dry_run = options.dry_run
1550 293ba2d8 Iustin Pop
    op.debug_level = options.debug
1551 94428652 Iustin Pop
1552 94428652 Iustin Pop
1553 af30b2fd Michael Hanselmann
def GetClient():
1554 af30b2fd Michael Hanselmann
  # TODO: Cache object?
1555 b33e986b Iustin Pop
  try:
1556 b33e986b Iustin Pop
    client = luxi.Client()
1557 b33e986b Iustin Pop
  except luxi.NoMasterError:
1558 d9a51679 Michael Hanselmann
    ss = ssconf.SimpleStore()
1559 d9a51679 Michael Hanselmann
1560 d9a51679 Michael Hanselmann
    # Try to read ssconf file
1561 d9a51679 Michael Hanselmann
    try:
1562 d9a51679 Michael Hanselmann
      ss.GetMasterNode()
1563 d9a51679 Michael Hanselmann
    except errors.ConfigurationError:
1564 d9a51679 Michael Hanselmann
      raise errors.OpPrereqError("Cluster not initialized or this machine is"
1565 d9a51679 Michael Hanselmann
                                 " not part of a cluster")
1566 d9a51679 Michael Hanselmann
1567 d9a51679 Michael Hanselmann
    master, myself = ssconf.GetMasterAndMyself(ss=ss)
1568 b33e986b Iustin Pop
    if master != myself:
1569 b33e986b Iustin Pop
      raise errors.OpPrereqError("This is not the master node, please connect"
1570 b33e986b Iustin Pop
                                 " to node '%s' and rerun the command" %
1571 b33e986b Iustin Pop
                                 master)
1572 d9a51679 Michael Hanselmann
    raise
1573 b33e986b Iustin Pop
  return client
1574 af30b2fd Michael Hanselmann
1575 af30b2fd Michael Hanselmann
1576 73702ee7 Iustin Pop
def FormatError(err):
1577 73702ee7 Iustin Pop
  """Return a formatted error message for a given error.
1578 73702ee7 Iustin Pop

1579 73702ee7 Iustin Pop
  This function takes an exception instance and returns a tuple
1580 73702ee7 Iustin Pop
  consisting of two values: first, the recommended exit code, and
1581 73702ee7 Iustin Pop
  second, a string describing the error message (not
1582 73702ee7 Iustin Pop
  newline-terminated).
1583 73702ee7 Iustin Pop

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

1656 334d1483 Iustin Pop
  Arguments:
1657 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
1658 334d1483 Iustin Pop
                for command line handling.
1659 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
1660 334d1483 Iustin Pop
                override command line options; this can be used to pass
1661 334d1483 Iustin Pop
                options from the scripts to generic functions
1662 de47cf8f Guido Trotter
    - aliases: dictionary with command aliases {'alias': 'target, ...}
1663 a8083063 Iustin Pop

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

1716 d77490c5 Iustin Pop
  @param mode: constants.INSTANCE_CREATE or constants.INSTANCE_IMPORT
1717 d77490c5 Iustin Pop
  @param opts: the command line options selected by the user
1718 d77490c5 Iustin Pop
  @type args: list
1719 d77490c5 Iustin Pop
  @param args: should contain only one element, the new instance name
1720 d77490c5 Iustin Pop
  @rtype: int
1721 d77490c5 Iustin Pop
  @return: the desired exit code
1722 d77490c5 Iustin Pop

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

1851 7e49b6ce Michael Hanselmann
  """
1852 7e49b6ce Michael Hanselmann
  def __init__(self, feedback_fn, cluster_name, master_node, online_nodes):
1853 7e49b6ce Michael Hanselmann
    """Initializes this class.
1854 7e49b6ce Michael Hanselmann

1855 7e49b6ce Michael Hanselmann
    @type feedback_fn: callable
1856 7e49b6ce Michael Hanselmann
    @param feedback_fn: Feedback function
1857 7e49b6ce Michael Hanselmann
    @type cluster_name: string
1858 7e49b6ce Michael Hanselmann
    @param cluster_name: Cluster name
1859 7e49b6ce Michael Hanselmann
    @type master_node: string
1860 7e49b6ce Michael Hanselmann
    @param master_node Master node name
1861 7e49b6ce Michael Hanselmann
    @type online_nodes: list
1862 7e49b6ce Michael Hanselmann
    @param online_nodes: List of names of online nodes
1863 7e49b6ce Michael Hanselmann

1864 7e49b6ce Michael Hanselmann
    """
1865 7e49b6ce Michael Hanselmann
    self.feedback_fn = feedback_fn
1866 7e49b6ce Michael Hanselmann
    self.cluster_name = cluster_name
1867 7e49b6ce Michael Hanselmann
    self.master_node = master_node
1868 7e49b6ce Michael Hanselmann
    self.online_nodes = online_nodes
1869 7e49b6ce Michael Hanselmann
1870 7e49b6ce Michael Hanselmann
    self.ssh = ssh.SshRunner(self.cluster_name)
1871 7e49b6ce Michael Hanselmann
1872 7e49b6ce Michael Hanselmann
    self.nonmaster_nodes = [name for name in online_nodes
1873 7e49b6ce Michael Hanselmann
                            if name != master_node]
1874 7e49b6ce Michael Hanselmann
1875 7e49b6ce Michael Hanselmann
    assert self.master_node not in self.nonmaster_nodes
1876 7e49b6ce Michael Hanselmann
1877 7e49b6ce Michael Hanselmann
  def _RunCmd(self, node_name, cmd):
1878 7e49b6ce Michael Hanselmann
    """Runs a command on the local or a remote machine.
1879 7e49b6ce Michael Hanselmann

1880 7e49b6ce Michael Hanselmann
    @type node_name: string
1881 7e49b6ce Michael Hanselmann
    @param node_name: Machine name
1882 7e49b6ce Michael Hanselmann
    @type cmd: list
1883 7e49b6ce Michael Hanselmann
    @param cmd: Command
1884 7e49b6ce Michael Hanselmann

1885 7e49b6ce Michael Hanselmann
    """
1886 7e49b6ce Michael Hanselmann
    if node_name is None or node_name == self.master_node:
1887 7e49b6ce Michael Hanselmann
      # No need to use SSH
1888 7e49b6ce Michael Hanselmann
      result = utils.RunCmd(cmd)
1889 7e49b6ce Michael Hanselmann
    else:
1890 7e49b6ce Michael Hanselmann
      result = self.ssh.Run(node_name, "root", utils.ShellQuoteArgs(cmd))
1891 7e49b6ce Michael Hanselmann
1892 7e49b6ce Michael Hanselmann
    if result.failed:
1893 7e49b6ce Michael Hanselmann
      errmsg = ["Failed to run command %s" % result.cmd]
1894 7e49b6ce Michael Hanselmann
      if node_name:
1895 7e49b6ce Michael Hanselmann
        errmsg.append("on node %s" % node_name)
1896 7e49b6ce Michael Hanselmann
      errmsg.append(": exitcode %s and error %s" %
1897 7e49b6ce Michael Hanselmann
                    (result.exit_code, result.output))
1898 7e49b6ce Michael Hanselmann
      raise errors.OpExecError(" ".join(errmsg))
1899 7e49b6ce Michael Hanselmann
1900 7e49b6ce Michael Hanselmann
  def Call(self, fn, *args):
1901 7e49b6ce Michael Hanselmann
    """Call function while all daemons are stopped.
1902 7e49b6ce Michael Hanselmann

1903 7e49b6ce Michael Hanselmann
    @type fn: callable
1904 7e49b6ce Michael Hanselmann
    @param fn: Function to be called
1905 7e49b6ce Michael Hanselmann

1906 7e49b6ce Michael Hanselmann
    """
1907 7e49b6ce Michael Hanselmann
    # Pause watcher by acquiring an exclusive lock on watcher state file
1908 7e49b6ce Michael Hanselmann
    self.feedback_fn("Blocking watcher")
1909 7e49b6ce Michael Hanselmann
    watcher_block = utils.FileLock.Open(constants.WATCHER_STATEFILE)
1910 7e49b6ce Michael Hanselmann
    try:
1911 7e49b6ce Michael Hanselmann
      # TODO: Currently, this just blocks. There's no timeout.
1912 7e49b6ce Michael Hanselmann
      # TODO: Should it be a shared lock?
1913 7e49b6ce Michael Hanselmann
      watcher_block.Exclusive(blocking=True)
1914 7e49b6ce Michael Hanselmann
1915 7e49b6ce Michael Hanselmann
      # Stop master daemons, so that no new jobs can come in and all running
1916 7e49b6ce Michael Hanselmann
      # ones are finished
1917 7e49b6ce Michael Hanselmann
      self.feedback_fn("Stopping master daemons")
1918 7e49b6ce Michael Hanselmann
      self._RunCmd(None, [constants.DAEMON_UTIL, "stop-master"])
1919 7e49b6ce Michael Hanselmann
      try:
1920 7e49b6ce Michael Hanselmann
        # Stop daemons on all nodes
1921 7e49b6ce Michael Hanselmann
        for node_name in self.online_nodes:
1922 7e49b6ce Michael Hanselmann
          self.feedback_fn("Stopping daemons on %s" % node_name)
1923 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "stop-all"])
1924 7e49b6ce Michael Hanselmann
1925 7e49b6ce Michael Hanselmann
        # All daemons are shut down now
1926 7e49b6ce Michael Hanselmann
        try:
1927 7e49b6ce Michael Hanselmann
          return fn(self, *args)
1928 d512e84b Michael Hanselmann
        except Exception, err:
1929 d512e84b Michael Hanselmann
          _, errmsg = FormatError(err)
1930 7e49b6ce Michael Hanselmann
          logging.exception("Caught exception")
1931 d512e84b Michael Hanselmann
          self.feedback_fn(errmsg)
1932 7e49b6ce Michael Hanselmann
          raise
1933 7e49b6ce Michael Hanselmann
      finally:
1934 7e49b6ce Michael Hanselmann
        # Start cluster again, master node last
1935 7e49b6ce Michael Hanselmann
        for node_name in self.nonmaster_nodes + [self.master_node]:
1936 7e49b6ce Michael Hanselmann
          self.feedback_fn("Starting daemons on %s" % node_name)
1937 7e49b6ce Michael Hanselmann
          self._RunCmd(node_name, [constants.DAEMON_UTIL, "start-all"])
1938 7e49b6ce Michael Hanselmann
    finally:
1939 7e49b6ce Michael Hanselmann
      # Resume watcher
1940 7e49b6ce Michael Hanselmann
      watcher_block.Close()
1941 7e49b6ce Michael Hanselmann
1942 7e49b6ce Michael Hanselmann
1943 7e49b6ce Michael Hanselmann
def RunWhileClusterStopped(feedback_fn, fn, *args):
1944 7e49b6ce Michael Hanselmann
  """Calls a function while all cluster daemons are stopped.
1945 7e49b6ce Michael Hanselmann

1946 7e49b6ce Michael Hanselmann
  @type feedback_fn: callable
1947 7e49b6ce Michael Hanselmann
  @param feedback_fn: Feedback function
1948 7e49b6ce Michael Hanselmann
  @type fn: callable
1949 7e49b6ce Michael Hanselmann
  @param fn: Function to be called when daemons are stopped
1950 7e49b6ce Michael Hanselmann

1951 7e49b6ce Michael Hanselmann
  """
1952 7e49b6ce Michael Hanselmann
  feedback_fn("Gathering cluster information")
1953 7e49b6ce Michael Hanselmann
1954 7e49b6ce Michael Hanselmann
  # This ensures we're running on the master daemon
1955 7e49b6ce Michael Hanselmann
  cl = GetClient()
1956 7e49b6ce Michael Hanselmann
1957 7e49b6ce Michael Hanselmann
  (cluster_name, master_node) = \
1958 7e49b6ce Michael Hanselmann
    cl.QueryConfigValues(["cluster_name", "master_node"])
1959 7e49b6ce Michael Hanselmann
1960 7e49b6ce Michael Hanselmann
  online_nodes = GetOnlineNodes([], cl=cl)
1961 7e49b6ce Michael Hanselmann
1962 7e49b6ce Michael Hanselmann
  # Don't keep a reference to the client. The master daemon will go away.
1963 7e49b6ce Michael Hanselmann
  del cl
1964 7e49b6ce Michael Hanselmann
1965 7e49b6ce Michael Hanselmann
  assert master_node in online_nodes
1966 7e49b6ce Michael Hanselmann
1967 7e49b6ce Michael Hanselmann
  return _RunWhileClusterStoppedHelper(feedback_fn, cluster_name, master_node,
1968 7e49b6ce Michael Hanselmann
                                       online_nodes).Call(fn, *args)
1969 7e49b6ce Michael Hanselmann
1970 7e49b6ce Michael Hanselmann
1971 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
1972 9fbfbb7b Iustin Pop
                  numfields=None, unitfields=None,
1973 9fbfbb7b Iustin Pop
                  units=None):
1974 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
1975 137161c9 Michael Hanselmann

1976 9fbfbb7b Iustin Pop
  @type headers: dict
1977 9fbfbb7b Iustin Pop
  @param headers: dictionary mapping field names to headers for
1978 9fbfbb7b Iustin Pop
      the table
1979 9fbfbb7b Iustin Pop
  @type fields: list
1980 9fbfbb7b Iustin Pop
  @param fields: the field names corresponding to each row in
1981 9fbfbb7b Iustin Pop
      the data field
1982 9fbfbb7b Iustin Pop
  @param separator: the separator to be used; if this is None,
1983 9fbfbb7b Iustin Pop
      the default 'smart' algorithm is used which computes optimal
1984 9fbfbb7b Iustin Pop
      field width, otherwise just the separator is used between
1985 9fbfbb7b Iustin Pop
      each field
1986 9fbfbb7b Iustin Pop
  @type data: list
1987 9fbfbb7b Iustin Pop
  @param data: a list of lists, each sublist being one row to be output
1988 9fbfbb7b Iustin Pop
  @type numfields: list
1989 9fbfbb7b Iustin Pop
  @param numfields: a list with the fields that hold numeric
1990 9fbfbb7b Iustin Pop
      values and thus should be right-aligned
1991 9fbfbb7b Iustin Pop
  @type unitfields: list
1992 9fbfbb7b Iustin Pop
  @param unitfields: a list with the fields that hold numeric
1993 9fbfbb7b Iustin Pop
      values that should be formatted with the units field
1994 9fbfbb7b Iustin Pop
  @type units: string or None
1995 9fbfbb7b Iustin Pop
  @param units: the units we should use for formatting, or None for
1996 9fbfbb7b Iustin Pop
      automatic choice (human-readable for non-separator usage, otherwise
1997 9fbfbb7b Iustin Pop
      megabytes); this is a one-letter string
1998 137161c9 Michael Hanselmann

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

2082 3386e7a9 Iustin Pop
  @type ts: timestamp
2083 3386e7a9 Iustin Pop
  @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
2084 3386e7a9 Iustin Pop

2085 3386e7a9 Iustin Pop
  @rtype: string
2086 5fcc718f Iustin Pop
  @return: a string with the formatted timestamp
2087 3386e7a9 Iustin Pop

2088 3386e7a9 Iustin Pop
  """
2089 e0ec0ff6 Iustin Pop
  if not isinstance (ts, (tuple, list)) or len(ts) != 2:
2090 e0ec0ff6 Iustin Pop
    return '?'
2091 3386e7a9 Iustin Pop
  sec, usec = ts
2092 3386e7a9 Iustin Pop
  return time.strftime("%F %T", time.localtime(sec)) + ".%06d" % usec
2093 2241e2b9 Iustin Pop
2094 2241e2b9 Iustin Pop
2095 2241e2b9 Iustin Pop
def ParseTimespec(value):
2096 2241e2b9 Iustin Pop
  """Parse a time specification.
2097 2241e2b9 Iustin Pop

2098 2241e2b9 Iustin Pop
  The following suffixed will be recognized:
2099 2241e2b9 Iustin Pop

2100 2241e2b9 Iustin Pop
    - s: seconds
2101 2241e2b9 Iustin Pop
    - m: minutes
2102 2241e2b9 Iustin Pop
    - h: hours
2103 2241e2b9 Iustin Pop
    - d: day
2104 2241e2b9 Iustin Pop
    - w: weeks
2105 2241e2b9 Iustin Pop

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

2108 2241e2b9 Iustin Pop
  """
2109 2241e2b9 Iustin Pop
  value = str(value)
2110 2241e2b9 Iustin Pop
  if not value:
2111 2241e2b9 Iustin Pop
    raise errors.OpPrereqError("Empty time specification passed")
2112 2241e2b9 Iustin Pop
  suffix_map = {
2113 2241e2b9 Iustin Pop
    's': 1,
2114 2241e2b9 Iustin Pop
    'm': 60,
2115 2241e2b9 Iustin Pop
    'h': 3600,
2116 2241e2b9 Iustin Pop
    'd': 86400,
2117 2241e2b9 Iustin Pop
    'w': 604800,
2118 2241e2b9 Iustin Pop
    }
2119 2241e2b9 Iustin Pop
  if value[-1] not in suffix_map:
2120 2241e2b9 Iustin Pop
    try:
2121 2241e2b9 Iustin Pop
      value = int(value)
2122 691744c4 Iustin Pop
    except (TypeError, ValueError):
2123 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2124 2241e2b9 Iustin Pop
  else:
2125 2241e2b9 Iustin Pop
    multiplier = suffix_map[value[-1]]
2126 2241e2b9 Iustin Pop
    value = value[:-1]
2127 2241e2b9 Iustin Pop
    if not value: # no data left after stripping the suffix
2128 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification (only"
2129 2241e2b9 Iustin Pop
                                 " suffix passed)")
2130 2241e2b9 Iustin Pop
    try:
2131 2241e2b9 Iustin Pop
      value = int(value) * multiplier
2132 691744c4 Iustin Pop
    except (TypeError, ValueError):
2133 2241e2b9 Iustin Pop
      raise errors.OpPrereqError("Invalid time specification '%s'" % value)
2134 2241e2b9 Iustin Pop
  return value
2135 46fbdd04 Iustin Pop
2136 46fbdd04 Iustin Pop
2137 e9e26bb3 Iustin Pop
def GetOnlineNodes(nodes, cl=None, nowarn=False, secondary_ips=False,
2138 e9e26bb3 Iustin Pop
                   filter_master=False):
2139 4040a784 Iustin Pop
  """Returns the names of online nodes.
2140 4040a784 Iustin Pop

2141 4040a784 Iustin Pop
  This function will also log a warning on stderr with the names of
2142 4040a784 Iustin Pop
  the online nodes.
2143 4040a784 Iustin Pop

2144 4040a784 Iustin Pop
  @param nodes: if not empty, use only this subset of nodes (minus the
2145 4040a784 Iustin Pop
      offline ones)
2146 4040a784 Iustin Pop
  @param cl: if not None, luxi client to use
2147 4040a784 Iustin Pop
  @type nowarn: boolean
2148 4040a784 Iustin Pop
  @param nowarn: by default, this function will output a note with the
2149 4040a784 Iustin Pop
      offline nodes that are skipped; if this parameter is True the
2150 4040a784 Iustin Pop
      note is not displayed
2151 e9e26bb3 Iustin Pop
  @type secondary_ips: boolean
2152 e9e26bb3 Iustin Pop
  @param secondary_ips: if True, return the secondary IPs instead of the
2153 e9e26bb3 Iustin Pop
      names, useful for doing network traffic over the replication interface
2154 e9e26bb3 Iustin Pop
      (if any)
2155 e9e26bb3 Iustin Pop
  @type filter_master: boolean
2156 e9e26bb3 Iustin Pop
  @param filter_master: if True, do not return the master node in the list
2157 e9e26bb3 Iustin Pop
      (useful in coordination with secondary_ips where we cannot check our
2158 e9e26bb3 Iustin Pop
      node name against the list)
2159 4040a784 Iustin Pop

2160 4040a784 Iustin Pop
  """
2161 4040a784 Iustin Pop
  if cl is None:
2162 4040a784 Iustin Pop
    cl = GetClient()
2163 4040a784 Iustin Pop
2164 e9e26bb3 Iustin Pop
  if secondary_ips:
2165 e9e26bb3 Iustin Pop
    name_idx = 2
2166 e9e26bb3 Iustin Pop
  else:
2167 e9e26bb3 Iustin Pop
    name_idx = 0
2168 e9e26bb3 Iustin Pop
2169 e9e26bb3 Iustin Pop
  if filter_master:
2170 e9e26bb3 Iustin Pop
    master_node = cl.QueryConfigValues(["master_node"])[0]
2171 e9e26bb3 Iustin Pop
    filter_fn = lambda x: x != master_node
2172 e9e26bb3 Iustin Pop
  else:
2173 e9e26bb3 Iustin Pop
    filter_fn = lambda _: True
2174 e9e26bb3 Iustin Pop
2175 e9e26bb3 Iustin Pop
  result = cl.QueryNodes(names=nodes, fields=["name", "offline", "sip"],
2176 2e7b8369 Iustin Pop
                         use_locking=False)
2177 4040a784 Iustin Pop
  offline = [row[0] for row in result if row[1]]
2178 4040a784 Iustin Pop
  if offline and not nowarn:
2179 1f864b60 Iustin Pop
    ToStderr("Note: skipping offline node(s): %s" % utils.CommaJoin(offline))
2180 e9e26bb3 Iustin Pop
  return [row[name_idx] for row in result if not row[1] and filter_fn(row[0])]
2181 4040a784 Iustin Pop
2182 4040a784 Iustin Pop
2183 46fbdd04 Iustin Pop
def _ToStream(stream, txt, *args):
2184 46fbdd04 Iustin Pop
  """Write a message to a stream, bypassing the logging system
2185 46fbdd04 Iustin Pop

2186 46fbdd04 Iustin Pop
  @type stream: file object
2187 46fbdd04 Iustin Pop
  @param stream: the file to which we should write
2188 46fbdd04 Iustin Pop
  @type txt: str
2189 46fbdd04 Iustin Pop
  @param txt: the message
2190 46fbdd04 Iustin Pop

2191 46fbdd04 Iustin Pop
  """
2192 46fbdd04 Iustin Pop
  if args:
2193 46fbdd04 Iustin Pop
    args = tuple(args)
2194 46fbdd04 Iustin Pop
    stream.write(txt % args)
2195 46fbdd04 Iustin Pop
  else:
2196 46fbdd04 Iustin Pop
    stream.write(txt)
2197 46fbdd04 Iustin Pop
  stream.write('\n')
2198 46fbdd04 Iustin Pop
  stream.flush()
2199 46fbdd04 Iustin Pop
2200 46fbdd04 Iustin Pop
2201 46fbdd04 Iustin Pop
def ToStdout(txt, *args):
2202 46fbdd04 Iustin Pop
  """Write a message to stdout only, bypassing the logging system
2203 46fbdd04 Iustin Pop

2204 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2205 46fbdd04 Iustin Pop

2206 46fbdd04 Iustin Pop
  @type txt: str
2207 46fbdd04 Iustin Pop
  @param txt: the message
2208 46fbdd04 Iustin Pop

2209 46fbdd04 Iustin Pop
  """
2210 46fbdd04 Iustin Pop
  _ToStream(sys.stdout, txt, *args)
2211 46fbdd04 Iustin Pop
2212 46fbdd04 Iustin Pop
2213 46fbdd04 Iustin Pop
def ToStderr(txt, *args):
2214 46fbdd04 Iustin Pop
  """Write a message to stderr only, bypassing the logging system
2215 46fbdd04 Iustin Pop

2216 46fbdd04 Iustin Pop
  This is just a wrapper over _ToStream.
2217 46fbdd04 Iustin Pop

2218 46fbdd04 Iustin Pop
  @type txt: str
2219 46fbdd04 Iustin Pop
  @param txt: the message
2220 46fbdd04 Iustin Pop

2221 46fbdd04 Iustin Pop
  """
2222 46fbdd04 Iustin Pop
  _ToStream(sys.stderr, txt, *args)
2223 479636a3 Iustin Pop
2224 479636a3 Iustin Pop
2225 479636a3 Iustin Pop
class JobExecutor(object):
2226 479636a3 Iustin Pop
  """Class which manages the submission and execution of multiple jobs.
2227 479636a3 Iustin Pop

2228 479636a3 Iustin Pop
  Note that instances of this class should not be reused between
2229 479636a3 Iustin Pop
  GetResults() calls.
2230 479636a3 Iustin Pop

2231 479636a3 Iustin Pop
  """
2232 919ca415 Iustin Pop
  def __init__(self, cl=None, verbose=True, opts=None, feedback_fn=None):
2233 479636a3 Iustin Pop
    self.queue = []
2234 479636a3 Iustin Pop
    if cl is None:
2235 479636a3 Iustin Pop
      cl = GetClient()
2236 479636a3 Iustin Pop
    self.cl = cl
2237 479636a3 Iustin Pop
    self.verbose = verbose
2238 23b4b983 Iustin Pop
    self.jobs = []
2239 cff5fa7f Iustin Pop
    self.opts = opts
2240 919ca415 Iustin Pop
    self.feedback_fn = feedback_fn
2241 479636a3 Iustin Pop
2242 479636a3 Iustin Pop
  def QueueJob(self, name, *ops):
2243 23b4b983 Iustin Pop
    """Record a job for later submit.
2244 479636a3 Iustin Pop

2245 479636a3 Iustin Pop
    @type name: string
2246 479636a3 Iustin Pop
    @param name: a description of the job, will be used in WaitJobSet
2247 479636a3 Iustin Pop
    """
2248 cff5fa7f Iustin Pop
    SetGenericOpcodeOpts(ops, self.opts)
2249 23b4b983 Iustin Pop
    self.queue.append((name, ops))
2250 23b4b983 Iustin Pop
2251 66ecc479 Guido Trotter
  def SubmitPending(self, each=False):
2252 23b4b983 Iustin Pop
    """Submit all pending jobs.
2253 23b4b983 Iustin Pop

2254 23b4b983 Iustin Pop
    """
2255 66ecc479 Guido Trotter
    if each:
2256 66ecc479 Guido Trotter
      results = []
2257 66ecc479 Guido Trotter
      for row in self.queue:
2258 66ecc479 Guido Trotter
        # SubmitJob will remove the success status, but raise an exception if
2259 66ecc479 Guido Trotter
        # the submission fails, so we'll notice that anyway.
2260 66ecc479 Guido Trotter
        results.append([True, self.cl.SubmitJob(row[1])])
2261 66ecc479 Guido Trotter
    else:
2262 66ecc479 Guido Trotter
      results = self.cl.SubmitManyJobs([row[1] for row in self.queue])
2263 5299e61f Iustin Pop
    for (idx, ((status, data), (name, _))) in enumerate(zip(results,
2264 5299e61f Iustin Pop
                                                            self.queue)):
2265 5299e61f Iustin Pop
      self.jobs.append((idx, status, data, name))
2266 5299e61f Iustin Pop
2267 5299e61f Iustin Pop
  def _ChooseJob(self):
2268 5299e61f Iustin Pop
    """Choose a non-waiting/queued job to poll next.
2269 5299e61f Iustin Pop

2270 5299e61f Iustin Pop
    """
2271 5299e61f Iustin Pop
    assert self.jobs, "_ChooseJob called with empty job list"
2272 5299e61f Iustin Pop
2273 5299e61f Iustin Pop
    result = self.cl.QueryJobs([i[2] for i in self.jobs], ["status"])
2274 5299e61f Iustin Pop
    assert result
2275 5299e61f Iustin Pop
2276 5299e61f Iustin Pop
    for job_data, status in zip(self.jobs, result):
2277 5299e61f Iustin Pop
      if status[0] in (constants.JOB_STATUS_QUEUED,
2278 5299e61f Iustin Pop
                    constants.JOB_STATUS_WAITLOCK,
2279 5299e61f Iustin Pop
                    constants.JOB_STATUS_CANCELING):
2280 5299e61f Iustin Pop
        # job is still waiting
2281 5299e61f Iustin Pop
        continue
2282 5299e61f Iustin Pop
      # good candidate found
2283 5299e61f Iustin Pop
      self.jobs.remove(job_data)
2284 5299e61f Iustin Pop
      return job_data
2285 5299e61f Iustin Pop
2286 5299e61f Iustin Pop
    # no job found
2287 5299e61f Iustin Pop
    return self.jobs.pop(0)
2288 479636a3 Iustin Pop
2289 479636a3 Iustin Pop
  def GetResults(self):
2290 479636a3 Iustin Pop
    """Wait for and return the results of all jobs.
2291 479636a3 Iustin Pop

2292 479636a3 Iustin Pop
    @rtype: list
2293 479636a3 Iustin Pop
    @return: list of tuples (success, job results), in the same order
2294 479636a3 Iustin Pop
        as the submitted jobs; if a job has failed, instead of the result
2295 479636a3 Iustin Pop
        there will be the error message
2296 479636a3 Iustin Pop

2297 479636a3 Iustin Pop
    """
2298 23b4b983 Iustin Pop
    if not self.jobs:
2299 23b4b983 Iustin Pop
      self.SubmitPending()
2300 479636a3 Iustin Pop
    results = []
2301 479636a3 Iustin Pop
    if self.verbose:
2302 5299e61f Iustin Pop
      ok_jobs = [row[2] for row in self.jobs if row[1]]
2303 23b4b983 Iustin Pop
      if ok_jobs:
2304 1f864b60 Iustin Pop
        ToStdout("Submitted jobs %s", utils.CommaJoin(ok_jobs))
2305 5299e61f Iustin Pop
2306 5299e61f Iustin Pop
    # first, remove any non-submitted jobs
2307 cea881e5 Michael Hanselmann
    self.jobs, failures = compat.partition(self.jobs, lambda x: x[1])
2308 5299e61f Iustin Pop
    for idx, _, jid, name in failures:
2309 c63355f2 Iustin Pop
      ToStderr("Failed to submit job for %s: %s", name, jid)
2310 c63355f2 Iustin Pop
      results.append((idx, False, jid))
2311 5299e61f Iustin Pop
2312 5299e61f Iustin Pop
    while self.jobs:
2313 5299e61f Iustin Pop
      (idx, _, jid, name) = self._ChooseJob()
2314 5299e61f Iustin Pop
      ToStdout("Waiting for job %s for %s...", jid, name)
2315 479636a3 Iustin Pop
      try:
2316 919ca415 Iustin Pop
        job_result = PollJob(jid, cl=self.cl, feedback_fn=self.feedback_fn)
2317 479636a3 Iustin Pop
        success = True
2318 479636a3 Iustin Pop
      except (errors.GenericError, luxi.ProtocolError), err:
2319 479636a3 Iustin Pop
        _, job_result = FormatError(err)
2320 479636a3 Iustin Pop
        success = False
2321 479636a3 Iustin Pop
        # the error message will always be shown, verbose or not
2322 479636a3 Iustin Pop
        ToStderr("Job %s for %s has failed: %s", jid, name, job_result)
2323 479636a3 Iustin Pop
2324 5299e61f Iustin Pop
      results.append((idx, success, job_result))
2325 5299e61f Iustin Pop
2326 5299e61f Iustin Pop
    # sort based on the index, then drop it
2327 5299e61f Iustin Pop
    results.sort()
2328 5299e61f Iustin Pop
    results = [i[1:] for i in results]
2329 5299e61f Iustin Pop
2330 479636a3 Iustin Pop
    return results
2331 479636a3 Iustin Pop
2332 479636a3 Iustin Pop
  def WaitOrShow(self, wait):
2333 479636a3 Iustin Pop
    """Wait for job results or only print the job IDs.
2334 479636a3 Iustin Pop

2335 479636a3 Iustin Pop
    @type wait: boolean
2336 479636a3 Iustin Pop
    @param wait: whether to wait or not
2337 479636a3 Iustin Pop

2338 479636a3 Iustin Pop
    """
2339 479636a3 Iustin Pop
    if wait:
2340 479636a3 Iustin Pop
      return self.GetResults()
2341 479636a3 Iustin Pop
    else:
2342 23b4b983 Iustin Pop
      if not self.jobs:
2343 23b4b983 Iustin Pop
        self.SubmitPending()
2344 71834b2a Guido Trotter
      for _, status, result, name in self.jobs:
2345 23b4b983 Iustin Pop
        if status:
2346 23b4b983 Iustin Pop
          ToStdout("%s: %s", result, name)
2347 23b4b983 Iustin Pop
        else:
2348 23b4b983 Iustin Pop
          ToStderr("Failure for %s: %s", name, result)