Revision f0b1bafe

b/lib/cli.py
2382 2382
  """Callable class for formatting fields of a query.
2383 2383

  
2384 2384
  """
2385
  def __init__(self, fn, status_fn):
2385
  def __init__(self, fn, status_fn, verbose):
2386 2386
    """Initializes this class.
2387 2387

  
2388 2388
    @type fn: callable
2389 2389
    @param fn: Formatting function
2390 2390
    @type status_fn: callable
2391 2391
    @param status_fn: Function to report fields' status
2392
    @type verbose: boolean
2393
    @param verbose: whether to use verbose field descriptions or not
2392 2394

  
2393 2395
    """
2394 2396
    self._fn = fn
2395 2397
    self._status_fn = status_fn
2398
    if verbose:
2399
      self._desc_index = 0
2400
    else:
2401
      self._desc_index = 1
2396 2402

  
2397 2403
  def __call__(self, data):
2398 2404
    """Returns a field's string representation.
......
2409 2415
    assert value is None, \
2410 2416
           "Found value %r for abnormal status %s" % (value, status)
2411 2417

  
2412
    if status == constants.RS_UNKNOWN:
2413
      return "(unknown)"
2414

  
2415
    if status == constants.RS_NODATA:
2416
      return "(nodata)"
2417

  
2418
    if status == constants.RS_UNAVAIL:
2419
      return "(unavail)"
2420

  
2421
    if status == constants.RS_OFFLINE:
2422
      return "(offline)"
2418
    if status in constants.RSS_DESCRIPTION:
2419
      return constants.RSS_DESCRIPTION[status][self._desc_index]
2423 2420

  
2424 2421
    raise NotImplementedError("Unknown status %s" % status)
2425 2422

  
2426 2423

  
2427 2424
def FormatQueryResult(result, unit=None, format_override=None, separator=None,
2428
                      header=False):
2425
                      header=False, verbose=False):
2429 2426
  """Formats data in L{objects.QueryResponse}.
2430 2427

  
2431 2428
  @type result: L{objects.QueryResponse}
......
2440 2437
  @param separator: String used to separate fields
2441 2438
  @type header: bool
2442 2439
  @param header: Whether to output header row
2440
  @type verbose: boolean
2441
  @param verbose: whether to use verbose field descriptions or not
2443 2442

  
2444 2443
  """
2445 2444
  if unit is None:
......
2462 2461
    assert fdef.title and fdef.name
2463 2462
    (fn, align_right) = _GetColumnFormatter(fdef, format_override, unit)
2464 2463
    columns.append(TableColumn(fdef.title,
2465
                               _QueryColumnFormatter(fn, _RecordStatus),
2464
                               _QueryColumnFormatter(fn, _RecordStatus,
2465
                                                     verbose),
2466 2466
                               align_right))
2467 2467

  
2468 2468
  table = FormatTable(result.data, columns, header, separator)
......
2511 2511

  
2512 2512

  
2513 2513
def GenericList(resource, fields, names, unit, separator, header, cl=None,
2514
                format_override=None):
2514
                format_override=None, verbose=False):
2515 2515
  """Generic implementation for listing all items of a resource.
2516 2516

  
2517 2517
  @param resource: One of L{constants.QR_OP_LUXI}
......
2530 2530
  @type format_override: dict
2531 2531
  @param format_override: Dictionary for overriding field formatting functions,
2532 2532
    indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
2533
  @type verbose: boolean
2534
  @param verbose: whether to use verbose field descriptions or not
2533 2535

  
2534 2536
  """
2535 2537
  if cl is None:
......
2544 2546

  
2545 2547
  (status, data) = FormatQueryResult(response, unit=unit, separator=separator,
2546 2548
                                     header=header,
2547
                                     format_override=format_override)
2549
                                     format_override=format_override,
2550
                                     verbose=verbose)
2548 2551

  
2549 2552
  for line in data:
2550 2553
    ToStdout(line)
b/lib/client/gnt_debug.py
503 503
  while True:
504 504
    ret = GenericList(constants.QR_LOCK, selected_fields, None, None,
505 505
                      opts.separator, not opts.no_headers,
506
                      format_override=fmtoverride)
506
                      format_override=fmtoverride, verbose=opts.verbose)
507 507

  
508 508
    if ret != constants.EXIT_SUCCESS:
509 509
      return ret
......
575 575
    TestJobqueue, ARGS_NONE, [PRIORITY_OPT],
576 576
    "", "Test a few aspects of the job queue"),
577 577
  "locks": (
578
    ListLocks, ARGS_NONE, [NOHDR_OPT, SEP_OPT, FIELDS_OPT, INTERVAL_OPT],
578
    ListLocks, ARGS_NONE,
579
    [NOHDR_OPT, SEP_OPT, FIELDS_OPT, INTERVAL_OPT, VERBOSE_OPT],
579 580
    "[--interval N]", "Show a list of locks in the master daemon"),
580 581
  }
581 582

  
b/lib/client/gnt_group.py
1 1
#
2 2
#
3 3

  
4
# Copyright (C) 2010 Google Inc.
4
# Copyright (C) 2010, 2011 Google Inc.
5 5
#
6 6
# This program is free software; you can redistribute it and/or modify
7 7
# it under the terms of the GNU General Public License as published by
......
101 101

  
102 102
  return GenericList(constants.QR_GROUP, desired_fields, args, None,
103 103
                     opts.separator, not opts.no_headers,
104
                     format_override=fmtoverride)
104
                     format_override=fmtoverride, verbose=opts.verbose)
105 105

  
106 106

  
107 107
def ListGroupFields(opts, args):
......
189 189
    "<group_name> <node>...", "Assign nodes to a group"),
190 190
  "list": (
191 191
    ListGroups, ARGS_MANY_GROUPS,
192
    [NOHDR_OPT, SEP_OPT, FIELDS_OPT],
192
    [NOHDR_OPT, SEP_OPT, FIELDS_OPT, VERBOSE_OPT],
193 193
    "[<group_name>...]",
194 194
    "Lists the node groups in the cluster. The available fields can be shown"
195 195
    " using the \"list-fields\" command (see the man page for details)."
b/lib/client/gnt_instance.py
257 257

  
258 258
  return GenericList(constants.QR_INSTANCE, selected_fields, args, opts.units,
259 259
                     opts.separator, not opts.no_headers,
260
                     format_override=fmtoverride)
260
                     format_override=fmtoverride, verbose=opts.verbose)
261 261

  
262 262

  
263 263
def ListInstanceFields(opts, args):
......
1398 1398
    "Show information on the specified instance(s)"),
1399 1399
  'list': (
1400 1400
    ListInstances, ARGS_MANY_INSTANCES,
1401
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
1401
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, VERBOSE_OPT],
1402 1402
    "[<instance>...]",
1403 1403
    "Lists the instances and their status. The available fields can be shown"
1404 1404
    " using the \"list-fields\" command (see the man page for details)."
b/lib/client/gnt_node.py
223 223

  
224 224
  return GenericList(constants.QR_NODE, selected_fields, args, opts.units,
225 225
                     opts.separator, not opts.no_headers,
226
                     format_override=fmtoverride)
226
                     format_override=fmtoverride, verbose=opts.verbose)
227 227

  
228 228

  
229 229
def ListNodeFields(opts, args):
......
747 747
    "[<node_name>...]", "Show information about the node(s)"),
748 748
  'list': (
749 749
    ListNodes, ARGS_MANY_NODES,
750
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
750
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, VERBOSE_OPT],
751 751
    "[nodes...]",
752 752
    "Lists the nodes in the cluster. The available fields can be shown using"
753 753
    " the \"list-fields\" command (see the man page for details)."
b/lib/constants.py
1029 1029
  RS_OFFLINE,
1030 1030
  ])
1031 1031

  
1032
#: Dictionary with special field cases and their verbose/terse formatting
1033
RSS_DESCRIPTION = {
1034
  RS_UNKNOWN: ("(unknown)", "??"),
1035
  RS_NODATA:  ("(nodata)",  "?"),
1036
  RS_OFFLINE: ("(offline)", "*"),
1037
  RS_UNAVAIL: ("(unavail)", "-"),
1038
  }
1039

  
1032 1040
# max dynamic devices
1033 1041
MAX_NICS = 8
1034 1042
MAX_DISKS = 16
b/man/ganeti.rst
179 179

  
180 180
All Ganeti daemons re-open the log file(s) when sent a SIGHUP signal.
181 181
**logrotate**(8) can be used to rotate Ganeti's log files.
182

  
183
Common field formatting
184
-----------------------
185

  
186
Multiple ganeti commands use the same framework for tabular listing of
187
resources (e.g. **gnt-instance list**, **gnt-node list**, **gnt-group
188
list**, **gnt-debug locks**, etc.). For these commands, special states
189
are denoted via a special symbol (in terse mode) or a string (in
190
verbose mode):
191

  
192
*, (offline)
193
    The node in question is marked offline, and thus it cannot be
194
    queried for data. This result is persistent until the node is
195
    de-offlined.
196

  
197
?, (nodata)
198
    Ganeti expected to receive an answer from this entity, but the
199
    cluster RPC call failed and/or we didn't receive a valid answer;
200
    usually more information is available in the node daemon log (if
201
    the node is alive) or the master daemon log. This result is
202
    transient, and re-running command might return a different result.
203

  
204
-, (unavail)
205
    The respective field doesn't make sense for this entity;
206
    e.g. querying a down instance for its current memory 'live' usage,
207
    or querying a non-vm_capable node for disk/memory data. This
208
    result is persistent, and until the entity state is changed via
209
    ganeti commands, the result won't change.
210

  
211
??, (unknown)
212
    This field is not known (note that this is different from entity
213
    being unknown). Either you have mis-typed the field name, or you
214
    are using a field that the running Ganeti master daemon doesn't
215
    know. This result is persistent, re-running the command won't
216
    change it.
b/man/gnt-debug.rst
93 93
LOCKS
94 94
~~~~~
95 95

  
96
| **locks** [--no-headers] [--separator=*SEPARATOR*]
96
| **locks** [--no-headers] [--separator=*SEPARATOR*] [-v]
97 97
| [-o *[+]FIELD,...*] [--interval=*SECONDS*]
98 98

  
99 99
Shows a list of locks in the master daemon.
......
103 103
used between the output fields. Both these options are to help
104 104
scripting.
105 105

  
106
The ``-v`` option activates verbose mode, which changes the display of
107
special field states (see **ganeti(7)**).
108

  
106 109
The ``-o`` option takes a comma-separated list of output fields.
107 110
The available fields and their meaning are:
108 111

  
b/man/gnt-group.rst
92 92
LIST
93 93
~~~~
94 94

  
95
| **list** [--no-headers] [--separator=*SEPARATOR*]
95
| **list** [--no-headers] [--separator=*SEPARATOR*] [-v]
96 96
| [-o *[+]FIELD,...*] [group...]
97 97

  
98 98
Lists all existing node groups in the cluster.
......
102 102
used between the output fields. Both these options are to help
103 103
scripting.
104 104

  
105
The ``-v`` option activates verbose mode, which changes the display of
106
special field states (see **ganeti(7)**).
107

  
105 108
The ``-o`` option takes a comma-separated list of output fields.
106 109
If the value of the option starts with the character ``+``, the new
107 110
fields will be added to the default list. This allows to quickly
b/man/gnt-instance.rst
624 624
^^^^
625 625

  
626 626
| **list**
627
| [--no-headers] [--separator=*SEPARATOR*] [--units=*UNITS*]
627
| [--no-headers] [--separator=*SEPARATOR*] [--units=*UNITS*] [-v]
628 628
| [-o *[+]FIELD,...*] [instance...]
629 629

  
630 630
Shows the currently configured instances with memory usage, disk
......
642 642
parsing by scripts. In both cases, the ``--units`` option can be
643 643
used to enforce a given output unit.
644 644

  
645
The ``-v`` option activates verbose mode, which changes the display of
646
special field states (see **ganeti(7)**).
647

  
645 648
The ``-o`` option takes a comma-separated list of output fields.
646 649
The available fields and their meaning are:
647 650

  
648 651

  
649

  
650 652
name
651 653
    the instance name
652 654

  
b/man/gnt-node.rst
149 149

  
150 150
| **list**
151 151
| [--no-headers] [--separator=*SEPARATOR*]
152
| [--units=*UNITS*] [-o *[+]FIELD,...*]
152
| [--units=*UNITS*] [-v] [-o *[+]FIELD,...*]
153 153
| [node...]
154 154

  
155 155
Lists the nodes in the cluster.
......
169 169
Queries of nodes will be done in parallel with any running jobs. This might
170 170
give inconsistent results for the free disk/memory.
171 171

  
172
The ``-v`` option activates verbose mode, which changes the display of
173
special field states (see **ganeti(7)**).
174

  
172 175
The ``-o`` option takes a comma-separated list of output fields.
173 176
The available fields and their meaning are:
174 177

  
175 178

  
176

  
177 179
name
178 180
    the node name
179 181

  
b/test/ganeti.cli_unittest.py
1 1
#!/usr/bin/python
2 2
#
3 3

  
4
# Copyright (C) 2008 Google Inc.
4
# Copyright (C) 2008, 2011 Google Inc.
5 5
#
6 6
# This program is free software; you can redistribute it and/or modify
7 7
# it under the terms of the GNU General Public License as published by
......
396 396
      ])
397 397

  
398 398
    self.assertEqual(cli.FormatQueryResult(response, header=True,
399
                                           separator="|"),
399
                                           separator="|", verbose=True),
400 400
      (cli.QR_UNKNOWN, [
401 401
      "ID|unk|Unavail|NoData|OffLine",
402 402
      "1|(unknown)|N||(offline)",
403 403
      "2|(unknown)|(nodata)|x|(offline)",
404 404
      "3|(unknown)|N|(unavail)|(offline)",
405 405
      ]))
406
    self.assertEqual(cli.FormatQueryResult(response, header=True,
407
                                           separator="|", verbose=False),
408
      (cli.QR_UNKNOWN, [
409
      "ID|unk|Unavail|NoData|OffLine",
410
      "1|??|N||*",
411
      "2|??|?|x|*",
412
      "3|??|N|-|*",
413
      ]))
406 414

  
407 415
  def testNoData(self):
408 416
    fields = [
......
452 460
      ])
453 461

  
454 462
    self.assertEqual(cli.FormatQueryResult(response, header=False,
455
                                           separator="|"),
463
                                           separator="|", verbose=True),
456 464
      (cli.QR_INCOMPLETE, [
457 465
      "1|N||(offline)",
458 466
      "2|(nodata)|x|abc",
459 467
      "3|N|(unavail)|(offline)",
460 468
      ]))
469
    self.assertEqual(cli.FormatQueryResult(response, header=False,
470
                                           separator="|", verbose=False),
471
      (cli.QR_INCOMPLETE, [
472
      "1|N||*",
473
      "2|?|x|abc",
474
      "3|N|-|*",
475
      ]))
461 476

  
462 477
  def testInvalidFieldType(self):
463 478
    fields = [

Also available in: Unified diff