Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ 4d32c211

History | View | Annotate | Download (24.1 kB)

1 37494fa4 Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 783a6c0b Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010 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 7260cfbe Iustin Pop
"""Node related commands"""
22 a8083063 Iustin Pop
23 2d54e29c Iustin Pop
# pylint: disable-msg=W0401,W0613,W0614,C0103
24 2f79bd34 Iustin Pop
# W0401: Wildcard import ganeti.cli
25 2d54e29c Iustin Pop
# W0613: Unused argument, since all functions follow the same API
26 2f79bd34 Iustin Pop
# W0614: Unused import %s from wildcard import (since we need cli)
27 7260cfbe Iustin Pop
# C0103: Invalid name gnt-node
28 2f79bd34 Iustin Pop
29 a8083063 Iustin Pop
from ganeti.cli import *
30 3ef51126 René Nussbaumer
from ganeti import bootstrap
31 a8083063 Iustin Pop
from ganeti import opcodes
32 a8083063 Iustin Pop
from ganeti import utils
33 846baef9 Iustin Pop
from ganeti import constants
34 6396164f Guido Trotter
from ganeti import compat
35 c450e9b0 Iustin Pop
from ganeti import errors
36 a744b676 Manuel Franceschini
from ganeti import netutils
37 a8083063 Iustin Pop
38 a8083063 Iustin Pop
39 ebf366ee Iustin Pop
#: default list of field for L{ListNodes}
40 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
41 48c4dfa8 Iustin Pop
  "name", "dtotal", "dfree",
42 48c4dfa8 Iustin Pop
  "mtotal", "mnode", "mfree",
43 48c4dfa8 Iustin Pop
  "pinst_cnt", "sinst_cnt",
44 48c4dfa8 Iustin Pop
  ]
45 48c4dfa8 Iustin Pop
46 620a85fd Iustin Pop
47 a4ebd726 Michael Hanselmann
#: Default field list for L{ListVolumes}
48 a4ebd726 Michael Hanselmann
_LIST_VOL_DEF_FIELDS = ["node", "phys", "vg", "name", "size", "instance"]
49 a4ebd726 Michael Hanselmann
50 a4ebd726 Michael Hanselmann
51 620a85fd Iustin Pop
#: default list of field for L{ListStorage}
52 620a85fd Iustin Pop
_LIST_STOR_DEF_FIELDS = [
53 620a85fd Iustin Pop
  constants.SF_NODE,
54 620a85fd Iustin Pop
  constants.SF_TYPE,
55 620a85fd Iustin Pop
  constants.SF_NAME,
56 620a85fd Iustin Pop
  constants.SF_SIZE,
57 620a85fd Iustin Pop
  constants.SF_USED,
58 620a85fd Iustin Pop
  constants.SF_FREE,
59 620a85fd Iustin Pop
  constants.SF_ALLOCATABLE,
60 620a85fd Iustin Pop
  ]
61 620a85fd Iustin Pop
62 620a85fd Iustin Pop
63 cc3bcec8 Guido Trotter
#: headers (and full field list for L{ListNodes}
64 cc3bcec8 Guido Trotter
_LIST_HEADERS = {
65 cc3bcec8 Guido Trotter
  "name": "Node", "pinst_cnt": "Pinst", "sinst_cnt": "Sinst",
66 cc3bcec8 Guido Trotter
  "pinst_list": "PriInstances", "sinst_list": "SecInstances",
67 cc3bcec8 Guido Trotter
  "pip": "PrimaryIP", "sip": "SecondaryIP",
68 cc3bcec8 Guido Trotter
  "dtotal": "DTotal", "dfree": "DFree",
69 cc3bcec8 Guido Trotter
  "mtotal": "MTotal", "mnode": "MNode", "mfree": "MFree",
70 cc3bcec8 Guido Trotter
  "bootid": "BootID",
71 0105bad3 Iustin Pop
  "ctotal": "CTotal", "cnodes": "CNodes", "csockets": "CSockets",
72 cc3bcec8 Guido Trotter
  "tags": "Tags",
73 cc3bcec8 Guido Trotter
  "serial_no": "SerialNo",
74 cc3bcec8 Guido Trotter
  "master_candidate": "MasterC",
75 cc3bcec8 Guido Trotter
  "master": "IsMaster",
76 0b2454b9 Iustin Pop
  "offline": "Offline", "drained": "Drained",
77 c120ff34 Iustin Pop
  "role": "Role",
78 c190e817 Iustin Pop
  "ctime": "CTime", "mtime": "MTime", "uuid": "UUID",
79 c190e817 Iustin Pop
  "master_capable": "MasterCapable", "vm_capable": "VMCapable",
80 cc3bcec8 Guido Trotter
  }
81 cc3bcec8 Guido Trotter
82 620a85fd Iustin Pop
83 620a85fd Iustin Pop
#: headers (and full field list for L{ListStorage}
84 620a85fd Iustin Pop
_LIST_STOR_HEADERS = {
85 620a85fd Iustin Pop
  constants.SF_NODE: "Node",
86 620a85fd Iustin Pop
  constants.SF_TYPE: "Type",
87 620a85fd Iustin Pop
  constants.SF_NAME: "Name",
88 620a85fd Iustin Pop
  constants.SF_SIZE: "Size",
89 620a85fd Iustin Pop
  constants.SF_USED: "Used",
90 620a85fd Iustin Pop
  constants.SF_FREE: "Free",
91 620a85fd Iustin Pop
  constants.SF_ALLOCATABLE: "Allocatable",
92 620a85fd Iustin Pop
  }
93 620a85fd Iustin Pop
94 620a85fd Iustin Pop
95 0e89fc2d Michael Hanselmann
#: User-facing storage unit types
96 0e89fc2d Michael Hanselmann
_USER_STORAGE_TYPE = {
97 0e89fc2d Michael Hanselmann
  constants.ST_FILE: "file",
98 0e89fc2d Michael Hanselmann
  constants.ST_LVM_PV: "lvm-pv",
99 0e89fc2d Michael Hanselmann
  constants.ST_LVM_VG: "lvm-vg",
100 0e89fc2d Michael Hanselmann
  }
101 0e89fc2d Michael Hanselmann
102 a8005e17 Michael Hanselmann
_STORAGE_TYPE_OPT = \
103 aeaefce8 Iustin Pop
  cli_option("-t", "--storage-type",
104 a8005e17 Michael Hanselmann
             dest="user_storage_type",
105 a8005e17 Michael Hanselmann
             choices=_USER_STORAGE_TYPE.keys(),
106 a8005e17 Michael Hanselmann
             default=None,
107 a8005e17 Michael Hanselmann
             metavar="STORAGE_TYPE",
108 ab3e6da8 Iustin Pop
             help=("Storage type (%s)" %
109 ab3e6da8 Iustin Pop
                   utils.CommaJoin(_USER_STORAGE_TYPE.keys())))
110 a8005e17 Michael Hanselmann
111 a8005e17 Michael Hanselmann
_REPAIRABLE_STORAGE_TYPES = \
112 a8005e17 Michael Hanselmann
  [st for st, so in constants.VALID_STORAGE_OPERATIONS.iteritems()
113 a8005e17 Michael Hanselmann
   if constants.SO_FIX_CONSISTENCY in so]
114 a8005e17 Michael Hanselmann
115 a8005e17 Michael Hanselmann
_MODIFIABLE_STORAGE_TYPES = constants.MODIFIABLE_STORAGE_FIELDS.keys()
116 a8005e17 Michael Hanselmann
117 51144e33 Michael Hanselmann
118 2e6469a1 René Nussbaumer
NONODE_SETUP_OPT = cli_option("--no-node-setup", default=True,
119 2e6469a1 René Nussbaumer
                              action="store_false", dest="node_setup",
120 2e6469a1 René Nussbaumer
                              help=("Do not make initial SSH setup on remote"
121 2e6469a1 René Nussbaumer
                                    " node (needs to be done manually)"))
122 2e6469a1 René Nussbaumer
123 2e6469a1 René Nussbaumer
124 86f5eae3 Michael Hanselmann
def ConvertStorageType(user_storage_type):
125 86f5eae3 Michael Hanselmann
  """Converts a user storage type to its internal name.
126 86f5eae3 Michael Hanselmann

127 86f5eae3 Michael Hanselmann
  """
128 86f5eae3 Michael Hanselmann
  try:
129 86f5eae3 Michael Hanselmann
    return _USER_STORAGE_TYPE[user_storage_type]
130 86f5eae3 Michael Hanselmann
  except KeyError:
131 debac808 Iustin Pop
    raise errors.OpPrereqError("Unknown storage type: %s" % user_storage_type,
132 debac808 Iustin Pop
                               errors.ECODE_INVAL)
133 86f5eae3 Michael Hanselmann
134 86f5eae3 Michael Hanselmann
135 2e6469a1 René Nussbaumer
def _RunSetupSSH(options, nodes):
136 2e6469a1 René Nussbaumer
  """Wrapper around utils.RunCmd to call setup-ssh
137 2e6469a1 René Nussbaumer

138 2e6469a1 René Nussbaumer
  @param options: The command line options
139 2e6469a1 René Nussbaumer
  @param nodes: The nodes to setup
140 2e6469a1 René Nussbaumer

141 2e6469a1 René Nussbaumer
  """
142 2e6469a1 René Nussbaumer
  cmd = [constants.SETUP_SSH]
143 2e6469a1 René Nussbaumer
144 2e6469a1 René Nussbaumer
  # Pass --debug|--verbose to the external script if set on our invocation
145 2e6469a1 René Nussbaumer
  # --debug overrides --verbose
146 2e6469a1 René Nussbaumer
  if options.debug:
147 2e6469a1 René Nussbaumer
    cmd.append("--debug")
148 2e6469a1 René Nussbaumer
  elif options.verbose:
149 2e6469a1 René Nussbaumer
    cmd.append("--verbose")
150 e81edf72 Manuel Franceschini
  if not options.ssh_key_check:
151 3ef51126 René Nussbaumer
    cmd.append("--no-ssh-key-check")
152 2e6469a1 René Nussbaumer
153 2e6469a1 René Nussbaumer
  cmd.extend(nodes)
154 2e6469a1 René Nussbaumer
155 2e6469a1 René Nussbaumer
  result = utils.RunCmd(cmd, interactive=True)
156 2e6469a1 René Nussbaumer
157 2e6469a1 René Nussbaumer
  if result.failed:
158 2e6469a1 René Nussbaumer
    errmsg = ("Command '%s' failed with exit code %s; output %r" %
159 2e6469a1 René Nussbaumer
              (result.cmd, result.exit_code, result.output))
160 2e6469a1 René Nussbaumer
    raise errors.OpExecError(errmsg)
161 2e6469a1 René Nussbaumer
162 2e6469a1 René Nussbaumer
163 4331f6cd Michael Hanselmann
@UsesRPC
164 a8083063 Iustin Pop
def AddNode(opts, args):
165 ebf366ee Iustin Pop
  """Add a node to the cluster.
166 ebf366ee Iustin Pop

167 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
168 ebf366ee Iustin Pop
  @type args: list
169 ebf366ee Iustin Pop
  @param args: should contain only one element, the new node name
170 ebf366ee Iustin Pop
  @rtype: int
171 ebf366ee Iustin Pop
  @return: the desired exit code
172 05ccd983 Guido Trotter

173 05ccd983 Guido Trotter
  """
174 87622829 Iustin Pop
  cl = GetClient()
175 b705c7a6 Manuel Franceschini
  node = netutils.GetHostname(name=args[0]).name
176 82e12743 Iustin Pop
  readd = opts.readd
177 82e12743 Iustin Pop
178 82e12743 Iustin Pop
  try:
179 82e12743 Iustin Pop
    output = cl.QueryNodes(names=[node], fields=['name', 'sip'],
180 77921a95 Iustin Pop
                           use_locking=False)
181 82e12743 Iustin Pop
    node_exists, sip = output[0]
182 82e12743 Iustin Pop
  except (errors.OpPrereqError, errors.OpExecError):
183 82e12743 Iustin Pop
    node_exists = ""
184 82e12743 Iustin Pop
    sip = None
185 82e12743 Iustin Pop
186 82e12743 Iustin Pop
  if readd:
187 82e12743 Iustin Pop
    if not node_exists:
188 82e12743 Iustin Pop
      ToStderr("Node %s not in the cluster"
189 82e12743 Iustin Pop
               " - please retry without '--readd'", node)
190 82e12743 Iustin Pop
      return 1
191 82e12743 Iustin Pop
  else:
192 82e12743 Iustin Pop
    if node_exists:
193 3a24c527 Iustin Pop
      ToStderr("Node %s already in the cluster (as %s)"
194 82e12743 Iustin Pop
               " - please retry with '--readd'", node, node_exists)
195 05ccd983 Guido Trotter
      return 1
196 82e12743 Iustin Pop
    sip = opts.secondary_ip
197 05ccd983 Guido Trotter
198 87622829 Iustin Pop
  # read the cluster name from the master
199 87622829 Iustin Pop
  output = cl.QueryConfigValues(['cluster_name'])
200 3ef51126 René Nussbaumer
  cluster_name = output[0]
201 87622829 Iustin Pop
202 3ef51126 René Nussbaumer
  if not readd and opts.node_setup:
203 82e12743 Iustin Pop
    ToStderr("-- WARNING -- \n"
204 82e12743 Iustin Pop
             "Performing this operation is going to replace the ssh daemon"
205 82e12743 Iustin Pop
             " keypair\n"
206 82e12743 Iustin Pop
             "on the target machine (%s) with the ones of the"
207 82e12743 Iustin Pop
             " current one\n"
208 82e12743 Iustin Pop
             "and grant full intra-cluster ssh root access to/from it\n", node)
209 05ccd983 Guido Trotter
210 2e6469a1 René Nussbaumer
  if opts.node_setup:
211 2e6469a1 René Nussbaumer
    _RunSetupSSH(opts, [node])
212 827f753e Guido Trotter
213 3ef51126 René Nussbaumer
  bootstrap.SetupNodeDaemon(cluster_name, node, opts.ssh_key_check)
214 3ef51126 René Nussbaumer
215 82e12743 Iustin Pop
  op = opcodes.OpAddNode(node_name=args[0], secondary_ip=sip,
216 fd3d37b6 Iustin Pop
                         readd=opts.readd, group=opts.nodegroup,
217 fd3d37b6 Iustin Pop
                         vm_capable=opts.vm_capable,
218 fd3d37b6 Iustin Pop
                         master_capable=opts.master_capable)
219 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
220 a8083063 Iustin Pop
221 a8083063 Iustin Pop
222 a8083063 Iustin Pop
def ListNodes(opts, args):
223 a8083063 Iustin Pop
  """List nodes and their properties.
224 a8083063 Iustin Pop

225 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
226 ebf366ee Iustin Pop
  @type args: list
227 ebf366ee Iustin Pop
  @param args: should be an empty list
228 ebf366ee Iustin Pop
  @rtype: int
229 ebf366ee Iustin Pop
  @return: the desired exit code
230 ebf366ee Iustin Pop

231 a8083063 Iustin Pop
  """
232 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
233 a8083063 Iustin Pop
234 f1de3563 Iustin Pop
  output = GetClient().QueryNodes(args, selected_fields, opts.do_locking)
235 a8083063 Iustin Pop
236 a8083063 Iustin Pop
  if not opts.no_headers:
237 cc3bcec8 Guido Trotter
    headers = _LIST_HEADERS
238 137161c9 Michael Hanselmann
  else:
239 137161c9 Michael Hanselmann
    headers = None
240 137161c9 Michael Hanselmann
241 9fbfbb7b Iustin Pop
  unitfields = ["dtotal", "dfree", "mtotal", "mnode", "mfree"]
242 137161c9 Michael Hanselmann
243 ec223efb Iustin Pop
  numfields = ["dtotal", "dfree",
244 ec223efb Iustin Pop
               "mtotal", "mnode", "mfree",
245 e8a4c138 Iustin Pop
               "pinst_cnt", "sinst_cnt",
246 38d7239a Iustin Pop
               "ctotal", "serial_no"]
247 ec223efb Iustin Pop
248 130a6a6f Iustin Pop
  list_type_fields = ("pinst_list", "sinst_list", "tags")
249 ec223efb Iustin Pop
  # change raw values to nicer strings
250 ec223efb Iustin Pop
  for row in output:
251 ec223efb Iustin Pop
    for idx, field in enumerate(selected_fields):
252 ec223efb Iustin Pop
      val = row[idx]
253 130a6a6f Iustin Pop
      if field in list_type_fields:
254 ec223efb Iustin Pop
        val = ",".join(val)
255 c190e817 Iustin Pop
      elif field in ('master', 'master_candidate', 'offline', 'drained',
256 c190e817 Iustin Pop
                     'master_capable', 'vm_capable'):
257 0e67cdbe Iustin Pop
        if val:
258 0e67cdbe Iustin Pop
          val = 'Y'
259 0e67cdbe Iustin Pop
        else:
260 0e67cdbe Iustin Pop
          val = 'N'
261 90f72445 Iustin Pop
      elif field == "ctime" or field == "mtime":
262 90f72445 Iustin Pop
        val = utils.FormatTime(val)
263 ec223efb Iustin Pop
      elif val is None:
264 ec223efb Iustin Pop
        val = "?"
265 cc5b94db Guido Trotter
      elif opts.roman_integers and isinstance(val, int):
266 6396164f Guido Trotter
        val = compat.TryToRoman(val)
267 ec223efb Iustin Pop
      row[idx] = str(val)
268 137161c9 Michael Hanselmann
269 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
270 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
271 9fbfbb7b Iustin Pop
                       numfields=numfields, data=output, units=opts.units)
272 16be8703 Iustin Pop
  for line in data:
273 3a24c527 Iustin Pop
    ToStdout(line)
274 a8083063 Iustin Pop
275 a8083063 Iustin Pop
  return 0
276 a8083063 Iustin Pop
277 a8083063 Iustin Pop
278 a5bc662a Iustin Pop
def EvacuateNode(opts, args):
279 a5bc662a Iustin Pop
  """Relocate all secondary instance from a node.
280 a5bc662a Iustin Pop

281 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
282 ebf366ee Iustin Pop
  @type args: list
283 ebf366ee Iustin Pop
  @param args: should be an empty list
284 ebf366ee Iustin Pop
  @rtype: int
285 ebf366ee Iustin Pop
  @return: the desired exit code
286 ebf366ee Iustin Pop

287 a5bc662a Iustin Pop
  """
288 479636a3 Iustin Pop
  cl = GetClient()
289 a5bc662a Iustin Pop
  force = opts.force
290 c4ed32cb Iustin Pop
291 c4ed32cb Iustin Pop
  dst_node = opts.dst_node
292 c4ed32cb Iustin Pop
  iallocator = opts.iallocator
293 c4ed32cb Iustin Pop
294 f8c9fa5c Iustin Pop
  op = opcodes.OpNodeEvacuationStrategy(nodes=args,
295 f8c9fa5c Iustin Pop
                                        iallocator=iallocator,
296 f8c9fa5c Iustin Pop
                                        remote_node=dst_node)
297 f8c9fa5c Iustin Pop
298 f8c9fa5c Iustin Pop
  result = SubmitOpCode(op, cl=cl, opts=opts)
299 f8c9fa5c Iustin Pop
  if not result:
300 f8c9fa5c Iustin Pop
    # no instances to migrate
301 f8c9fa5c Iustin Pop
    ToStderr("No secondary instances on node(s) %s, exiting.",
302 f8c9fa5c Iustin Pop
             utils.CommaJoin(args))
303 a5bc662a Iustin Pop
    return constants.EXIT_SUCCESS
304 a5bc662a Iustin Pop
305 f8c9fa5c Iustin Pop
  if not force and not AskUser("Relocate instance(s) %s from node(s) %s?" %
306 f8c9fa5c Iustin Pop
                               (",".join("'%s'" % name[0] for name in result),
307 f8c9fa5c Iustin Pop
                               utils.CommaJoin(args))):
308 a5bc662a Iustin Pop
    return constants.EXIT_CONFIRMATION
309 a5bc662a Iustin Pop
310 f8c9fa5c Iustin Pop
  jex = JobExecutor(cl=cl, opts=opts)
311 f8c9fa5c Iustin Pop
  for row in result:
312 f8c9fa5c Iustin Pop
    iname = row[0]
313 f8c9fa5c Iustin Pop
    node = row[1]
314 f8c9fa5c Iustin Pop
    ToStdout("Will relocate instance %s to node %s", iname, node)
315 f8c9fa5c Iustin Pop
    op = opcodes.OpReplaceDisks(instance_name=iname,
316 f8c9fa5c Iustin Pop
                                remote_node=node, disks=[],
317 f8c9fa5c Iustin Pop
                                mode=constants.REPLACE_DISK_CHG,
318 f8c9fa5c Iustin Pop
                                early_release=opts.early_release)
319 f8c9fa5c Iustin Pop
    jex.QueueJob(iname, op)
320 f8c9fa5c Iustin Pop
  results = jex.GetResults()
321 f8c9fa5c Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
322 f8c9fa5c Iustin Pop
  if bad_cnt == 0:
323 f8c9fa5c Iustin Pop
    ToStdout("All %d instance(s) failed over successfully.", len(results))
324 f8c9fa5c Iustin Pop
    rcode = constants.EXIT_SUCCESS
325 f8c9fa5c Iustin Pop
  else:
326 f8c9fa5c Iustin Pop
    ToStdout("There were errors during the failover:\n"
327 f8c9fa5c Iustin Pop
             "%d error(s) out of %d instance(s).", bad_cnt, len(results))
328 f8c9fa5c Iustin Pop
    rcode = constants.EXIT_FAILURE
329 f8c9fa5c Iustin Pop
  return rcode
330 a5bc662a Iustin Pop
331 a5bc662a Iustin Pop
332 c450e9b0 Iustin Pop
def FailoverNode(opts, args):
333 c450e9b0 Iustin Pop
  """Failover all primary instance on a node.
334 c450e9b0 Iustin Pop

335 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
336 ebf366ee Iustin Pop
  @type args: list
337 ebf366ee Iustin Pop
  @param args: should be an empty list
338 ebf366ee Iustin Pop
  @rtype: int
339 ebf366ee Iustin Pop
  @return: the desired exit code
340 ebf366ee Iustin Pop

341 c450e9b0 Iustin Pop
  """
342 479636a3 Iustin Pop
  cl = GetClient()
343 c450e9b0 Iustin Pop
  force = opts.force
344 c450e9b0 Iustin Pop
  selected_fields = ["name", "pinst_list"]
345 c450e9b0 Iustin Pop
346 2e7b8369 Iustin Pop
  # these fields are static data anyway, so it doesn't matter, but
347 2e7b8369 Iustin Pop
  # locking=True should be safer
348 2e7b8369 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields,
349 77921a95 Iustin Pop
                         use_locking=False)
350 c450e9b0 Iustin Pop
  node, pinst = result[0]
351 c450e9b0 Iustin Pop
352 c450e9b0 Iustin Pop
  if not pinst:
353 3a24c527 Iustin Pop
    ToStderr("No primary instances on node %s, exiting.", node)
354 c450e9b0 Iustin Pop
    return 0
355 c450e9b0 Iustin Pop
356 c450e9b0 Iustin Pop
  pinst = utils.NiceSort(pinst)
357 c450e9b0 Iustin Pop
358 c450e9b0 Iustin Pop
  retcode = 0
359 c450e9b0 Iustin Pop
360 c450e9b0 Iustin Pop
  if not force and not AskUser("Fail over instance(s) %s?" %
361 c450e9b0 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
362 c450e9b0 Iustin Pop
    return 2
363 c450e9b0 Iustin Pop
364 cb573a31 Iustin Pop
  jex = JobExecutor(cl=cl, opts=opts)
365 c450e9b0 Iustin Pop
  for iname in pinst:
366 c450e9b0 Iustin Pop
    op = opcodes.OpFailoverInstance(instance_name=iname,
367 c450e9b0 Iustin Pop
                                    ignore_consistency=opts.ignore_consistency)
368 479636a3 Iustin Pop
    jex.QueueJob(iname, op)
369 479636a3 Iustin Pop
  results = jex.GetResults()
370 479636a3 Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
371 479636a3 Iustin Pop
  if bad_cnt == 0:
372 479636a3 Iustin Pop
    ToStdout("All %d instance(s) failed over successfully.", len(results))
373 c450e9b0 Iustin Pop
  else:
374 3a24c527 Iustin Pop
    ToStdout("There were errors during the failover:\n"
375 479636a3 Iustin Pop
             "%d error(s) out of %d instance(s).", bad_cnt, len(results))
376 c450e9b0 Iustin Pop
  return retcode
377 c450e9b0 Iustin Pop
378 c450e9b0 Iustin Pop
379 40ef0ed6 Iustin Pop
def MigrateNode(opts, args):
380 40ef0ed6 Iustin Pop
  """Migrate all primary instance on a node.
381 40ef0ed6 Iustin Pop

382 40ef0ed6 Iustin Pop
  """
383 40ef0ed6 Iustin Pop
  cl = GetClient()
384 40ef0ed6 Iustin Pop
  force = opts.force
385 40ef0ed6 Iustin Pop
  selected_fields = ["name", "pinst_list"]
386 40ef0ed6 Iustin Pop
387 77921a95 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields, use_locking=False)
388 40ef0ed6 Iustin Pop
  node, pinst = result[0]
389 40ef0ed6 Iustin Pop
390 40ef0ed6 Iustin Pop
  if not pinst:
391 40ef0ed6 Iustin Pop
    ToStdout("No primary instances on node %s, exiting." % node)
392 40ef0ed6 Iustin Pop
    return 0
393 40ef0ed6 Iustin Pop
394 40ef0ed6 Iustin Pop
  pinst = utils.NiceSort(pinst)
395 40ef0ed6 Iustin Pop
396 40ef0ed6 Iustin Pop
  if not force and not AskUser("Migrate instance(s) %s?" %
397 40ef0ed6 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
398 40ef0ed6 Iustin Pop
    return 2
399 40ef0ed6 Iustin Pop
400 e71b9ef4 Iustin Pop
  # this should be removed once --non-live is deprecated
401 783a6c0b Iustin Pop
  if not opts.live and opts.migration_mode is not None:
402 e71b9ef4 Iustin Pop
    raise errors.OpPrereqError("Only one of the --non-live and "
403 783a6c0b Iustin Pop
                               "--migration-mode options can be passed",
404 e71b9ef4 Iustin Pop
                               errors.ECODE_INVAL)
405 e71b9ef4 Iustin Pop
  if not opts.live: # --non-live passed
406 8c35561f Iustin Pop
    mode = constants.HT_MIGRATION_NONLIVE
407 e71b9ef4 Iustin Pop
  else:
408 8c35561f Iustin Pop
    mode = opts.migration_mode
409 8c35561f Iustin Pop
  op = opcodes.OpMigrateNode(node_name=args[0], mode=mode)
410 400ca2f7 Iustin Pop
  SubmitOpCode(op, cl=cl, opts=opts)
411 40ef0ed6 Iustin Pop
412 40ef0ed6 Iustin Pop
413 a8083063 Iustin Pop
def ShowNodeConfig(opts, args):
414 a8083063 Iustin Pop
  """Show node information.
415 a8083063 Iustin Pop

416 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
417 ebf366ee Iustin Pop
  @type args: list
418 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
419 ebf366ee Iustin Pop
      we show information about all nodes, or should contain
420 ebf366ee Iustin Pop
      a list of nodes to be queried for information
421 ebf366ee Iustin Pop
  @rtype: int
422 ebf366ee Iustin Pop
  @return: the desired exit code
423 ebf366ee Iustin Pop

424 a8083063 Iustin Pop
  """
425 2e7b8369 Iustin Pop
  cl = GetClient()
426 2e7b8369 Iustin Pop
  result = cl.QueryNodes(fields=["name", "pip", "sip",
427 0b2454b9 Iustin Pop
                                 "pinst_list", "sinst_list",
428 7b4978ad Iustin Pop
                                 "master_candidate", "drained", "offline",
429 7b4978ad Iustin Pop
                                 "master_capable", "vm_capable"],
430 77921a95 Iustin Pop
                         names=args, use_locking=False)
431 a8083063 Iustin Pop
432 0b2454b9 Iustin Pop
  for (name, primary_ip, secondary_ip, pinst, sinst,
433 7b4978ad Iustin Pop
       is_mc, drained, offline, master_capable, vm_capable) in result:
434 3a24c527 Iustin Pop
    ToStdout("Node name: %s", name)
435 3a24c527 Iustin Pop
    ToStdout("  primary ip: %s", primary_ip)
436 3a24c527 Iustin Pop
    ToStdout("  secondary ip: %s", secondary_ip)
437 0b2454b9 Iustin Pop
    ToStdout("  master candidate: %s", is_mc)
438 0b2454b9 Iustin Pop
    ToStdout("  drained: %s", drained)
439 0b2454b9 Iustin Pop
    ToStdout("  offline: %s", offline)
440 7b4978ad Iustin Pop
    ToStdout("  master_capable: %s", master_capable)
441 7b4978ad Iustin Pop
    ToStdout("  vm_capable: %s", vm_capable)
442 7b4978ad Iustin Pop
    if vm_capable:
443 7b4978ad Iustin Pop
      if pinst:
444 7b4978ad Iustin Pop
        ToStdout("  primary for instances:")
445 7b4978ad Iustin Pop
        for iname in utils.NiceSort(pinst):
446 7b4978ad Iustin Pop
          ToStdout("    - %s", iname)
447 7b4978ad Iustin Pop
      else:
448 7b4978ad Iustin Pop
        ToStdout("  primary for no instances")
449 7b4978ad Iustin Pop
      if sinst:
450 7b4978ad Iustin Pop
        ToStdout("  secondary for instances:")
451 7b4978ad Iustin Pop
        for iname in utils.NiceSort(sinst):
452 7b4978ad Iustin Pop
          ToStdout("    - %s", iname)
453 7b4978ad Iustin Pop
      else:
454 7b4978ad Iustin Pop
        ToStdout("  secondary for no instances")
455 a8083063 Iustin Pop
456 a8083063 Iustin Pop
  return 0
457 a8083063 Iustin Pop
458 a8083063 Iustin Pop
459 a8083063 Iustin Pop
def RemoveNode(opts, args):
460 ebf366ee Iustin Pop
  """Remove a node from the cluster.
461 ebf366ee Iustin Pop

462 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
463 ebf366ee Iustin Pop
  @type args: list
464 ebf366ee Iustin Pop
  @param args: should contain only one element, the name of
465 ebf366ee Iustin Pop
      the node to be removed
466 ebf366ee Iustin Pop
  @rtype: int
467 ebf366ee Iustin Pop
  @return: the desired exit code
468 ebf366ee Iustin Pop

469 ebf366ee Iustin Pop
  """
470 a8083063 Iustin Pop
  op = opcodes.OpRemoveNode(node_name=args[0])
471 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
472 ebf366ee Iustin Pop
  return 0
473 a8083063 Iustin Pop
474 a8083063 Iustin Pop
475 f5118ade Iustin Pop
def PowercycleNode(opts, args):
476 f5118ade Iustin Pop
  """Remove a node from the cluster.
477 f5118ade Iustin Pop

478 f5118ade Iustin Pop
  @param opts: the command line options selected by the user
479 f5118ade Iustin Pop
  @type args: list
480 f5118ade Iustin Pop
  @param args: should contain only one element, the name of
481 f5118ade Iustin Pop
      the node to be removed
482 f5118ade Iustin Pop
  @rtype: int
483 f5118ade Iustin Pop
  @return: the desired exit code
484 f5118ade Iustin Pop

485 f5118ade Iustin Pop
  """
486 f5118ade Iustin Pop
  node = args[0]
487 f5118ade Iustin Pop
  if (not opts.confirm and
488 f5118ade Iustin Pop
      not AskUser("Are you sure you want to hard powercycle node %s?" % node)):
489 f5118ade Iustin Pop
    return 2
490 f5118ade Iustin Pop
491 f5118ade Iustin Pop
  op = opcodes.OpPowercycleNode(node_name=node, force=opts.force)
492 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
493 48418fea Iustin Pop
  if result:
494 48418fea Iustin Pop
    ToStderr(result)
495 f5118ade Iustin Pop
  return 0
496 f5118ade Iustin Pop
497 f5118ade Iustin Pop
498 dcb93971 Michael Hanselmann
def ListVolumes(opts, args):
499 dcb93971 Michael Hanselmann
  """List logical volumes on node(s).
500 dcb93971 Michael Hanselmann

501 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
502 ebf366ee Iustin Pop
  @type args: list
503 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
504 ebf366ee Iustin Pop
      we list data for all nodes, or contain a list of nodes
505 ebf366ee Iustin Pop
      to display data only for those
506 ebf366ee Iustin Pop
  @rtype: int
507 ebf366ee Iustin Pop
  @return: the desired exit code
508 ebf366ee Iustin Pop

509 dcb93971 Michael Hanselmann
  """
510 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_VOL_DEF_FIELDS)
511 dcb93971 Michael Hanselmann
512 dcb93971 Michael Hanselmann
  op = opcodes.OpQueryNodeVolumes(nodes=args, output_fields=selected_fields)
513 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
514 dcb93971 Michael Hanselmann
515 dcb93971 Michael Hanselmann
  if not opts.no_headers:
516 137161c9 Michael Hanselmann
    headers = {"node": "Node", "phys": "PhysDev",
517 137161c9 Michael Hanselmann
               "vg": "VG", "name": "Name",
518 137161c9 Michael Hanselmann
               "size": "Size", "instance": "Instance"}
519 137161c9 Michael Hanselmann
  else:
520 137161c9 Michael Hanselmann
    headers = None
521 137161c9 Michael Hanselmann
522 9fbfbb7b Iustin Pop
  unitfields = ["size"]
523 137161c9 Michael Hanselmann
524 137161c9 Michael Hanselmann
  numfields = ["size"]
525 137161c9 Michael Hanselmann
526 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
527 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
528 9fbfbb7b Iustin Pop
                       numfields=numfields, data=output, units=opts.units)
529 16be8703 Iustin Pop
530 16be8703 Iustin Pop
  for line in data:
531 3a24c527 Iustin Pop
    ToStdout(line)
532 dcb93971 Michael Hanselmann
533 dcb93971 Michael Hanselmann
  return 0
534 dcb93971 Michael Hanselmann
535 dcb93971 Michael Hanselmann
536 9b94905f Iustin Pop
def ListStorage(opts, args):
537 4007f57d Michael Hanselmann
  """List physical volumes on node(s).
538 4007f57d Michael Hanselmann

539 4007f57d Michael Hanselmann
  @param opts: the command line options selected by the user
540 4007f57d Michael Hanselmann
  @type args: list
541 4007f57d Michael Hanselmann
  @param args: should either be an empty list, in which case
542 4007f57d Michael Hanselmann
      we list data for all nodes, or contain a list of nodes
543 4007f57d Michael Hanselmann
      to display data only for those
544 4007f57d Michael Hanselmann
  @rtype: int
545 4007f57d Michael Hanselmann
  @return: the desired exit code
546 4007f57d Michael Hanselmann

547 4007f57d Michael Hanselmann
  """
548 53548798 Michael Hanselmann
  # TODO: Default to ST_FILE if LVM is disabled on the cluster
549 53548798 Michael Hanselmann
  if opts.user_storage_type is None:
550 53548798 Michael Hanselmann
    opts.user_storage_type = constants.ST_LVM_PV
551 53548798 Michael Hanselmann
552 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(opts.user_storage_type)
553 53548798 Michael Hanselmann
554 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_STOR_DEF_FIELDS)
555 4007f57d Michael Hanselmann
556 4007f57d Michael Hanselmann
  op = opcodes.OpQueryNodeStorage(nodes=args,
557 53548798 Michael Hanselmann
                                  storage_type=storage_type,
558 4007f57d Michael Hanselmann
                                  output_fields=selected_fields)
559 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
560 4007f57d Michael Hanselmann
561 4007f57d Michael Hanselmann
  if not opts.no_headers:
562 4007f57d Michael Hanselmann
    headers = {
563 620a85fd Iustin Pop
      constants.SF_NODE: "Node",
564 620a85fd Iustin Pop
      constants.SF_TYPE: "Type",
565 4007f57d Michael Hanselmann
      constants.SF_NAME: "Name",
566 4007f57d Michael Hanselmann
      constants.SF_SIZE: "Size",
567 4007f57d Michael Hanselmann
      constants.SF_USED: "Used",
568 4007f57d Michael Hanselmann
      constants.SF_FREE: "Free",
569 4007f57d Michael Hanselmann
      constants.SF_ALLOCATABLE: "Allocatable",
570 4007f57d Michael Hanselmann
      }
571 4007f57d Michael Hanselmann
  else:
572 4007f57d Michael Hanselmann
    headers = None
573 4007f57d Michael Hanselmann
574 4007f57d Michael Hanselmann
  unitfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
575 4007f57d Michael Hanselmann
  numfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
576 4007f57d Michael Hanselmann
577 dc09c3cf Iustin Pop
  # change raw values to nicer strings
578 dc09c3cf Iustin Pop
  for row in output:
579 dc09c3cf Iustin Pop
    for idx, field in enumerate(selected_fields):
580 dc09c3cf Iustin Pop
      val = row[idx]
581 dc09c3cf Iustin Pop
      if field == constants.SF_ALLOCATABLE:
582 dc09c3cf Iustin Pop
        if val:
583 dc09c3cf Iustin Pop
          val = "Y"
584 dc09c3cf Iustin Pop
        else:
585 dc09c3cf Iustin Pop
          val = "N"
586 dc09c3cf Iustin Pop
      row[idx] = str(val)
587 dc09c3cf Iustin Pop
588 4007f57d Michael Hanselmann
  data = GenerateTable(separator=opts.separator, headers=headers,
589 4007f57d Michael Hanselmann
                       fields=selected_fields, unitfields=unitfields,
590 4007f57d Michael Hanselmann
                       numfields=numfields, data=output, units=opts.units)
591 4007f57d Michael Hanselmann
592 4007f57d Michael Hanselmann
  for line in data:
593 4007f57d Michael Hanselmann
    ToStdout(line)
594 4007f57d Michael Hanselmann
595 4007f57d Michael Hanselmann
  return 0
596 4007f57d Michael Hanselmann
597 4007f57d Michael Hanselmann
598 9b94905f Iustin Pop
def ModifyStorage(opts, args):
599 0e89fc2d Michael Hanselmann
  """Modify storage volume on a node.
600 0e89fc2d Michael Hanselmann

601 0e89fc2d Michael Hanselmann
  @param opts: the command line options selected by the user
602 0e89fc2d Michael Hanselmann
  @type args: list
603 0e89fc2d Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
604 0e89fc2d Michael Hanselmann
  @rtype: int
605 0e89fc2d Michael Hanselmann
  @return: the desired exit code
606 0e89fc2d Michael Hanselmann

607 0e89fc2d Michael Hanselmann
  """
608 0e89fc2d Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
609 0e89fc2d Michael Hanselmann
610 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
611 0e89fc2d Michael Hanselmann
612 0e89fc2d Michael Hanselmann
  changes = {}
613 0e89fc2d Michael Hanselmann
614 0e89fc2d Michael Hanselmann
  if opts.allocatable is not None:
615 e7b61bb0 Iustin Pop
    changes[constants.SF_ALLOCATABLE] = opts.allocatable
616 0e89fc2d Michael Hanselmann
617 0e89fc2d Michael Hanselmann
  if changes:
618 0e89fc2d Michael Hanselmann
    op = opcodes.OpModifyNodeStorage(node_name=node_name,
619 0e89fc2d Michael Hanselmann
                                     storage_type=storage_type,
620 0e89fc2d Michael Hanselmann
                                     name=volume_name,
621 0e89fc2d Michael Hanselmann
                                     changes=changes)
622 400ca2f7 Iustin Pop
    SubmitOpCode(op, opts=opts)
623 620a85fd Iustin Pop
  else:
624 620a85fd Iustin Pop
    ToStderr("No changes to perform, exiting.")
625 0e89fc2d Michael Hanselmann
626 0e89fc2d Michael Hanselmann
627 9b94905f Iustin Pop
def RepairStorage(opts, args):
628 1e3463f1 Michael Hanselmann
  """Repairs a storage volume on a node.
629 1e3463f1 Michael Hanselmann

630 1e3463f1 Michael Hanselmann
  @param opts: the command line options selected by the user
631 1e3463f1 Michael Hanselmann
  @type args: list
632 1e3463f1 Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
633 1e3463f1 Michael Hanselmann
  @rtype: int
634 1e3463f1 Michael Hanselmann
  @return: the desired exit code
635 1e3463f1 Michael Hanselmann

636 1e3463f1 Michael Hanselmann
  """
637 1e3463f1 Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
638 1e3463f1 Michael Hanselmann
639 1e3463f1 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
640 1e3463f1 Michael Hanselmann
641 1e3463f1 Michael Hanselmann
  op = opcodes.OpRepairNodeStorage(node_name=node_name,
642 1e3463f1 Michael Hanselmann
                                   storage_type=storage_type,
643 7e9c6a78 Iustin Pop
                                   name=volume_name,
644 7e9c6a78 Iustin Pop
                                   ignore_consistency=opts.ignore_consistency)
645 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
646 1e3463f1 Michael Hanselmann
647 1e3463f1 Michael Hanselmann
648 b31c8676 Iustin Pop
def SetNodeParams(opts, args):
649 b31c8676 Iustin Pop
  """Modifies a node.
650 b31c8676 Iustin Pop

651 b31c8676 Iustin Pop
  @param opts: the command line options selected by the user
652 b31c8676 Iustin Pop
  @type args: list
653 b31c8676 Iustin Pop
  @param args: should contain only one element, the node name
654 b31c8676 Iustin Pop
  @rtype: int
655 b31c8676 Iustin Pop
  @return: the desired exit code
656 b31c8676 Iustin Pop

657 b31c8676 Iustin Pop
  """
658 53919782 Iustin Pop
  all_changes = [opts.master_candidate, opts.drained, opts.offline,
659 4d32c211 Guido Trotter
                 opts.master_capable, opts.vm_capable, opts.secondary_ip]
660 53919782 Iustin Pop
  if all_changes.count(None) == len(all_changes):
661 b31c8676 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
662 b31c8676 Iustin Pop
    return 1
663 b31c8676 Iustin Pop
664 b31c8676 Iustin Pop
  op = opcodes.OpSetNodeParams(node_name=args[0],
665 e7b61bb0 Iustin Pop
                               master_candidate=opts.master_candidate,
666 e7b61bb0 Iustin Pop
                               offline=opts.offline,
667 e7b61bb0 Iustin Pop
                               drained=opts.drained,
668 f91e255a Iustin Pop
                               master_capable=opts.master_capable,
669 53919782 Iustin Pop
                               vm_capable=opts.vm_capable,
670 4d32c211 Guido Trotter
                               secondary_ip=opts.secondary_ip,
671 4c61d894 Iustin Pop
                               force=opts.force,
672 4c61d894 Iustin Pop
                               auto_promote=opts.auto_promote)
673 b31c8676 Iustin Pop
674 b31c8676 Iustin Pop
  # even if here we process the result, we allow submit only
675 b31c8676 Iustin Pop
  result = SubmitOrSend(op, opts)
676 b31c8676 Iustin Pop
677 b31c8676 Iustin Pop
  if result:
678 b31c8676 Iustin Pop
    ToStdout("Modified node %s", args[0])
679 b31c8676 Iustin Pop
    for param, data in result:
680 b31c8676 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
681 b31c8676 Iustin Pop
  return 0
682 b31c8676 Iustin Pop
683 b31c8676 Iustin Pop
684 a8083063 Iustin Pop
commands = {
685 6ea815cf Iustin Pop
  'add': (
686 6ea815cf Iustin Pop
    AddNode, [ArgHost(min=1, max=1)],
687 3ef51126 René Nussbaumer
    [SECONDARY_IP_OPT, READD_OPT, NOSSH_KEYCHECK_OPT, NONODE_SETUP_OPT,
688 fd3d37b6 Iustin Pop
     VERBOSE_OPT, NODEGROUP_OPT, PRIORITY_OPT, CAPAB_MASTER_OPT,
689 fd3d37b6 Iustin Pop
     CAPAB_VM_OPT],
690 3ef51126 René Nussbaumer
    "[-s ip] [--readd] [--no-ssh-key-check] [--no-node-setup]  [--verbose] "
691 2e6469a1 René Nussbaumer
    " <node_name>",
692 6ea815cf Iustin Pop
    "Add a node to the cluster"),
693 6ea815cf Iustin Pop
  'evacuate': (
694 f8c9fa5c Iustin Pop
    EvacuateNode, [ArgNode(min=1)],
695 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, IALLOCATOR_OPT, NEW_SECONDARY_OPT, EARLY_RELEASE_OPT,
696 aa06f8c6 Michael Hanselmann
     PRIORITY_OPT],
697 6ea815cf Iustin Pop
    "[-f] {-I <iallocator> | -n <dst>} <node>",
698 6ea815cf Iustin Pop
    "Relocate the secondary instances from a node"
699 6ea815cf Iustin Pop
    " to other nodes (only for instances with drbd disk template)"),
700 6ea815cf Iustin Pop
  'failover': (
701 aa06f8c6 Michael Hanselmann
    FailoverNode, ARGS_ONE_NODE, [FORCE_OPT, IGNORE_CONSIST_OPT, PRIORITY_OPT],
702 6ea815cf Iustin Pop
    "[-f] <node>",
703 6ea815cf Iustin Pop
    "Stops the primary instances on a node and start them on their"
704 6ea815cf Iustin Pop
    " secondary node (only for instances with drbd disk template)"),
705 6ea815cf Iustin Pop
  'migrate': (
706 aa06f8c6 Michael Hanselmann
    MigrateNode, ARGS_ONE_NODE,
707 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, NONLIVE_OPT, MIGRATION_MODE_OPT, PRIORITY_OPT],
708 6ea815cf Iustin Pop
    "[-f] <node>",
709 6ea815cf Iustin Pop
    "Migrate all the primary instance on a node away from it"
710 6ea815cf Iustin Pop
    " (only for instances of type drbd)"),
711 6ea815cf Iustin Pop
  'info': (
712 064c21f8 Iustin Pop
    ShowNodeConfig, ARGS_MANY_NODES, [],
713 6ea815cf Iustin Pop
    "[<node_name>...]", "Show information about the node(s)"),
714 6ea815cf Iustin Pop
  'list': (
715 6ea815cf Iustin Pop
    ListNodes, ARGS_MANY_NODES,
716 31d97b2a Guido Trotter
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, SYNC_OPT, ROMAN_OPT],
717 6ea815cf Iustin Pop
    "[nodes...]",
718 6ea815cf Iustin Pop
    "Lists the nodes in the cluster. The available fields are (see the man"
719 6ea815cf Iustin Pop
    " page for details): %s. The default field list is (in order): %s." %
720 1f864b60 Iustin Pop
    (utils.CommaJoin(_LIST_HEADERS), utils.CommaJoin(_LIST_DEF_FIELDS))),
721 6ea815cf Iustin Pop
  'modify': (
722 6ea815cf Iustin Pop
    SetNodeParams, ARGS_ONE_NODE,
723 53919782 Iustin Pop
    [FORCE_OPT, SUBMIT_OPT, MC_OPT, DRAINED_OPT, OFFLINE_OPT,
724 4d32c211 Guido Trotter
     CAPAB_MASTER_OPT, CAPAB_VM_OPT, SECONDARY_IP_OPT,
725 aa06f8c6 Michael Hanselmann
     AUTO_PROMOTE_OPT, DRY_RUN_OPT, PRIORITY_OPT],
726 6ea815cf Iustin Pop
    "<node_name>", "Alters the parameters of a node"),
727 6ea815cf Iustin Pop
  'powercycle': (
728 6ea815cf Iustin Pop
    PowercycleNode, ARGS_ONE_NODE,
729 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, CONFIRM_OPT, DRY_RUN_OPT, PRIORITY_OPT],
730 6ea815cf Iustin Pop
    "<node_name>", "Tries to forcefully powercycle a node"),
731 6ea815cf Iustin Pop
  'remove': (
732 aa06f8c6 Michael Hanselmann
    RemoveNode, ARGS_ONE_NODE, [DRY_RUN_OPT, PRIORITY_OPT],
733 6ea815cf Iustin Pop
    "<node_name>", "Removes a node from the cluster"),
734 6ea815cf Iustin Pop
  'volumes': (
735 6ea815cf Iustin Pop
    ListVolumes, [ArgNode()],
736 aa06f8c6 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, PRIORITY_OPT],
737 6ea815cf Iustin Pop
    "[<node_name>...]", "List logical volumes on node(s)"),
738 9b94905f Iustin Pop
  'list-storage': (
739 9b94905f Iustin Pop
    ListStorage, ARGS_MANY_NODES,
740 aa06f8c6 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, _STORAGE_TYPE_OPT,
741 aa06f8c6 Michael Hanselmann
     PRIORITY_OPT],
742 620a85fd Iustin Pop
    "[<node_name>...]", "List physical volumes on node(s). The available"
743 620a85fd Iustin Pop
    " fields are (see the man page for details): %s." %
744 1f864b60 Iustin Pop
    (utils.CommaJoin(_LIST_STOR_HEADERS))),
745 9b94905f Iustin Pop
  'modify-storage': (
746 9b94905f Iustin Pop
    ModifyStorage,
747 6ea815cf Iustin Pop
    [ArgNode(min=1, max=1),
748 6ea815cf Iustin Pop
     ArgChoice(min=1, max=1, choices=_MODIFIABLE_STORAGE_TYPES),
749 6ea815cf Iustin Pop
     ArgFile(min=1, max=1)],
750 aa06f8c6 Michael Hanselmann
    [ALLOCATABLE_OPT, DRY_RUN_OPT, PRIORITY_OPT],
751 064c21f8 Iustin Pop
    "<node_name> <storage_type> <name>", "Modify storage volume on a node"),
752 9b94905f Iustin Pop
  'repair-storage': (
753 9b94905f Iustin Pop
    RepairStorage,
754 6ea815cf Iustin Pop
    [ArgNode(min=1, max=1),
755 6ea815cf Iustin Pop
     ArgChoice(min=1, max=1, choices=_REPAIRABLE_STORAGE_TYPES),
756 6ea815cf Iustin Pop
     ArgFile(min=1, max=1)],
757 aa06f8c6 Michael Hanselmann
    [IGNORE_CONSIST_OPT, DRY_RUN_OPT, PRIORITY_OPT],
758 6ea815cf Iustin Pop
    "<node_name> <storage_type> <name>",
759 6ea815cf Iustin Pop
    "Repairs a storage volume on a node"),
760 6ea815cf Iustin Pop
  'list-tags': (
761 064c21f8 Iustin Pop
    ListTags, ARGS_ONE_NODE, [],
762 6ea815cf Iustin Pop
    "<node_name>", "List the tags of the given node"),
763 6ea815cf Iustin Pop
  'add-tags': (
764 aa06f8c6 Michael Hanselmann
    AddTags, [ArgNode(min=1, max=1), ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT],
765 6ea815cf Iustin Pop
    "<node_name> tag...", "Add tags to the given node"),
766 6ea815cf Iustin Pop
  'remove-tags': (
767 aa06f8c6 Michael Hanselmann
    RemoveTags, [ArgNode(min=1, max=1), ArgUnknown()],
768 aa06f8c6 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT],
769 6ea815cf Iustin Pop
    "<node_name> tag...", "Remove tags from the given node"),
770 a8083063 Iustin Pop
  }
771 a8083063 Iustin Pop
772 a8083063 Iustin Pop
773 37494fa4 Michael Hanselmann
def Main():
774 37494fa4 Michael Hanselmann
  return GenericMain(commands, override={"tag_type": constants.TAG_NODE})