Statistics
| Branch: | Tag: | Revision:

root / lib / cli.py @ 810c50b7

History | View | Annotate | Download (15.1 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
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 a8083063 Iustin Pop
import copy
29 a8083063 Iustin Pop
30 a8083063 Iustin Pop
from ganeti import utils
31 a8083063 Iustin Pop
from ganeti import logger
32 a8083063 Iustin Pop
from ganeti import errors
33 a8083063 Iustin Pop
from ganeti import mcpu
34 a8083063 Iustin Pop
from ganeti import constants
35 846baef9 Iustin Pop
from ganeti import opcodes
36 a8083063 Iustin Pop
37 a8083063 Iustin Pop
from optparse import (OptionParser, make_option, TitledHelpFormatter,
38 a8083063 Iustin Pop
                      Option, OptionValueError, SUPPRESS_HELP)
39 a8083063 Iustin Pop
40 a8083063 Iustin Pop
__all__ = ["DEBUG_OPT", "NOHDR_OPT", "SEP_OPT", "GenericMain", "SubmitOpCode",
41 47988778 Iustin Pop
           "cli_option", "GenerateTable", "AskUser",
42 a8083063 Iustin Pop
           "ARGS_NONE", "ARGS_FIXED", "ARGS_ATLEAST", "ARGS_ANY", "ARGS_ONE",
43 846baef9 Iustin Pop
           "USEUNITS_OPT", "FIELDS_OPT", "FORCE_OPT",
44 810c50b7 Iustin Pop
           "ListTags", "AddTags", "RemoveTags", "TAG_SRC_OPT",
45 846baef9 Iustin Pop
           ]
46 846baef9 Iustin Pop
47 846baef9 Iustin Pop
48 846baef9 Iustin Pop
def _ExtractTagsObject(opts, args):
49 846baef9 Iustin Pop
  """Extract the tag type object.
50 846baef9 Iustin Pop

51 846baef9 Iustin Pop
  Note that this function will modify its args parameter.
52 846baef9 Iustin Pop

53 846baef9 Iustin Pop
  """
54 846baef9 Iustin Pop
  if not hasattr(opts, "tag_type"):
55 846baef9 Iustin Pop
    raise errors.ProgrammerError("tag_type not passed to _ExtractTagsObject")
56 846baef9 Iustin Pop
  kind = opts.tag_type
57 846baef9 Iustin Pop
  if kind == constants.TAG_CLUSTER:
58 846baef9 Iustin Pop
    retval = kind, kind
59 846baef9 Iustin Pop
  elif kind == constants.TAG_NODE or kind == constants.TAG_INSTANCE:
60 846baef9 Iustin Pop
    if not args:
61 846baef9 Iustin Pop
      raise errors.OpPrereq("no arguments passed to the command")
62 846baef9 Iustin Pop
    name = args.pop(0)
63 846baef9 Iustin Pop
    retval = kind, name
64 846baef9 Iustin Pop
  else:
65 846baef9 Iustin Pop
    raise errors.ProgrammerError("Unhandled tag type '%s'" % kind)
66 846baef9 Iustin Pop
  return retval
67 846baef9 Iustin Pop
68 846baef9 Iustin Pop
69 810c50b7 Iustin Pop
def _ExtendTags(opts, args):
70 810c50b7 Iustin Pop
  """Extend the args if a source file has been given.
71 810c50b7 Iustin Pop

72 810c50b7 Iustin Pop
  This function will extend the tags with the contents of the file
73 810c50b7 Iustin Pop
  passed in the 'tags_source' attribute of the opts parameter. A file
74 810c50b7 Iustin Pop
  named '-' will be replaced by stdin.
75 810c50b7 Iustin Pop

76 810c50b7 Iustin Pop
  """
77 810c50b7 Iustin Pop
  fname = opts.tags_source
78 810c50b7 Iustin Pop
  if fname is None:
79 810c50b7 Iustin Pop
    return
80 810c50b7 Iustin Pop
  if fname == "-":
81 810c50b7 Iustin Pop
    new_fh = sys.stdin
82 810c50b7 Iustin Pop
  else:
83 810c50b7 Iustin Pop
    new_fh = open(fname, "r")
84 810c50b7 Iustin Pop
  new_data = []
85 810c50b7 Iustin Pop
  try:
86 810c50b7 Iustin Pop
    # we don't use the nice 'new_data = [line.strip() for line in fh]'
87 810c50b7 Iustin Pop
    # because of python bug 1633941
88 810c50b7 Iustin Pop
    while True:
89 810c50b7 Iustin Pop
      line = new_fh.readline()
90 810c50b7 Iustin Pop
      if not line:
91 810c50b7 Iustin Pop
        break
92 810c50b7 Iustin Pop
      new_data.append(line.strip())
93 810c50b7 Iustin Pop
  finally:
94 810c50b7 Iustin Pop
    new_fh.close()
95 810c50b7 Iustin Pop
  args.extend(new_data)
96 810c50b7 Iustin Pop
97 810c50b7 Iustin Pop
98 846baef9 Iustin Pop
def ListTags(opts, args):
99 846baef9 Iustin Pop
  """List the tags on a given object.
100 846baef9 Iustin Pop

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

106 846baef9 Iustin Pop
  """
107 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
108 846baef9 Iustin Pop
  op = opcodes.OpGetTags(kind=kind, name=name)
109 846baef9 Iustin Pop
  result = SubmitOpCode(op)
110 846baef9 Iustin Pop
  result = list(result)
111 846baef9 Iustin Pop
  result.sort()
112 846baef9 Iustin Pop
  for tag in result:
113 846baef9 Iustin Pop
    print tag
114 846baef9 Iustin Pop
115 846baef9 Iustin Pop
116 846baef9 Iustin Pop
def AddTags(opts, args):
117 846baef9 Iustin Pop
  """Add tags on a given object.
118 846baef9 Iustin Pop

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

124 846baef9 Iustin Pop
  """
125 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
126 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
127 846baef9 Iustin Pop
  if not args:
128 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be added")
129 846baef9 Iustin Pop
  op = opcodes.OpAddTags(kind=kind, name=name, tags=args)
130 846baef9 Iustin Pop
  SubmitOpCode(op)
131 846baef9 Iustin Pop
132 846baef9 Iustin Pop
133 846baef9 Iustin Pop
def RemoveTags(opts, args):
134 846baef9 Iustin Pop
  """Remove tags from a given object.
135 846baef9 Iustin Pop

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

141 846baef9 Iustin Pop
  """
142 846baef9 Iustin Pop
  kind, name = _ExtractTagsObject(opts, args)
143 810c50b7 Iustin Pop
  _ExtendTags(opts, args)
144 846baef9 Iustin Pop
  if not args:
145 846baef9 Iustin Pop
    raise errors.OpPrereqError("No tags to be removed")
146 846baef9 Iustin Pop
  op = opcodes.OpDelTags(kind=kind, name=name, tags=args)
147 846baef9 Iustin Pop
  SubmitOpCode(op)
148 846baef9 Iustin Pop
149 a8083063 Iustin Pop
150 a8083063 Iustin Pop
DEBUG_OPT = make_option("-d", "--debug", default=False,
151 a8083063 Iustin Pop
                        action="store_true",
152 a8083063 Iustin Pop
                        help="Turn debugging on")
153 a8083063 Iustin Pop
154 a8083063 Iustin Pop
NOHDR_OPT = make_option("--no-headers", default=False,
155 a8083063 Iustin Pop
                        action="store_true", dest="no_headers",
156 a8083063 Iustin Pop
                        help="Don't display column headers")
157 a8083063 Iustin Pop
158 137161c9 Michael Hanselmann
SEP_OPT = make_option("--separator", default=None,
159 a8083063 Iustin Pop
                      action="store", dest="separator",
160 a8083063 Iustin Pop
                      help="Separator between output fields"
161 a8083063 Iustin Pop
                      " (defaults to one space)")
162 a8083063 Iustin Pop
163 a8083063 Iustin Pop
USEUNITS_OPT = make_option("--human-readable", default=False,
164 a8083063 Iustin Pop
                           action="store_true", dest="human_readable",
165 a8083063 Iustin Pop
                           help="Print sizes in human readable format")
166 a8083063 Iustin Pop
167 dcb93971 Michael Hanselmann
FIELDS_OPT = make_option("-o", "--output", dest="output", action="store",
168 dcb93971 Michael Hanselmann
                         type="string", help="Select output fields",
169 dcb93971 Michael Hanselmann
                         metavar="FIELDS")
170 dcb93971 Michael Hanselmann
171 fe7b0351 Michael Hanselmann
FORCE_OPT = make_option("-f", "--force", dest="force", action="store_true",
172 fe7b0351 Michael Hanselmann
                        default=False, help="Force the operation")
173 fe7b0351 Michael Hanselmann
174 a8083063 Iustin Pop
_LOCK_OPT = make_option("--lock-retries", default=None,
175 a8083063 Iustin Pop
                        type="int", help=SUPPRESS_HELP)
176 a8083063 Iustin Pop
177 810c50b7 Iustin Pop
TAG_SRC_OPT = make_option("--from", dest="tags_source",
178 810c50b7 Iustin Pop
                          default=None, help="File with tag names")
179 810c50b7 Iustin Pop
180 a8083063 Iustin Pop
def ARGS_FIXED(val):
181 a8083063 Iustin Pop
  """Macro-like function denoting a fixed number of arguments"""
182 a8083063 Iustin Pop
  return -val
183 a8083063 Iustin Pop
184 a8083063 Iustin Pop
185 a8083063 Iustin Pop
def ARGS_ATLEAST(val):
186 a8083063 Iustin Pop
  """Macro-like function denoting a minimum number of arguments"""
187 a8083063 Iustin Pop
  return val
188 a8083063 Iustin Pop
189 a8083063 Iustin Pop
190 a8083063 Iustin Pop
ARGS_NONE = None
191 a8083063 Iustin Pop
ARGS_ONE = ARGS_FIXED(1)
192 a8083063 Iustin Pop
ARGS_ANY = ARGS_ATLEAST(0)
193 a8083063 Iustin Pop
194 a8083063 Iustin Pop
195 a8083063 Iustin Pop
def check_unit(option, opt, value):
196 a8083063 Iustin Pop
  try:
197 a8083063 Iustin Pop
    return utils.ParseUnit(value)
198 a8083063 Iustin Pop
  except errors.UnitParseError, err:
199 3ecf6786 Iustin Pop
    raise OptionValueError("option %s: %s" % (opt, err))
200 a8083063 Iustin Pop
201 a8083063 Iustin Pop
202 a8083063 Iustin Pop
class CliOption(Option):
203 a8083063 Iustin Pop
  TYPES = Option.TYPES + ("unit",)
204 a8083063 Iustin Pop
  TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)
205 a8083063 Iustin Pop
  TYPE_CHECKER["unit"] = check_unit
206 a8083063 Iustin Pop
207 a8083063 Iustin Pop
208 a8083063 Iustin Pop
# optparse.py sets make_option, so we do it for our own option class, too
209 a8083063 Iustin Pop
cli_option = CliOption
210 a8083063 Iustin Pop
211 a8083063 Iustin Pop
212 a8083063 Iustin Pop
def _ParseArgs(argv, commands):
213 a8083063 Iustin Pop
  """Parses the command line and return the function which must be
214 a8083063 Iustin Pop
  executed together with its arguments
215 a8083063 Iustin Pop

216 a8083063 Iustin Pop
  Arguments:
217 a8083063 Iustin Pop
    argv: the command line
218 a8083063 Iustin Pop

219 a8083063 Iustin Pop
    commands: dictionary with special contents, see the design doc for
220 a8083063 Iustin Pop
    cmdline handling
221 098c0958 Michael Hanselmann

222 a8083063 Iustin Pop
  """
223 a8083063 Iustin Pop
  if len(argv) == 0:
224 a8083063 Iustin Pop
    binary = "<command>"
225 a8083063 Iustin Pop
  else:
226 a8083063 Iustin Pop
    binary = argv[0].split("/")[-1]
227 a8083063 Iustin Pop
228 a8083063 Iustin Pop
  if len(argv) > 1 and argv[1] == "--version":
229 a8083063 Iustin Pop
    print "%s (ganeti) %s" % (binary, constants.RELEASE_VERSION)
230 a8083063 Iustin Pop
    # Quit right away. That way we don't have to care about this special
231 a8083063 Iustin Pop
    # argument. optparse.py does it the same.
232 a8083063 Iustin Pop
    sys.exit(0)
233 a8083063 Iustin Pop
234 a8083063 Iustin Pop
  if len(argv) < 2 or argv[1] not in commands.keys():
235 a8083063 Iustin Pop
    # let's do a nice thing
236 a8083063 Iustin Pop
    sortedcmds = commands.keys()
237 a8083063 Iustin Pop
    sortedcmds.sort()
238 a8083063 Iustin Pop
    print ("Usage: %(bin)s {command} [options...] [argument...]"
239 a8083063 Iustin Pop
           "\n%(bin)s <command> --help to see details, or"
240 a8083063 Iustin Pop
           " man %(bin)s\n" % {"bin": binary})
241 a8083063 Iustin Pop
    # compute the max line length for cmd + usage
242 a8083063 Iustin Pop
    mlen = max([len(" %s %s" % (cmd, commands[cmd][3])) for cmd in commands])
243 a8083063 Iustin Pop
    mlen = min(60, mlen) # should not get here...
244 a8083063 Iustin Pop
    # and format a nice command list
245 a8083063 Iustin Pop
    print "Commands:"
246 a8083063 Iustin Pop
    for cmd in sortedcmds:
247 a8083063 Iustin Pop
      cmdstr = " %s %s" % (cmd, commands[cmd][3])
248 a8083063 Iustin Pop
      help_text = commands[cmd][4]
249 a8083063 Iustin Pop
      help_lines = textwrap.wrap(help_text, 79-3-mlen)
250 a8083063 Iustin Pop
      print "%-*s - %s" % (mlen, cmdstr,
251 a8083063 Iustin Pop
                                          help_lines.pop(0))
252 a8083063 Iustin Pop
      for line in help_lines:
253 a8083063 Iustin Pop
        print "%-*s   %s" % (mlen, "", line)
254 a8083063 Iustin Pop
    print
255 a8083063 Iustin Pop
    return None, None, None
256 a8083063 Iustin Pop
  cmd = argv.pop(1)
257 a8083063 Iustin Pop
  func, nargs, parser_opts, usage, description = commands[cmd]
258 a8083063 Iustin Pop
  parser_opts.append(_LOCK_OPT)
259 a8083063 Iustin Pop
  parser = OptionParser(option_list=parser_opts,
260 a8083063 Iustin Pop
                        description=description,
261 a8083063 Iustin Pop
                        formatter=TitledHelpFormatter(),
262 a8083063 Iustin Pop
                        usage="%%prog %s %s" % (cmd, usage))
263 a8083063 Iustin Pop
  parser.disable_interspersed_args()
264 a8083063 Iustin Pop
  options, args = parser.parse_args()
265 a8083063 Iustin Pop
  if nargs is None:
266 a8083063 Iustin Pop
    if len(args) != 0:
267 a8083063 Iustin Pop
      print >> sys.stderr, ("Error: Command %s expects no arguments" % cmd)
268 a8083063 Iustin Pop
      return None, None, None
269 a8083063 Iustin Pop
  elif nargs < 0 and len(args) != -nargs:
270 a8083063 Iustin Pop
    print >> sys.stderr, ("Error: Command %s expects %d argument(s)" %
271 a8083063 Iustin Pop
                         (cmd, -nargs))
272 a8083063 Iustin Pop
    return None, None, None
273 a8083063 Iustin Pop
  elif nargs >= 0 and len(args) < nargs:
274 a8083063 Iustin Pop
    print >> sys.stderr, ("Error: Command %s expects at least %d argument(s)" %
275 a8083063 Iustin Pop
                         (cmd, nargs))
276 a8083063 Iustin Pop
    return None, None, None
277 a8083063 Iustin Pop
278 a8083063 Iustin Pop
  return func, options, args
279 a8083063 Iustin Pop
280 a8083063 Iustin Pop
281 47988778 Iustin Pop
def AskUser(text, choices=None):
282 47988778 Iustin Pop
  """Ask the user a question.
283 a8083063 Iustin Pop

284 a8083063 Iustin Pop
  Args:
285 47988778 Iustin Pop
    text - the question to ask.
286 a8083063 Iustin Pop

287 47988778 Iustin Pop
    choices - list with elements tuples (input_char, return_value,
288 47988778 Iustin Pop
    description); if not given, it will default to: [('y', True,
289 47988778 Iustin Pop
    'Perform the operation'), ('n', False, 'Do no do the operation')];
290 47988778 Iustin Pop
    note that the '?' char is reserved for help
291 47988778 Iustin Pop

292 47988778 Iustin Pop
  Returns: one of the return values from the choices list; if input is
293 47988778 Iustin Pop
  not possible (i.e. not running with a tty, we return the last entry
294 47988778 Iustin Pop
  from the list
295 a8083063 Iustin Pop

296 a8083063 Iustin Pop
  """
297 47988778 Iustin Pop
  if choices is None:
298 47988778 Iustin Pop
    choices = [('y', True, 'Perform the operation'),
299 47988778 Iustin Pop
               ('n', False, 'Do not perform the operation')]
300 47988778 Iustin Pop
  if not choices or not isinstance(choices, list):
301 47988778 Iustin Pop
    raise errors.ProgrammerError("Invalid choiches argument to AskUser")
302 47988778 Iustin Pop
  for entry in choices:
303 47988778 Iustin Pop
    if not isinstance(entry, tuple) or len(entry) < 3 or entry[0] == '?':
304 47988778 Iustin Pop
      raise errors.ProgrammerError("Invalid choiches element to AskUser")
305 47988778 Iustin Pop
306 47988778 Iustin Pop
  answer = choices[-1][1]
307 47988778 Iustin Pop
  new_text = []
308 47988778 Iustin Pop
  for line in text.splitlines():
309 47988778 Iustin Pop
    new_text.append(textwrap.fill(line, 70, replace_whitespace=False))
310 47988778 Iustin Pop
  text = "\n".join(new_text)
311 a8083063 Iustin Pop
  try:
312 a8083063 Iustin Pop
    f = file("/dev/tty", "r+")
313 a8083063 Iustin Pop
  except IOError:
314 47988778 Iustin Pop
    return answer
315 a8083063 Iustin Pop
  try:
316 47988778 Iustin Pop
    chars = [entry[0] for entry in choices]
317 47988778 Iustin Pop
    chars[-1] = "[%s]" % chars[-1]
318 47988778 Iustin Pop
    chars.append('?')
319 47988778 Iustin Pop
    maps = dict([(entry[0], entry[1]) for entry in choices])
320 47988778 Iustin Pop
    while True:
321 47988778 Iustin Pop
      f.write(text)
322 47988778 Iustin Pop
      f.write('\n')
323 47988778 Iustin Pop
      f.write("/".join(chars))
324 47988778 Iustin Pop
      f.write(": ")
325 47988778 Iustin Pop
      line = f.readline(2).strip().lower()
326 47988778 Iustin Pop
      if line in maps:
327 47988778 Iustin Pop
        answer = maps[line]
328 47988778 Iustin Pop
        break
329 47988778 Iustin Pop
      elif line == '?':
330 47988778 Iustin Pop
        for entry in choices:
331 47988778 Iustin Pop
          f.write(" %s - %s\n" % (entry[0], entry[2]))
332 47988778 Iustin Pop
        f.write("\n")
333 47988778 Iustin Pop
        continue
334 a8083063 Iustin Pop
  finally:
335 a8083063 Iustin Pop
    f.close()
336 a8083063 Iustin Pop
  return answer
337 a8083063 Iustin Pop
338 a8083063 Iustin Pop
339 a8083063 Iustin Pop
def SubmitOpCode(op):
340 a8083063 Iustin Pop
  """Function to submit an opcode.
341 a8083063 Iustin Pop

342 a8083063 Iustin Pop
  This is just a simple wrapper over the construction of the processor
343 a8083063 Iustin Pop
  instance. It should be extended to better handle feedback and
344 a8083063 Iustin Pop
  interaction functions.
345 a8083063 Iustin Pop

346 a8083063 Iustin Pop
  """
347 a8083063 Iustin Pop
  proc = mcpu.Processor()
348 a8083063 Iustin Pop
  return proc.ExecOpCode(op, logger.ToStdout)
349 a8083063 Iustin Pop
350 a8083063 Iustin Pop
351 334d1483 Iustin Pop
def GenericMain(commands, override=None):
352 a8083063 Iustin Pop
  """Generic main function for all the gnt-* commands.
353 a8083063 Iustin Pop

354 334d1483 Iustin Pop
  Arguments:
355 334d1483 Iustin Pop
    - commands: a dictionary with a special structure, see the design doc
356 334d1483 Iustin Pop
                for command line handling.
357 334d1483 Iustin Pop
    - override: if not None, we expect a dictionary with keys that will
358 334d1483 Iustin Pop
                override command line options; this can be used to pass
359 334d1483 Iustin Pop
                options from the scripts to generic functions
360 a8083063 Iustin Pop

361 a8083063 Iustin Pop
  """
362 a8083063 Iustin Pop
  # save the program name and the entire command line for later logging
363 a8083063 Iustin Pop
  if sys.argv:
364 a8083063 Iustin Pop
    binary = os.path.basename(sys.argv[0]) or sys.argv[0]
365 a8083063 Iustin Pop
    if len(sys.argv) >= 2:
366 a8083063 Iustin Pop
      binary += " " + sys.argv[1]
367 a8083063 Iustin Pop
      old_cmdline = " ".join(sys.argv[2:])
368 a8083063 Iustin Pop
    else:
369 a8083063 Iustin Pop
      old_cmdline = ""
370 a8083063 Iustin Pop
  else:
371 a8083063 Iustin Pop
    binary = "<unknown program>"
372 a8083063 Iustin Pop
    old_cmdline = ""
373 a8083063 Iustin Pop
374 a8083063 Iustin Pop
  func, options, args = _ParseArgs(sys.argv, commands)
375 a8083063 Iustin Pop
  if func is None: # parse error
376 a8083063 Iustin Pop
    return 1
377 a8083063 Iustin Pop
378 334d1483 Iustin Pop
  if override is not None:
379 334d1483 Iustin Pop
    for key, val in override.iteritems():
380 334d1483 Iustin Pop
      setattr(options, key, val)
381 334d1483 Iustin Pop
382 a8083063 Iustin Pop
  logger.SetupLogging(debug=options.debug, program=binary)
383 a8083063 Iustin Pop
384 a8083063 Iustin Pop
  try:
385 a8083063 Iustin Pop
    utils.Lock('cmd', max_retries=options.lock_retries, debug=options.debug)
386 a8083063 Iustin Pop
  except errors.LockError, err:
387 a8083063 Iustin Pop
    logger.ToStderr(str(err))
388 a8083063 Iustin Pop
    return 1
389 a8083063 Iustin Pop
390 a8083063 Iustin Pop
  if old_cmdline:
391 a8083063 Iustin Pop
    logger.Info("run with arguments '%s'" % old_cmdline)
392 a8083063 Iustin Pop
  else:
393 a8083063 Iustin Pop
    logger.Info("run with no arguments")
394 a8083063 Iustin Pop
395 a8083063 Iustin Pop
  try:
396 a8083063 Iustin Pop
    try:
397 a8083063 Iustin Pop
      result = func(options, args)
398 a8083063 Iustin Pop
    except errors.ConfigurationError, err:
399 a8083063 Iustin Pop
      logger.Error("Corrupt configuration file: %s" % err)
400 a8083063 Iustin Pop
      logger.ToStderr("Aborting.")
401 a8083063 Iustin Pop
      result = 2
402 a8083063 Iustin Pop
    except errors.HooksAbort, err:
403 a8083063 Iustin Pop
      logger.ToStderr("Failure: hooks execution failed:")
404 a8083063 Iustin Pop
      for node, script, out in err.args[0]:
405 a8083063 Iustin Pop
        if out:
406 a8083063 Iustin Pop
          logger.ToStderr("  node: %s, script: %s, output: %s" %
407 a8083063 Iustin Pop
                          (node, script, out))
408 a8083063 Iustin Pop
        else:
409 a8083063 Iustin Pop
          logger.ToStderr("  node: %s, script: %s (no output)" %
410 a8083063 Iustin Pop
                          (node, script))
411 a8083063 Iustin Pop
      result = 1
412 a8083063 Iustin Pop
    except errors.HooksFailure, err:
413 a8083063 Iustin Pop
      logger.ToStderr("Failure: hooks general failure: %s" % str(err))
414 a8083063 Iustin Pop
      result = 1
415 89e1fc26 Iustin Pop
    except errors.ResolverError, err:
416 89e1fc26 Iustin Pop
      this_host = utils.HostInfo.SysName()
417 89e1fc26 Iustin Pop
      if err.args[0] == this_host:
418 89e1fc26 Iustin Pop
        msg = "Failure: can't resolve my own hostname ('%s')"
419 89e1fc26 Iustin Pop
      else:
420 89e1fc26 Iustin Pop
        msg = "Failure: can't resolve hostname '%s'"
421 89e1fc26 Iustin Pop
      logger.ToStderr(msg % err.args[0])
422 89e1fc26 Iustin Pop
      result = 1
423 a8083063 Iustin Pop
    except errors.OpPrereqError, err:
424 a8083063 Iustin Pop
      logger.ToStderr("Failure: prerequisites not met for this"
425 a8083063 Iustin Pop
                      " operation:\n%s" % str(err))
426 a8083063 Iustin Pop
      result = 1
427 a8083063 Iustin Pop
    except errors.OpExecError, err:
428 a8083063 Iustin Pop
      logger.ToStderr("Failure: command execution error:\n%s" % str(err))
429 a8083063 Iustin Pop
      result = 1
430 a8083063 Iustin Pop
  finally:
431 a8083063 Iustin Pop
    utils.Unlock('cmd')
432 a8083063 Iustin Pop
    utils.LockCleanup()
433 a8083063 Iustin Pop
434 a8083063 Iustin Pop
  return result
435 137161c9 Michael Hanselmann
436 137161c9 Michael Hanselmann
437 16be8703 Iustin Pop
def GenerateTable(headers, fields, separator, data,
438 16be8703 Iustin Pop
                  numfields=None, unitfields=None):
439 137161c9 Michael Hanselmann
  """Prints a table with headers and different fields.
440 137161c9 Michael Hanselmann

441 137161c9 Michael Hanselmann
  Args:
442 137161c9 Michael Hanselmann
    headers: Dict of header titles or None if no headers should be shown
443 137161c9 Michael Hanselmann
    fields: List of fields to show
444 137161c9 Michael Hanselmann
    separator: String used to separate fields or None for spaces
445 137161c9 Michael Hanselmann
    data: Data to be printed
446 137161c9 Michael Hanselmann
    numfields: List of fields to be aligned to right
447 137161c9 Michael Hanselmann
    unitfields: List of fields to be formatted as units
448 137161c9 Michael Hanselmann

449 137161c9 Michael Hanselmann
  """
450 137161c9 Michael Hanselmann
  if numfields is None:
451 137161c9 Michael Hanselmann
    numfields = []
452 137161c9 Michael Hanselmann
  if unitfields is None:
453 137161c9 Michael Hanselmann
    unitfields = []
454 137161c9 Michael Hanselmann
455 137161c9 Michael Hanselmann
  format_fields = []
456 137161c9 Michael Hanselmann
  for field in fields:
457 137161c9 Michael Hanselmann
    if separator is not None:
458 137161c9 Michael Hanselmann
      format_fields.append("%s")
459 137161c9 Michael Hanselmann
    elif field in numfields:
460 137161c9 Michael Hanselmann
      format_fields.append("%*s")
461 137161c9 Michael Hanselmann
    else:
462 137161c9 Michael Hanselmann
      format_fields.append("%-*s")
463 137161c9 Michael Hanselmann
464 137161c9 Michael Hanselmann
  if separator is None:
465 137161c9 Michael Hanselmann
    mlens = [0 for name in fields]
466 137161c9 Michael Hanselmann
    format = ' '.join(format_fields)
467 137161c9 Michael Hanselmann
  else:
468 137161c9 Michael Hanselmann
    format = separator.replace("%", "%%").join(format_fields)
469 137161c9 Michael Hanselmann
470 137161c9 Michael Hanselmann
  for row in data:
471 137161c9 Michael Hanselmann
    for idx, val in enumerate(row):
472 137161c9 Michael Hanselmann
      if fields[idx] in unitfields:
473 137161c9 Michael Hanselmann
        try:
474 137161c9 Michael Hanselmann
          val = int(val)
475 137161c9 Michael Hanselmann
        except ValueError:
476 137161c9 Michael Hanselmann
          pass
477 137161c9 Michael Hanselmann
        else:
478 137161c9 Michael Hanselmann
          val = row[idx] = utils.FormatUnit(val)
479 137161c9 Michael Hanselmann
      if separator is None:
480 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(val))
481 137161c9 Michael Hanselmann
482 16be8703 Iustin Pop
  result = []
483 137161c9 Michael Hanselmann
  if headers:
484 137161c9 Michael Hanselmann
    args = []
485 137161c9 Michael Hanselmann
    for idx, name in enumerate(fields):
486 137161c9 Michael Hanselmann
      hdr = headers[name]
487 137161c9 Michael Hanselmann
      if separator is None:
488 137161c9 Michael Hanselmann
        mlens[idx] = max(mlens[idx], len(hdr))
489 137161c9 Michael Hanselmann
        args.append(mlens[idx])
490 137161c9 Michael Hanselmann
      args.append(hdr)
491 16be8703 Iustin Pop
    result.append(format % tuple(args))
492 137161c9 Michael Hanselmann
493 137161c9 Michael Hanselmann
  for line in data:
494 137161c9 Michael Hanselmann
    args = []
495 137161c9 Michael Hanselmann
    for idx in xrange(len(fields)):
496 137161c9 Michael Hanselmann
      if separator is None:
497 137161c9 Michael Hanselmann
        args.append(mlens[idx])
498 137161c9 Michael Hanselmann
      args.append(line[idx])
499 16be8703 Iustin Pop
    result.append(format % tuple(args))
500 16be8703 Iustin Pop
501 16be8703 Iustin Pop
  return result