Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-node @ 746ea1da

History | View | Annotate | Download (11.9 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 e7c6e02b Michael Hanselmann
# Copyright (C) 2006, 2007, 2008 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
import sys
23 a8083063 Iustin Pop
from optparse import make_option
24 a8083063 Iustin Pop
25 a8083063 Iustin Pop
from ganeti.cli import *
26 a8083063 Iustin Pop
from ganeti import opcodes
27 a8083063 Iustin Pop
from ganeti import logger
28 a8083063 Iustin Pop
from ganeti import utils
29 846baef9 Iustin Pop
from ganeti import constants
30 c450e9b0 Iustin Pop
from ganeti import errors
31 827f753e Guido Trotter
from ganeti import bootstrap
32 a8083063 Iustin Pop
33 a8083063 Iustin Pop
34 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
35 48c4dfa8 Iustin Pop
  "name", "dtotal", "dfree",
36 48c4dfa8 Iustin Pop
  "mtotal", "mnode", "mfree",
37 48c4dfa8 Iustin Pop
  "pinst_cnt", "sinst_cnt",
38 48c4dfa8 Iustin Pop
  ]
39 48c4dfa8 Iustin Pop
40 51144e33 Michael Hanselmann
41 a8083063 Iustin Pop
def AddNode(opts, args):
42 05ccd983 Guido Trotter
  """Add node cli-to-processor bridge.
43 05ccd983 Guido Trotter
44 05ccd983 Guido Trotter
  """
45 05ccd983 Guido Trotter
  dns_data = utils.HostInfo(args[0])
46 05ccd983 Guido Trotter
  node = dns_data.name
47 05ccd983 Guido Trotter
48 05ccd983 Guido Trotter
  if not opts.readd:
49 05ccd983 Guido Trotter
    op = opcodes.OpQueryNodes(output_fields=['name'], names=[node])
50 05ccd983 Guido Trotter
    try:
51 05ccd983 Guido Trotter
      output = SubmitOpCode(op)
52 05ccd983 Guido Trotter
    except (errors.OpPrereqError, errors.OpExecError):
53 05ccd983 Guido Trotter
      pass
54 05ccd983 Guido Trotter
    else:
55 05ccd983 Guido Trotter
      logger.ToStderr("Node %s already in the cluster (as %s)"
56 05ccd983 Guido Trotter
                      " - please use --readd" % (args[0], output[0][0]))
57 05ccd983 Guido Trotter
      return 1
58 05ccd983 Guido Trotter
59 99e8bbde Guido Trotter
  logger.ToStderr("-- WARNING -- \n"
60 99e8bbde Guido Trotter
    "Performing this operation is going to replace the ssh daemon keypair\n"
61 99e8bbde Guido Trotter
    "on the target machine (%s) with the ones of the current one\n"
62 05ccd983 Guido Trotter
    "and grant full intra-cluster ssh root access to/from it\n" % node)
63 05ccd983 Guido Trotter
64 c4b6c29c Michael Hanselmann
  bootstrap.SetupNodeDaemon(node, opts.ssh_key_check)
65 827f753e Guido Trotter
66 e7c6e02b Michael Hanselmann
  op = opcodes.OpAddNode(node_name=args[0], secondary_ip=opts.secondary_ip,
67 e7c6e02b Michael Hanselmann
                         readd=opts.readd)
68 a8083063 Iustin Pop
  SubmitOpCode(op)
69 a8083063 Iustin Pop
70 a8083063 Iustin Pop
71 a8083063 Iustin Pop
def ListNodes(opts, args):
72 a8083063 Iustin Pop
  """List nodes and their properties.
73 a8083063 Iustin Pop
74 a8083063 Iustin Pop
  """
75 a8083063 Iustin Pop
  if opts.output is None:
76 48c4dfa8 Iustin Pop
    selected_fields = _LIST_DEF_FIELDS
77 48c4dfa8 Iustin Pop
  elif opts.output.startswith("+"):
78 48c4dfa8 Iustin Pop
    selected_fields = _LIST_DEF_FIELDS + opts.output[1:].split(",")
79 a8083063 Iustin Pop
  else:
80 a8083063 Iustin Pop
    selected_fields = opts.output.split(",")
81 a8083063 Iustin Pop
82 c54784d9 Michael Hanselmann
  output = GetClient().QueryNodes([], selected_fields)
83 a8083063 Iustin Pop
84 a8083063 Iustin Pop
  if not opts.no_headers:
85 e8a4c138 Iustin Pop
    headers = {
86 e8a4c138 Iustin Pop
      "name": "Node", "pinst_cnt": "Pinst", "sinst_cnt": "Sinst",
87 e8a4c138 Iustin Pop
      "pinst_list": "PriInstances", "sinst_list": "SecInstances",
88 e8a4c138 Iustin Pop
      "pip": "PrimaryIP", "sip": "SecondaryIP",
89 e8a4c138 Iustin Pop
      "dtotal": "DTotal", "dfree": "DFree",
90 e8a4c138 Iustin Pop
      "mtotal": "MTotal", "mnode": "MNode", "mfree": "MFree",
91 e8a4c138 Iustin Pop
      "bootid": "BootID",
92 e8a4c138 Iustin Pop
      "ctotal": "CTotal",
93 130a6a6f Iustin Pop
      "tags": "Tags",
94 e8a4c138 Iustin Pop
      }
95 137161c9 Michael Hanselmann
  else:
96 137161c9 Michael Hanselmann
    headers = None
97 137161c9 Michael Hanselmann
98 137161c9 Michael Hanselmann
  if opts.human_readable:
99 137161c9 Michael Hanselmann
    unitfields = ["dtotal", "dfree", "mtotal", "mnode", "mfree"]
100 137161c9 Michael Hanselmann
  else:
101 137161c9 Michael Hanselmann
    unitfields = None
102 137161c9 Michael Hanselmann
103 ec223efb Iustin Pop
  numfields = ["dtotal", "dfree",
104 ec223efb Iustin Pop
               "mtotal", "mnode", "mfree",
105 e8a4c138 Iustin Pop
               "pinst_cnt", "sinst_cnt",
106 e8a4c138 Iustin Pop
               "ctotal"]
107 ec223efb Iustin Pop
108 130a6a6f Iustin Pop
  list_type_fields = ("pinst_list", "sinst_list", "tags")
109 ec223efb Iustin Pop
  # change raw values to nicer strings
110 ec223efb Iustin Pop
  for row in output:
111 ec223efb Iustin Pop
    for idx, field in enumerate(selected_fields):
112 ec223efb Iustin Pop
      val = row[idx]
113 130a6a6f Iustin Pop
      if field in list_type_fields:
114 ec223efb Iustin Pop
        val = ",".join(val)
115 ec223efb Iustin Pop
      elif val is None:
116 ec223efb Iustin Pop
        val = "?"
117 ec223efb Iustin Pop
      row[idx] = str(val)
118 137161c9 Michael Hanselmann
119 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
120 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
121 16be8703 Iustin Pop
                       numfields=numfields, data=output)
122 16be8703 Iustin Pop
  for line in data:
123 16be8703 Iustin Pop
    logger.ToStdout(line)
124 a8083063 Iustin Pop
125 a8083063 Iustin Pop
  return 0
126 a8083063 Iustin Pop
127 a8083063 Iustin Pop
128 a5bc662a Iustin Pop
def EvacuateNode(opts, args):
129 a5bc662a Iustin Pop
  """Relocate all secondary instance from a node.
130 a5bc662a Iustin Pop
131 a5bc662a Iustin Pop
  """
132 a5bc662a Iustin Pop
  force = opts.force
133 a5bc662a Iustin Pop
  selected_fields = ["name", "sinst_list"]
134 a5bc662a Iustin Pop
  src_node, dst_node = args
135 a5bc662a Iustin Pop
136 a5bc662a Iustin Pop
  op = opcodes.OpQueryNodes(output_fields=selected_fields, names=[src_node])
137 a5bc662a Iustin Pop
  result = SubmitOpCode(op)
138 a5bc662a Iustin Pop
  src_node, sinst = result[0]
139 a5bc662a Iustin Pop
  op = opcodes.OpQueryNodes(output_fields=["name"], names=[dst_node])
140 a5bc662a Iustin Pop
  result = SubmitOpCode(op)
141 a5bc662a Iustin Pop
  dst_node = result[0][0]
142 a5bc662a Iustin Pop
143 a5bc662a Iustin Pop
  if src_node == dst_node:
144 a5bc662a Iustin Pop
    raise errors.OpPrereqError("Evacuate node needs different source and"
145 a5bc662a Iustin Pop
                               " target nodes (node %s given twice)" %
146 a5bc662a Iustin Pop
                               src_node)
147 a5bc662a Iustin Pop
148 a5bc662a Iustin Pop
  if not sinst:
149 a5bc662a Iustin Pop
    logger.ToStderr("No secondary instances on node %s, exiting." % src_node)
150 a5bc662a Iustin Pop
    return constants.EXIT_SUCCESS
151 a5bc662a Iustin Pop
152 a5bc662a Iustin Pop
  sinst = utils.NiceSort(sinst)
153 a5bc662a Iustin Pop
154 a5bc662a Iustin Pop
  retcode = constants.EXIT_SUCCESS
155 a5bc662a Iustin Pop
156 a5bc662a Iustin Pop
  if not force and not AskUser("Relocate instance(s) %s from node\n"
157 a5bc662a Iustin Pop
                               " %s to node\n %s?" %
158 a5bc662a Iustin Pop
                               (",".join("'%s'" % name for name in sinst),
159 a5bc662a Iustin Pop
                               src_node, dst_node)):
160 a5bc662a Iustin Pop
    return constants.EXIT_CONFIRMATION
161 a5bc662a Iustin Pop
162 a5bc662a Iustin Pop
  good_cnt = bad_cnt = 0
163 a5bc662a Iustin Pop
  for iname in sinst:
164 a5bc662a Iustin Pop
    op = opcodes.OpReplaceDisks(instance_name=iname,
165 22d31e49 Michael Hanselmann
                                remote_node=dst_node,
166 22d31e49 Michael Hanselmann
                                mode=constants.REPLACE_DISK_ALL,
167 22d31e49 Michael Hanselmann
                                disks=["sda", "sdb"])
168 a5bc662a Iustin Pop
    try:
169 a5bc662a Iustin Pop
      logger.ToStdout("Replacing disks for instance %s" % iname)
170 a5bc662a Iustin Pop
      SubmitOpCode(op)
171 a5bc662a Iustin Pop
      logger.ToStdout("Instance %s has been relocated" % iname)
172 a5bc662a Iustin Pop
      good_cnt += 1
173 a5bc662a Iustin Pop
    except errors.GenericError, err:
174 a5bc662a Iustin Pop
      nret, msg = FormatError(err)
175 a5bc662a Iustin Pop
      retcode |= nret
176 a5bc662a Iustin Pop
      logger.ToStderr("Error replacing disks for instance %s: %s" %
177 a5bc662a Iustin Pop
                      (iname, msg))
178 a5bc662a Iustin Pop
      bad_cnt += 1
179 a5bc662a Iustin Pop
180 a5bc662a Iustin Pop
  if retcode == constants.EXIT_SUCCESS:
181 a5bc662a Iustin Pop
    logger.ToStdout("All %d instance(s) relocated successfully." % good_cnt)
182 a5bc662a Iustin Pop
  else:
183 a5bc662a Iustin Pop
    logger.ToStdout("There were errors during the relocation:\n"
184 a5bc662a Iustin Pop
                    "%d error(s) out of %d instance(s)." %
185 a5bc662a Iustin Pop
                    (bad_cnt, good_cnt + bad_cnt))
186 a5bc662a Iustin Pop
  return retcode
187 a5bc662a Iustin Pop
188 a5bc662a Iustin Pop
189 c450e9b0 Iustin Pop
def FailoverNode(opts, args):
190 c450e9b0 Iustin Pop
  """Failover all primary instance on a node.
191 c450e9b0 Iustin Pop
192 c450e9b0 Iustin Pop
  """
193 c450e9b0 Iustin Pop
  force = opts.force
194 c450e9b0 Iustin Pop
  selected_fields = ["name", "pinst_list"]
195 c450e9b0 Iustin Pop
196 c450e9b0 Iustin Pop
  op = opcodes.OpQueryNodes(output_fields=selected_fields, names=args)
197 c450e9b0 Iustin Pop
  result = SubmitOpCode(op)
198 c450e9b0 Iustin Pop
  node, pinst = result[0]
199 c450e9b0 Iustin Pop
200 c450e9b0 Iustin Pop
  if not pinst:
201 c450e9b0 Iustin Pop
    logger.ToStderr("No primary instances on node %s, exiting." % node)
202 c450e9b0 Iustin Pop
    return 0
203 c450e9b0 Iustin Pop
204 c450e9b0 Iustin Pop
  pinst = utils.NiceSort(pinst)
205 c450e9b0 Iustin Pop
206 c450e9b0 Iustin Pop
  retcode = 0
207 c450e9b0 Iustin Pop
208 c450e9b0 Iustin Pop
  if not force and not AskUser("Fail over instance(s) %s?" %
209 c450e9b0 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
210 c450e9b0 Iustin Pop
    return 2
211 c450e9b0 Iustin Pop
212 c450e9b0 Iustin Pop
  good_cnt = bad_cnt = 0
213 c450e9b0 Iustin Pop
  for iname in pinst:
214 c450e9b0 Iustin Pop
    op = opcodes.OpFailoverInstance(instance_name=iname,
215 c450e9b0 Iustin Pop
                                    ignore_consistency=opts.ignore_consistency)
216 c450e9b0 Iustin Pop
    try:
217 c450e9b0 Iustin Pop
      logger.ToStdout("Failing over instance %s" % iname)
218 c450e9b0 Iustin Pop
      SubmitOpCode(op)
219 c450e9b0 Iustin Pop
      logger.ToStdout("Instance %s has been failed over" % iname)
220 c450e9b0 Iustin Pop
      good_cnt += 1
221 c450e9b0 Iustin Pop
    except errors.GenericError, err:
222 c450e9b0 Iustin Pop
      nret, msg = FormatError(err)
223 c450e9b0 Iustin Pop
      retcode |= nret
224 c450e9b0 Iustin Pop
      logger.ToStderr("Error failing over instance %s: %s" % (iname, msg))
225 c450e9b0 Iustin Pop
      bad_cnt += 1
226 c450e9b0 Iustin Pop
227 c450e9b0 Iustin Pop
  if retcode == 0:
228 c450e9b0 Iustin Pop
    logger.ToStdout("All %d instance(s) failed over successfully." % good_cnt)
229 c450e9b0 Iustin Pop
  else:
230 c450e9b0 Iustin Pop
    logger.ToStdout("There were errors during the failover:\n"
231 c450e9b0 Iustin Pop
                    "%d error(s) out of %d instance(s)." %
232 c450e9b0 Iustin Pop
                    (bad_cnt, good_cnt + bad_cnt))
233 c450e9b0 Iustin Pop
  return retcode
234 c450e9b0 Iustin Pop
235 c450e9b0 Iustin Pop
236 a8083063 Iustin Pop
def ShowNodeConfig(opts, args):
237 a8083063 Iustin Pop
  """Show node information.
238 a8083063 Iustin Pop
239 a8083063 Iustin Pop
  """
240 4a72cc75 Iustin Pop
  op = opcodes.OpQueryNodes(output_fields=["name", "pip", "sip",
241 4a72cc75 Iustin Pop
                                           "pinst_list", "sinst_list"],
242 246e180a Iustin Pop
                            names=args)
243 a8083063 Iustin Pop
  result = SubmitOpCode(op)
244 a8083063 Iustin Pop
245 a8083063 Iustin Pop
  for name, primary_ip, secondary_ip, pinst, sinst in result:
246 a8083063 Iustin Pop
    logger.ToStdout("Node name: %s" % name)
247 a8083063 Iustin Pop
    logger.ToStdout("  primary ip: %s" % primary_ip)
248 a8083063 Iustin Pop
    logger.ToStdout("  secondary ip: %s" % secondary_ip)
249 a8083063 Iustin Pop
    if pinst:
250 a8083063 Iustin Pop
      logger.ToStdout("  primary for instances:")
251 a8083063 Iustin Pop
      for iname in pinst:
252 a8083063 Iustin Pop
        logger.ToStdout("    - %s" % iname)
253 a8083063 Iustin Pop
    else:
254 a8083063 Iustin Pop
      logger.ToStdout("  primary for no instances")
255 a8083063 Iustin Pop
    if sinst:
256 a8083063 Iustin Pop
      logger.ToStdout("  secondary for instances:")
257 a8083063 Iustin Pop
      for iname in sinst:
258 a8083063 Iustin Pop
        logger.ToStdout("    - %s" % iname)
259 a8083063 Iustin Pop
    else:
260 a8083063 Iustin Pop
      logger.ToStdout("  secondary for no instances")
261 a8083063 Iustin Pop
262 a8083063 Iustin Pop
  return 0
263 a8083063 Iustin Pop
264 a8083063 Iustin Pop
265 a8083063 Iustin Pop
def RemoveNode(opts, args):
266 a8083063 Iustin Pop
  """Remove node cli-to-processor bridge."""
267 a8083063 Iustin Pop
  op = opcodes.OpRemoveNode(node_name=args[0])
268 a8083063 Iustin Pop
  SubmitOpCode(op)
269 a8083063 Iustin Pop
270 a8083063 Iustin Pop
271 dcb93971 Michael Hanselmann
def ListVolumes(opts, args):
272 dcb93971 Michael Hanselmann
  """List logical volumes on node(s).
273 dcb93971 Michael Hanselmann
274 dcb93971 Michael Hanselmann
  """
275 dcb93971 Michael Hanselmann
  if opts.output is None:
276 dcb93971 Michael Hanselmann
    selected_fields = ["node", "phys", "vg",
277 dcb93971 Michael Hanselmann
                       "name", "size", "instance"]
278 dcb93971 Michael Hanselmann
  else:
279 dcb93971 Michael Hanselmann
    selected_fields = opts.output.split(",")
280 dcb93971 Michael Hanselmann
281 dcb93971 Michael Hanselmann
  op = opcodes.OpQueryNodeVolumes(nodes=args, output_fields=selected_fields)
282 dcb93971 Michael Hanselmann
  output = SubmitOpCode(op)
283 dcb93971 Michael Hanselmann
284 dcb93971 Michael Hanselmann
  if not opts.no_headers:
285 137161c9 Michael Hanselmann
    headers = {"node": "Node", "phys": "PhysDev",
286 137161c9 Michael Hanselmann
               "vg": "VG", "name": "Name",
287 137161c9 Michael Hanselmann
               "size": "Size", "instance": "Instance"}
288 137161c9 Michael Hanselmann
  else:
289 137161c9 Michael Hanselmann
    headers = None
290 137161c9 Michael Hanselmann
291 137161c9 Michael Hanselmann
  if opts.human_readable:
292 137161c9 Michael Hanselmann
    unitfields = ["size"]
293 137161c9 Michael Hanselmann
  else:
294 137161c9 Michael Hanselmann
    unitfields = None
295 137161c9 Michael Hanselmann
296 137161c9 Michael Hanselmann
  numfields = ["size"]
297 137161c9 Michael Hanselmann
298 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
299 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
300 16be8703 Iustin Pop
                       numfields=numfields, data=output)
301 16be8703 Iustin Pop
302 16be8703 Iustin Pop
  for line in data:
303 16be8703 Iustin Pop
    logger.ToStdout(line)
304 dcb93971 Michael Hanselmann
305 dcb93971 Michael Hanselmann
  return 0
306 dcb93971 Michael Hanselmann
307 dcb93971 Michael Hanselmann
308 a8083063 Iustin Pop
commands = {
309 a8083063 Iustin Pop
  'add': (AddNode, ARGS_ONE,
310 a8083063 Iustin Pop
          [DEBUG_OPT,
311 a8083063 Iustin Pop
           make_option("-s", "--secondary-ip", dest="secondary_ip",
312 a8083063 Iustin Pop
                       help="Specify the secondary ip for the node",
313 e7c6e02b Michael Hanselmann
                       metavar="ADDRESS", default=None),
314 e7c6e02b Michael Hanselmann
           make_option("--readd", dest="readd",
315 e7c6e02b Michael Hanselmann
                       default=False, action="store_true",
316 e7c6e02b Michael Hanselmann
                       help="Readd old node after replacing it"),
317 c4b6c29c Michael Hanselmann
           make_option("--no-ssh-key-check", dest="ssh_key_check",
318 c4b6c29c Michael Hanselmann
                       default=True, action="store_false",
319 c4b6c29c Michael Hanselmann
                       help="Disable SSH key fingerprint checking"),
320 e7c6e02b Michael Hanselmann
           ],
321 c4b6c29c Michael Hanselmann
          "[-s ip] [--readd] [--no-ssh-key-check] <node_name>",
322 c4b6c29c Michael Hanselmann
          "Add a node to the cluster"),
323 a5bc662a Iustin Pop
  'evacuate': (EvacuateNode, ARGS_FIXED(2),
324 a5bc662a Iustin Pop
               [DEBUG_OPT, FORCE_OPT],
325 9a033156 Iustin Pop
               "[-f] <src> <dst>",
326 a5bc662a Iustin Pop
               "Relocate the secondary instances from the first node"
327 abdf0113 Iustin Pop
               " to the second one (only for instances with drbd disk template"
328 abdf0113 Iustin Pop
               ),
329 c450e9b0 Iustin Pop
  'failover': (FailoverNode, ARGS_ONE,
330 c450e9b0 Iustin Pop
               [DEBUG_OPT, FORCE_OPT,
331 c450e9b0 Iustin Pop
                make_option("--ignore-consistency", dest="ignore_consistency",
332 c450e9b0 Iustin Pop
                            action="store_true", default=False,
333 c450e9b0 Iustin Pop
                            help="Ignore the consistency of the disks on"
334 c450e9b0 Iustin Pop
                            " the secondary"),
335 c450e9b0 Iustin Pop
                ],
336 9a033156 Iustin Pop
               "[-f] <node>",
337 c450e9b0 Iustin Pop
               "Stops the primary instances on a node and start them on their"
338 abdf0113 Iustin Pop
               " secondary node (only for instances with drbd disk template)"),
339 a8083063 Iustin Pop
  'info': (ShowNodeConfig, ARGS_ANY, [DEBUG_OPT],
340 9a033156 Iustin Pop
           "[<node_name>...]", "Show information about the node(s)"),
341 a8083063 Iustin Pop
  'list': (ListNodes, ARGS_NONE,
342 94428652 Iustin Pop
           [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT,
343 94428652 Iustin Pop
            SUBMIT_OPT],
344 9a033156 Iustin Pop
           "", "Lists the nodes in the cluster. The available fields"
345 d8a4b51d Iustin Pop
           " are (see the man page for details): name, pinst_cnt, pinst_list,"
346 d8a4b51d Iustin Pop
           " sinst_cnt, sinst_list, pip, sip, dtotal, dfree, mtotal, mnode,"
347 e8a4c138 Iustin Pop
           " mfree, bootid, cpu_count. The default field list is"
348 48c4dfa8 Iustin Pop
           " (in order): %s." % ", ".join(_LIST_DEF_FIELDS),
349 48c4dfa8 Iustin Pop
           ),
350 a8083063 Iustin Pop
  'remove': (RemoveNode, ARGS_ONE, [DEBUG_OPT],
351 9a033156 Iustin Pop
             "<node_name>", "Removes a node from the cluster"),
352 dcb93971 Michael Hanselmann
  'volumes': (ListVolumes, ARGS_ANY,
353 dcb93971 Michael Hanselmann
              [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
354 9a033156 Iustin Pop
              "[<node_name>...]", "List logical volumes on node(s)"),
355 846baef9 Iustin Pop
  'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
356 9a033156 Iustin Pop
                "<node_name>", "List the tags of the given node"),
357 810c50b7 Iustin Pop
  'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
358 9a033156 Iustin Pop
               "<node_name> tag...", "Add tags to the given node"),
359 810c50b7 Iustin Pop
  'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
360 9a033156 Iustin Pop
                  "<node_name> tag...", "Remove tags from the given node"),
361 a8083063 Iustin Pop
  }
362 a8083063 Iustin Pop
363 a8083063 Iustin Pop
364 a8083063 Iustin Pop
if __name__ == '__main__':
365 846baef9 Iustin Pop
  sys.exit(GenericMain(commands, override={"tag_type": constants.TAG_NODE}))