Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ 9b12c120

History | View | Annotate | Download (34.5 kB)

1 37494fa4 Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 f1dff7ec Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 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 b459a848 Andrea Spadaccini
# pylint: disable=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 aafee533 Michael Hanselmann
import itertools
30 aafee533 Michael Hanselmann
31 a8083063 Iustin Pop
from ganeti.cli import *
32 d363797e René Nussbaumer
from ganeti import cli
33 3ef51126 René Nussbaumer
from ganeti import bootstrap
34 a8083063 Iustin Pop
from ganeti import opcodes
35 a8083063 Iustin Pop
from ganeti import utils
36 846baef9 Iustin Pop
from ganeti import constants
37 c450e9b0 Iustin Pop
from ganeti import errors
38 a744b676 Manuel Franceschini
from ganeti import netutils
39 8572f1fe René Nussbaumer
from cStringIO import StringIO
40 a8083063 Iustin Pop
41 7acbda7b Iustin Pop
from ganeti import confd
42 7acbda7b Iustin Pop
from ganeti.confd import client as confd_client
43 a8083063 Iustin Pop
44 ebf366ee Iustin Pop
#: default list of field for L{ListNodes}
45 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
46 48c4dfa8 Iustin Pop
  "name", "dtotal", "dfree",
47 48c4dfa8 Iustin Pop
  "mtotal", "mnode", "mfree",
48 48c4dfa8 Iustin Pop
  "pinst_cnt", "sinst_cnt",
49 48c4dfa8 Iustin Pop
  ]
50 48c4dfa8 Iustin Pop
51 620a85fd Iustin Pop
52 a4ebd726 Michael Hanselmann
#: Default field list for L{ListVolumes}
53 a4ebd726 Michael Hanselmann
_LIST_VOL_DEF_FIELDS = ["node", "phys", "vg", "name", "size", "instance"]
54 a4ebd726 Michael Hanselmann
55 a4ebd726 Michael Hanselmann
56 620a85fd Iustin Pop
#: default list of field for L{ListStorage}
57 620a85fd Iustin Pop
_LIST_STOR_DEF_FIELDS = [
58 620a85fd Iustin Pop
  constants.SF_NODE,
59 620a85fd Iustin Pop
  constants.SF_TYPE,
60 620a85fd Iustin Pop
  constants.SF_NAME,
61 620a85fd Iustin Pop
  constants.SF_SIZE,
62 620a85fd Iustin Pop
  constants.SF_USED,
63 620a85fd Iustin Pop
  constants.SF_FREE,
64 620a85fd Iustin Pop
  constants.SF_ALLOCATABLE,
65 620a85fd Iustin Pop
  ]
66 620a85fd Iustin Pop
67 620a85fd Iustin Pop
68 abefdcff René Nussbaumer
#: default list of power commands
69 abefdcff René Nussbaumer
_LIST_POWER_COMMANDS = ["on", "off", "cycle", "status"]
70 abefdcff René Nussbaumer
71 abefdcff René Nussbaumer
72 982ed68e Adeodato Simo
#: headers (and full field list) for L{ListStorage}
73 620a85fd Iustin Pop
_LIST_STOR_HEADERS = {
74 620a85fd Iustin Pop
  constants.SF_NODE: "Node",
75 620a85fd Iustin Pop
  constants.SF_TYPE: "Type",
76 620a85fd Iustin Pop
  constants.SF_NAME: "Name",
77 620a85fd Iustin Pop
  constants.SF_SIZE: "Size",
78 620a85fd Iustin Pop
  constants.SF_USED: "Used",
79 620a85fd Iustin Pop
  constants.SF_FREE: "Free",
80 620a85fd Iustin Pop
  constants.SF_ALLOCATABLE: "Allocatable",
81 620a85fd Iustin Pop
  }
82 620a85fd Iustin Pop
83 620a85fd Iustin Pop
84 0e89fc2d Michael Hanselmann
#: User-facing storage unit types
85 0e89fc2d Michael Hanselmann
_USER_STORAGE_TYPE = {
86 0e89fc2d Michael Hanselmann
  constants.ST_FILE: "file",
87 0e89fc2d Michael Hanselmann
  constants.ST_LVM_PV: "lvm-pv",
88 0e89fc2d Michael Hanselmann
  constants.ST_LVM_VG: "lvm-vg",
89 0e89fc2d Michael Hanselmann
  }
90 0e89fc2d Michael Hanselmann
91 a8005e17 Michael Hanselmann
_STORAGE_TYPE_OPT = \
92 aeaefce8 Iustin Pop
  cli_option("-t", "--storage-type",
93 a8005e17 Michael Hanselmann
             dest="user_storage_type",
94 a8005e17 Michael Hanselmann
             choices=_USER_STORAGE_TYPE.keys(),
95 a8005e17 Michael Hanselmann
             default=None,
96 a8005e17 Michael Hanselmann
             metavar="STORAGE_TYPE",
97 ab3e6da8 Iustin Pop
             help=("Storage type (%s)" %
98 ab3e6da8 Iustin Pop
                   utils.CommaJoin(_USER_STORAGE_TYPE.keys())))
99 a8005e17 Michael Hanselmann
100 a8005e17 Michael Hanselmann
_REPAIRABLE_STORAGE_TYPES = \
101 a8005e17 Michael Hanselmann
  [st for st, so in constants.VALID_STORAGE_OPERATIONS.iteritems()
102 a8005e17 Michael Hanselmann
   if constants.SO_FIX_CONSISTENCY in so]
103 a8005e17 Michael Hanselmann
104 a8005e17 Michael Hanselmann
_MODIFIABLE_STORAGE_TYPES = constants.MODIFIABLE_STORAGE_FIELDS.keys()
105 a8005e17 Michael Hanselmann
106 51144e33 Michael Hanselmann
107 c832b6c8 René Nussbaumer
_OOB_COMMAND_ASK = frozenset([constants.OOB_POWER_OFF,
108 c832b6c8 René Nussbaumer
                              constants.OOB_POWER_CYCLE])
109 c832b6c8 René Nussbaumer
110 c832b6c8 René Nussbaumer
111 ef9fa5b9 René Nussbaumer
_ENV_OVERRIDE = frozenset(["list"])
112 ef9fa5b9 René Nussbaumer
113 ef9fa5b9 René Nussbaumer
114 2e6469a1 René Nussbaumer
NONODE_SETUP_OPT = cli_option("--no-node-setup", default=True,
115 2e6469a1 René Nussbaumer
                              action="store_false", dest="node_setup",
116 2e6469a1 René Nussbaumer
                              help=("Do not make initial SSH setup on remote"
117 2e6469a1 René Nussbaumer
                                    " node (needs to be done manually)"))
118 2e6469a1 René Nussbaumer
119 efae0fdd René Nussbaumer
IGNORE_STATUS_OPT = cli_option("--ignore-status", default=False,
120 efae0fdd René Nussbaumer
                               action="store_true", dest="ignore_status",
121 efae0fdd René Nussbaumer
                               help=("Ignore the Node(s) offline status"
122 efae0fdd René Nussbaumer
                                     " (potentially DANGEROUS)"))
123 efae0fdd René Nussbaumer
124 65a77fab René Nussbaumer
125 86f5eae3 Michael Hanselmann
def ConvertStorageType(user_storage_type):
126 86f5eae3 Michael Hanselmann
  """Converts a user storage type to its internal name.
127 86f5eae3 Michael Hanselmann

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

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

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

173 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
174 ebf366ee Iustin Pop
  @type args: list
175 ebf366ee Iustin Pop
  @param args: should contain only one element, the new node name
176 ebf366ee Iustin Pop
  @rtype: int
177 ebf366ee Iustin Pop
  @return: the desired exit code
178 05ccd983 Guido Trotter

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

243 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
244 ebf366ee Iustin Pop
  @type args: list
245 982ed68e Adeodato Simo
  @param args: nodes to list, or empty for all
246 ebf366ee Iustin Pop
  @rtype: int
247 ebf366ee Iustin Pop
  @return: the desired exit code
248 ebf366ee Iustin Pop

249 a8083063 Iustin Pop
  """
250 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
251 a8083063 Iustin Pop
252 7f5443a0 Michael Hanselmann
  fmtoverride = dict.fromkeys(["pinst_list", "sinst_list", "tags"],
253 a36f605d Michael Hanselmann
                              (",".join, False))
254 a8083063 Iustin Pop
255 7f5443a0 Michael Hanselmann
  return GenericList(constants.QR_NODE, selected_fields, args, opts.units,
256 7f5443a0 Michael Hanselmann
                     opts.separator, not opts.no_headers,
257 2afd577f Michael Hanselmann
                     format_override=fmtoverride, verbose=opts.verbose,
258 2afd577f Michael Hanselmann
                     force_filter=opts.force_filter)
259 137161c9 Michael Hanselmann
260 137161c9 Michael Hanselmann
261 7f5443a0 Michael Hanselmann
def ListNodeFields(opts, args):
262 7f5443a0 Michael Hanselmann
  """List node fields.
263 ec223efb Iustin Pop

264 7f5443a0 Michael Hanselmann
  @param opts: the command line options selected by the user
265 7f5443a0 Michael Hanselmann
  @type args: list
266 7f5443a0 Michael Hanselmann
  @param args: fields to list, or empty for all
267 7f5443a0 Michael Hanselmann
  @rtype: int
268 7f5443a0 Michael Hanselmann
  @return: the desired exit code
269 a8083063 Iustin Pop

270 7f5443a0 Michael Hanselmann
  """
271 7f5443a0 Michael Hanselmann
  return GenericListFields(constants.QR_NODE, args, opts.separator,
272 7f5443a0 Michael Hanselmann
                           not opts.no_headers)
273 a8083063 Iustin Pop
274 a8083063 Iustin Pop
275 a5bc662a Iustin Pop
def EvacuateNode(opts, args):
276 a5bc662a Iustin Pop
  """Relocate all secondary instance from a node.
277 a5bc662a Iustin Pop

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

284 a5bc662a Iustin Pop
  """
285 aafee533 Michael Hanselmann
  if opts.dst_node is not None:
286 aafee533 Michael Hanselmann
    ToStderr("New secondary node given (disabling iallocator), hence evacuating"
287 aafee533 Michael Hanselmann
             " secondary instances only.")
288 aafee533 Michael Hanselmann
    opts.secondary_only = True
289 aafee533 Michael Hanselmann
    opts.primary_only = False
290 aafee533 Michael Hanselmann
291 aafee533 Michael Hanselmann
  if opts.secondary_only and opts.primary_only:
292 aafee533 Michael Hanselmann
    raise errors.OpPrereqError("Only one of the --primary-only and"
293 aafee533 Michael Hanselmann
                               " --secondary-only options can be passed",
294 aafee533 Michael Hanselmann
                               errors.ECODE_INVAL)
295 aafee533 Michael Hanselmann
  elif opts.primary_only:
296 cb92e7a1 Michael Hanselmann
    mode = constants.NODE_EVAC_PRI
297 aafee533 Michael Hanselmann
  elif opts.secondary_only:
298 cb92e7a1 Michael Hanselmann
    mode = constants.NODE_EVAC_SEC
299 aafee533 Michael Hanselmann
  else:
300 cb92e7a1 Michael Hanselmann
    mode = constants.NODE_EVAC_ALL
301 c4ed32cb Iustin Pop
302 aafee533 Michael Hanselmann
  # Determine affected instances
303 aafee533 Michael Hanselmann
  fields = []
304 c4ed32cb Iustin Pop
305 aafee533 Michael Hanselmann
  if not opts.secondary_only:
306 aafee533 Michael Hanselmann
    fields.append("pinst_list")
307 aafee533 Michael Hanselmann
  if not opts.primary_only:
308 aafee533 Michael Hanselmann
    fields.append("sinst_list")
309 f8c9fa5c Iustin Pop
310 aafee533 Michael Hanselmann
  cl = GetClient()
311 aafee533 Michael Hanselmann
312 aafee533 Michael Hanselmann
  result = cl.QueryNodes(names=args, fields=fields, use_locking=False)
313 aafee533 Michael Hanselmann
  instances = set(itertools.chain(*itertools.chain(*itertools.chain(result))))
314 aafee533 Michael Hanselmann
315 aafee533 Michael Hanselmann
  if not instances:
316 aafee533 Michael Hanselmann
    # No instances to evacuate
317 aafee533 Michael Hanselmann
    ToStderr("No instances to evacuate on node(s) %s, exiting.",
318 f8c9fa5c Iustin Pop
             utils.CommaJoin(args))
319 a5bc662a Iustin Pop
    return constants.EXIT_SUCCESS
320 a5bc662a Iustin Pop
321 aafee533 Michael Hanselmann
  if not (opts.force or
322 aafee533 Michael Hanselmann
          AskUser("Relocate instance(s) %s from node(s) %s?" %
323 aafee533 Michael Hanselmann
                  (utils.CommaJoin(utils.NiceSort(instances)),
324 aafee533 Michael Hanselmann
                   utils.CommaJoin(args)))):
325 a5bc662a Iustin Pop
    return constants.EXIT_CONFIRMATION
326 a5bc662a Iustin Pop
327 aafee533 Michael Hanselmann
  # Evacuate node
328 aafee533 Michael Hanselmann
  op = opcodes.OpNodeEvacuate(node_name=args[0], mode=mode,
329 aafee533 Michael Hanselmann
                              remote_node=opts.dst_node,
330 aafee533 Michael Hanselmann
                              iallocator=opts.iallocator,
331 aafee533 Michael Hanselmann
                              early_release=opts.early_release)
332 c5a66db3 Michael Hanselmann
  result = SubmitOrSend(op, opts, cl=cl)
333 aafee533 Michael Hanselmann
334 aafee533 Michael Hanselmann
  # Keep track of submitted jobs
335 f8c9fa5c Iustin Pop
  jex = JobExecutor(cl=cl, opts=opts)
336 aafee533 Michael Hanselmann
337 aafee533 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
338 aafee533 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
339 aafee533 Michael Hanselmann
340 f8c9fa5c Iustin Pop
  results = jex.GetResults()
341 f8c9fa5c Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
342 f8c9fa5c Iustin Pop
  if bad_cnt == 0:
343 aafee533 Michael Hanselmann
    ToStdout("All instances evacuated successfully.")
344 f8c9fa5c Iustin Pop
    rcode = constants.EXIT_SUCCESS
345 f8c9fa5c Iustin Pop
  else:
346 aafee533 Michael Hanselmann
    ToStdout("There were %s errors during the evacuation.", bad_cnt)
347 f8c9fa5c Iustin Pop
    rcode = constants.EXIT_FAILURE
348 aafee533 Michael Hanselmann
349 f8c9fa5c Iustin Pop
  return rcode
350 a5bc662a Iustin Pop
351 a5bc662a Iustin Pop
352 c450e9b0 Iustin Pop
def FailoverNode(opts, args):
353 c450e9b0 Iustin Pop
  """Failover all primary instance on a node.
354 c450e9b0 Iustin Pop

355 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
356 ebf366ee Iustin Pop
  @type args: list
357 ebf366ee Iustin Pop
  @param args: should be an empty list
358 ebf366ee Iustin Pop
  @rtype: int
359 ebf366ee Iustin Pop
  @return: the desired exit code
360 ebf366ee Iustin Pop

361 c450e9b0 Iustin Pop
  """
362 479636a3 Iustin Pop
  cl = GetClient()
363 c450e9b0 Iustin Pop
  force = opts.force
364 c450e9b0 Iustin Pop
  selected_fields = ["name", "pinst_list"]
365 c450e9b0 Iustin Pop
366 2e7b8369 Iustin Pop
  # these fields are static data anyway, so it doesn't matter, but
367 2e7b8369 Iustin Pop
  # locking=True should be safer
368 2e7b8369 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields,
369 77921a95 Iustin Pop
                         use_locking=False)
370 c450e9b0 Iustin Pop
  node, pinst = result[0]
371 c450e9b0 Iustin Pop
372 c450e9b0 Iustin Pop
  if not pinst:
373 3a24c527 Iustin Pop
    ToStderr("No primary instances on node %s, exiting.", node)
374 c450e9b0 Iustin Pop
    return 0
375 c450e9b0 Iustin Pop
376 c450e9b0 Iustin Pop
  pinst = utils.NiceSort(pinst)
377 c450e9b0 Iustin Pop
378 c450e9b0 Iustin Pop
  retcode = 0
379 c450e9b0 Iustin Pop
380 c450e9b0 Iustin Pop
  if not force and not AskUser("Fail over instance(s) %s?" %
381 c450e9b0 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
382 c450e9b0 Iustin Pop
    return 2
383 c450e9b0 Iustin Pop
384 cb573a31 Iustin Pop
  jex = JobExecutor(cl=cl, opts=opts)
385 c450e9b0 Iustin Pop
  for iname in pinst:
386 019dbee1 Iustin Pop
    op = opcodes.OpInstanceFailover(instance_name=iname,
387 1b7761fd Apollon Oikonomopoulos
                                    ignore_consistency=opts.ignore_consistency,
388 1b7761fd Apollon Oikonomopoulos
                                    iallocator=opts.iallocator)
389 479636a3 Iustin Pop
    jex.QueueJob(iname, op)
390 479636a3 Iustin Pop
  results = jex.GetResults()
391 479636a3 Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
392 479636a3 Iustin Pop
  if bad_cnt == 0:
393 479636a3 Iustin Pop
    ToStdout("All %d instance(s) failed over successfully.", len(results))
394 c450e9b0 Iustin Pop
  else:
395 3a24c527 Iustin Pop
    ToStdout("There were errors during the failover:\n"
396 479636a3 Iustin Pop
             "%d error(s) out of %d instance(s).", bad_cnt, len(results))
397 c450e9b0 Iustin Pop
  return retcode
398 c450e9b0 Iustin Pop
399 c450e9b0 Iustin Pop
400 40ef0ed6 Iustin Pop
def MigrateNode(opts, args):
401 40ef0ed6 Iustin Pop
  """Migrate all primary instance on a node.
402 40ef0ed6 Iustin Pop

403 40ef0ed6 Iustin Pop
  """
404 40ef0ed6 Iustin Pop
  cl = GetClient()
405 40ef0ed6 Iustin Pop
  force = opts.force
406 40ef0ed6 Iustin Pop
  selected_fields = ["name", "pinst_list"]
407 40ef0ed6 Iustin Pop
408 77921a95 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields, use_locking=False)
409 b7a1c816 Michael Hanselmann
  ((node, pinst), ) = result
410 40ef0ed6 Iustin Pop
411 40ef0ed6 Iustin Pop
  if not pinst:
412 40ef0ed6 Iustin Pop
    ToStdout("No primary instances on node %s, exiting." % node)
413 40ef0ed6 Iustin Pop
    return 0
414 40ef0ed6 Iustin Pop
415 40ef0ed6 Iustin Pop
  pinst = utils.NiceSort(pinst)
416 40ef0ed6 Iustin Pop
417 b7a1c816 Michael Hanselmann
  if not (force or
418 b7a1c816 Michael Hanselmann
          AskUser("Migrate instance(s) %s?" %
419 b7a1c816 Michael Hanselmann
                  utils.CommaJoin(utils.NiceSort(pinst)))):
420 b7a1c816 Michael Hanselmann
    return constants.EXIT_CONFIRMATION
421 40ef0ed6 Iustin Pop
422 e71b9ef4 Iustin Pop
  # this should be removed once --non-live is deprecated
423 783a6c0b Iustin Pop
  if not opts.live and opts.migration_mode is not None:
424 e71b9ef4 Iustin Pop
    raise errors.OpPrereqError("Only one of the --non-live and "
425 783a6c0b Iustin Pop
                               "--migration-mode options can be passed",
426 e71b9ef4 Iustin Pop
                               errors.ECODE_INVAL)
427 e71b9ef4 Iustin Pop
  if not opts.live: # --non-live passed
428 8c35561f Iustin Pop
    mode = constants.HT_MIGRATION_NONLIVE
429 e71b9ef4 Iustin Pop
  else:
430 8c35561f Iustin Pop
    mode = opts.migration_mode
431 b7a1c816 Michael Hanselmann
432 1b7761fd Apollon Oikonomopoulos
  op = opcodes.OpNodeMigrate(node_name=args[0], mode=mode,
433 f8fa4175 Michael Hanselmann
                             iallocator=opts.iallocator,
434 9fa567b3 René Nussbaumer
                             target_node=opts.dst_node,
435 8c0b16f6 Guido Trotter
                             allow_runtime_changes=opts.allow_runtime_chgs,
436 9fa567b3 René Nussbaumer
                             ignore_ipolicy=opts.ignore_ipolicy)
437 b7a1c816 Michael Hanselmann
438 c5a66db3 Michael Hanselmann
  result = SubmitOrSend(op, opts, cl=cl)
439 b7a1c816 Michael Hanselmann
440 b7a1c816 Michael Hanselmann
  # Keep track of submitted jobs
441 b7a1c816 Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
442 b7a1c816 Michael Hanselmann
443 b7a1c816 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
444 b7a1c816 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
445 b7a1c816 Michael Hanselmann
446 b7a1c816 Michael Hanselmann
  results = jex.GetResults()
447 b7a1c816 Michael Hanselmann
  bad_cnt = len([row for row in results if not row[0]])
448 b7a1c816 Michael Hanselmann
  if bad_cnt == 0:
449 b7a1c816 Michael Hanselmann
    ToStdout("All instances migrated successfully.")
450 b7a1c816 Michael Hanselmann
    rcode = constants.EXIT_SUCCESS
451 b7a1c816 Michael Hanselmann
  else:
452 b7a1c816 Michael Hanselmann
    ToStdout("There were %s errors during the node migration.", bad_cnt)
453 b7a1c816 Michael Hanselmann
    rcode = constants.EXIT_FAILURE
454 b7a1c816 Michael Hanselmann
455 b7a1c816 Michael Hanselmann
  return rcode
456 40ef0ed6 Iustin Pop
457 40ef0ed6 Iustin Pop
458 a8083063 Iustin Pop
def ShowNodeConfig(opts, args):
459 a8083063 Iustin Pop
  """Show node information.
460 a8083063 Iustin Pop

461 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
462 ebf366ee Iustin Pop
  @type args: list
463 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
464 ebf366ee Iustin Pop
      we show information about all nodes, or should contain
465 ebf366ee Iustin Pop
      a list of nodes to be queried for information
466 ebf366ee Iustin Pop
  @rtype: int
467 ebf366ee Iustin Pop
  @return: the desired exit code
468 ebf366ee Iustin Pop

469 a8083063 Iustin Pop
  """
470 2e7b8369 Iustin Pop
  cl = GetClient()
471 2e7b8369 Iustin Pop
  result = cl.QueryNodes(fields=["name", "pip", "sip",
472 0b2454b9 Iustin Pop
                                 "pinst_list", "sinst_list",
473 7b4978ad Iustin Pop
                                 "master_candidate", "drained", "offline",
474 8572f1fe René Nussbaumer
                                 "master_capable", "vm_capable", "powered",
475 8572f1fe René Nussbaumer
                                 "ndparams", "custom_ndparams"],
476 77921a95 Iustin Pop
                         names=args, use_locking=False)
477 a8083063 Iustin Pop
478 8572f1fe René Nussbaumer
  for (name, primary_ip, secondary_ip, pinst, sinst, is_mc, drained, offline,
479 8572f1fe René Nussbaumer
       master_capable, vm_capable, powered, ndparams,
480 8572f1fe René Nussbaumer
       ndparams_custom) in result:
481 3a24c527 Iustin Pop
    ToStdout("Node name: %s", name)
482 3a24c527 Iustin Pop
    ToStdout("  primary ip: %s", primary_ip)
483 3a24c527 Iustin Pop
    ToStdout("  secondary ip: %s", secondary_ip)
484 0b2454b9 Iustin Pop
    ToStdout("  master candidate: %s", is_mc)
485 0b2454b9 Iustin Pop
    ToStdout("  drained: %s", drained)
486 0b2454b9 Iustin Pop
    ToStdout("  offline: %s", offline)
487 016acd85 René Nussbaumer
    if powered is not None:
488 016acd85 René Nussbaumer
      ToStdout("  powered: %s", powered)
489 7b4978ad Iustin Pop
    ToStdout("  master_capable: %s", master_capable)
490 7b4978ad Iustin Pop
    ToStdout("  vm_capable: %s", vm_capable)
491 7b4978ad Iustin Pop
    if vm_capable:
492 7b4978ad Iustin Pop
      if pinst:
493 7b4978ad Iustin Pop
        ToStdout("  primary for instances:")
494 7b4978ad Iustin Pop
        for iname in utils.NiceSort(pinst):
495 7b4978ad Iustin Pop
          ToStdout("    - %s", iname)
496 7b4978ad Iustin Pop
      else:
497 7b4978ad Iustin Pop
        ToStdout("  primary for no instances")
498 7b4978ad Iustin Pop
      if sinst:
499 7b4978ad Iustin Pop
        ToStdout("  secondary for instances:")
500 7b4978ad Iustin Pop
        for iname in utils.NiceSort(sinst):
501 7b4978ad Iustin Pop
          ToStdout("    - %s", iname)
502 7b4978ad Iustin Pop
      else:
503 7b4978ad Iustin Pop
        ToStdout("  secondary for no instances")
504 8572f1fe René Nussbaumer
    ToStdout("  node parameters:")
505 8572f1fe René Nussbaumer
    buf = StringIO()
506 8572f1fe René Nussbaumer
    FormatParameterDict(buf, ndparams_custom, ndparams, level=2)
507 8572f1fe René Nussbaumer
    ToStdout(buf.getvalue().rstrip("\n"))
508 a8083063 Iustin Pop
509 a8083063 Iustin Pop
  return 0
510 a8083063 Iustin Pop
511 a8083063 Iustin Pop
512 a8083063 Iustin Pop
def RemoveNode(opts, args):
513 ebf366ee Iustin Pop
  """Remove a node from the cluster.
514 ebf366ee Iustin Pop

515 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
516 ebf366ee Iustin Pop
  @type args: list
517 ebf366ee Iustin Pop
  @param args: should contain only one element, the name of
518 ebf366ee Iustin Pop
      the node to be removed
519 ebf366ee Iustin Pop
  @rtype: int
520 ebf366ee Iustin Pop
  @return: the desired exit code
521 ebf366ee Iustin Pop

522 ebf366ee Iustin Pop
  """
523 73d565a3 Iustin Pop
  op = opcodes.OpNodeRemove(node_name=args[0])
524 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
525 ebf366ee Iustin Pop
  return 0
526 a8083063 Iustin Pop
527 a8083063 Iustin Pop
528 f5118ade Iustin Pop
def PowercycleNode(opts, args):
529 f5118ade Iustin Pop
  """Remove a node from the cluster.
530 f5118ade Iustin Pop

531 f5118ade Iustin Pop
  @param opts: the command line options selected by the user
532 f5118ade Iustin Pop
  @type args: list
533 f5118ade Iustin Pop
  @param args: should contain only one element, the name of
534 f5118ade Iustin Pop
      the node to be removed
535 f5118ade Iustin Pop
  @rtype: int
536 f5118ade Iustin Pop
  @return: the desired exit code
537 f5118ade Iustin Pop

538 f5118ade Iustin Pop
  """
539 f5118ade Iustin Pop
  node = args[0]
540 f5118ade Iustin Pop
  if (not opts.confirm and
541 f5118ade Iustin Pop
      not AskUser("Are you sure you want to hard powercycle node %s?" % node)):
542 f5118ade Iustin Pop
    return 2
543 f5118ade Iustin Pop
544 e0d4735f Iustin Pop
  op = opcodes.OpNodePowercycle(node_name=node, force=opts.force)
545 c5a66db3 Michael Hanselmann
  result = SubmitOrSend(op, opts)
546 48418fea Iustin Pop
  if result:
547 48418fea Iustin Pop
    ToStderr(result)
548 f5118ade Iustin Pop
  return 0
549 f5118ade Iustin Pop
550 f5118ade Iustin Pop
551 abefdcff René Nussbaumer
def PowerNode(opts, args):
552 abefdcff René Nussbaumer
  """Change/ask power state of a node.
553 abefdcff René Nussbaumer

554 abefdcff René Nussbaumer
  @param opts: the command line options selected by the user
555 abefdcff René Nussbaumer
  @type args: list
556 abefdcff René Nussbaumer
  @param args: should contain only one element, the name of
557 abefdcff René Nussbaumer
      the node to be removed
558 abefdcff René Nussbaumer
  @rtype: int
559 abefdcff René Nussbaumer
  @return: the desired exit code
560 abefdcff René Nussbaumer

561 abefdcff René Nussbaumer
  """
562 c832b6c8 René Nussbaumer
  command = args.pop(0)
563 c832b6c8 René Nussbaumer
564 c832b6c8 René Nussbaumer
  if opts.no_headers:
565 c832b6c8 René Nussbaumer
    headers = None
566 c832b6c8 René Nussbaumer
  else:
567 c832b6c8 René Nussbaumer
    headers = {"node": "Node", "status": "Status"}
568 abefdcff René Nussbaumer
569 abefdcff René Nussbaumer
  if command not in _LIST_POWER_COMMANDS:
570 abefdcff René Nussbaumer
    ToStderr("power subcommand %s not supported." % command)
571 abefdcff René Nussbaumer
    return constants.EXIT_FAILURE
572 abefdcff René Nussbaumer
573 abefdcff René Nussbaumer
  oob_command = "power-%s" % command
574 abefdcff René Nussbaumer
575 c832b6c8 René Nussbaumer
  if oob_command in _OOB_COMMAND_ASK:
576 fed67843 René Nussbaumer
    if not args:
577 fed67843 René Nussbaumer
      ToStderr("Please provide at least one node for this command")
578 c832b6c8 René Nussbaumer
      return constants.EXIT_FAILURE
579 fed67843 René Nussbaumer
    elif not opts.force and not ConfirmOperation(args, "nodes",
580 c832b6c8 René Nussbaumer
                                                 "power %s" % command):
581 c832b6c8 René Nussbaumer
      return constants.EXIT_FAILURE
582 fed67843 René Nussbaumer
    assert len(args) > 0
583 c832b6c8 René Nussbaumer
584 d363797e René Nussbaumer
  opcodelist = []
585 efae0fdd René Nussbaumer
  if not opts.ignore_status and oob_command == constants.OOB_POWER_OFF:
586 c832b6c8 René Nussbaumer
    # TODO: This is a little ugly as we can't catch and revert
587 fed67843 René Nussbaumer
    for node in args:
588 c832b6c8 René Nussbaumer
      opcodelist.append(opcodes.OpNodeSetParams(node_name=node, offline=True,
589 c832b6c8 René Nussbaumer
                                                auto_promote=opts.auto_promote))
590 d363797e René Nussbaumer
591 fed67843 René Nussbaumer
  opcodelist.append(opcodes.OpOobCommand(node_names=args,
592 efae0fdd René Nussbaumer
                                         command=oob_command,
593 efae0fdd René Nussbaumer
                                         ignore_status=opts.ignore_status,
594 0a1fc31c René Nussbaumer
                                         timeout=opts.oob_timeout,
595 0a1fc31c René Nussbaumer
                                         power_delay=opts.power_delay))
596 d363797e René Nussbaumer
597 d363797e René Nussbaumer
  cli.SetGenericOpcodeOpts(opcodelist, opts)
598 d363797e René Nussbaumer
599 d363797e René Nussbaumer
  job_id = cli.SendJob(opcodelist)
600 d363797e René Nussbaumer
601 d363797e René Nussbaumer
  # We just want the OOB Opcode status
602 d363797e René Nussbaumer
  # If it fails PollJob gives us the error message in it
603 d363797e René Nussbaumer
  result = cli.PollJob(job_id)[-1]
604 d363797e René Nussbaumer
605 c832b6c8 René Nussbaumer
  errs = 0
606 c832b6c8 René Nussbaumer
  data = []
607 c832b6c8 René Nussbaumer
  for node_result in result:
608 c832b6c8 René Nussbaumer
    (node_tuple, data_tuple) = node_result
609 c832b6c8 René Nussbaumer
    (_, node_name) = node_tuple
610 c832b6c8 René Nussbaumer
    (data_status, data_node) = data_tuple
611 c832b6c8 René Nussbaumer
    if data_status == constants.RS_NORMAL:
612 b04808ea René Nussbaumer
      if oob_command == constants.OOB_POWER_STATUS:
613 c832b6c8 René Nussbaumer
        if data_node[constants.OOB_POWER_STATUS_POWERED]:
614 c832b6c8 René Nussbaumer
          text = "powered"
615 b04808ea René Nussbaumer
        else:
616 c832b6c8 René Nussbaumer
          text = "unpowered"
617 c832b6c8 René Nussbaumer
        data.append([node_name, text])
618 c832b6c8 René Nussbaumer
      else:
619 c832b6c8 René Nussbaumer
        # We don't expect data here, so we just say, it was successfully invoked
620 c832b6c8 René Nussbaumer
        data.append([node_name, "invoked"])
621 c832b6c8 René Nussbaumer
    else:
622 c832b6c8 René Nussbaumer
      errs += 1
623 f2c6673d Michael Hanselmann
      data.append([node_name, cli.FormatResultError(data_status, True)])
624 c832b6c8 René Nussbaumer
625 c832b6c8 René Nussbaumer
  data = GenerateTable(separator=opts.separator, headers=headers,
626 c832b6c8 René Nussbaumer
                       fields=["node", "status"], data=data)
627 c832b6c8 René Nussbaumer
628 c832b6c8 René Nussbaumer
  for line in data:
629 c832b6c8 René Nussbaumer
    ToStdout(line)
630 abefdcff René Nussbaumer
631 c832b6c8 René Nussbaumer
  if errs:
632 c832b6c8 René Nussbaumer
    return constants.EXIT_FAILURE
633 c832b6c8 René Nussbaumer
  else:
634 c832b6c8 René Nussbaumer
    return constants.EXIT_SUCCESS
635 abefdcff René Nussbaumer
636 abefdcff René Nussbaumer
637 a0724772 René Nussbaumer
def Health(opts, args):
638 a0724772 René Nussbaumer
  """Show health of a node using OOB.
639 a0724772 René Nussbaumer

640 a0724772 René Nussbaumer
  @param opts: the command line options selected by the user
641 a0724772 René Nussbaumer
  @type args: list
642 a0724772 René Nussbaumer
  @param args: should contain only one element, the name of
643 a0724772 René Nussbaumer
      the node to be removed
644 a0724772 René Nussbaumer
  @rtype: int
645 a0724772 René Nussbaumer
  @return: the desired exit code
646 a0724772 René Nussbaumer

647 a0724772 René Nussbaumer
  """
648 65a77fab René Nussbaumer
  op = opcodes.OpOobCommand(node_names=args, command=constants.OOB_HEALTH,
649 65a77fab René Nussbaumer
                            timeout=opts.oob_timeout)
650 a0724772 René Nussbaumer
  result = SubmitOpCode(op, opts=opts)
651 a0724772 René Nussbaumer
652 a0724772 René Nussbaumer
  if opts.no_headers:
653 a0724772 René Nussbaumer
    headers = None
654 a0724772 René Nussbaumer
  else:
655 a0724772 René Nussbaumer
    headers = {"node": "Node", "status": "Status"}
656 a0724772 René Nussbaumer
657 a0724772 René Nussbaumer
  errs = 0
658 a0724772 René Nussbaumer
  data = []
659 a0724772 René Nussbaumer
  for node_result in result:
660 a0724772 René Nussbaumer
    (node_tuple, data_tuple) = node_result
661 a0724772 René Nussbaumer
    (_, node_name) = node_tuple
662 a0724772 René Nussbaumer
    (data_status, data_node) = data_tuple
663 a0724772 René Nussbaumer
    if data_status == constants.RS_NORMAL:
664 a0724772 René Nussbaumer
      data.append([node_name, "%s=%s" % tuple(data_node[0])])
665 a0724772 René Nussbaumer
      for item, status in data_node[1:]:
666 a0724772 René Nussbaumer
        data.append(["", "%s=%s" % (item, status)])
667 a0724772 René Nussbaumer
    else:
668 a0724772 René Nussbaumer
      errs += 1
669 f2c6673d Michael Hanselmann
      data.append([node_name, cli.FormatResultError(data_status, True)])
670 a0724772 René Nussbaumer
671 a0724772 René Nussbaumer
  data = GenerateTable(separator=opts.separator, headers=headers,
672 a0724772 René Nussbaumer
                       fields=["node", "status"], data=data)
673 a0724772 René Nussbaumer
674 a0724772 René Nussbaumer
  for line in data:
675 a0724772 René Nussbaumer
    ToStdout(line)
676 a0724772 René Nussbaumer
677 a0724772 René Nussbaumer
  if errs:
678 a0724772 René Nussbaumer
    return constants.EXIT_FAILURE
679 a0724772 René Nussbaumer
  else:
680 a0724772 René Nussbaumer
    return constants.EXIT_SUCCESS
681 a0724772 René Nussbaumer
682 a0724772 René Nussbaumer
683 dcb93971 Michael Hanselmann
def ListVolumes(opts, args):
684 dcb93971 Michael Hanselmann
  """List logical volumes on node(s).
685 dcb93971 Michael Hanselmann

686 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
687 ebf366ee Iustin Pop
  @type args: list
688 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
689 ebf366ee Iustin Pop
      we list data for all nodes, or contain a list of nodes
690 ebf366ee Iustin Pop
      to display data only for those
691 ebf366ee Iustin Pop
  @rtype: int
692 ebf366ee Iustin Pop
  @return: the desired exit code
693 ebf366ee Iustin Pop

694 dcb93971 Michael Hanselmann
  """
695 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_VOL_DEF_FIELDS)
696 dcb93971 Michael Hanselmann
697 8ed55bfd Iustin Pop
  op = opcodes.OpNodeQueryvols(nodes=args, output_fields=selected_fields)
698 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
699 dcb93971 Michael Hanselmann
700 dcb93971 Michael Hanselmann
  if not opts.no_headers:
701 137161c9 Michael Hanselmann
    headers = {"node": "Node", "phys": "PhysDev",
702 137161c9 Michael Hanselmann
               "vg": "VG", "name": "Name",
703 137161c9 Michael Hanselmann
               "size": "Size", "instance": "Instance"}
704 137161c9 Michael Hanselmann
  else:
705 137161c9 Michael Hanselmann
    headers = None
706 137161c9 Michael Hanselmann
707 9fbfbb7b Iustin Pop
  unitfields = ["size"]
708 137161c9 Michael Hanselmann
709 137161c9 Michael Hanselmann
  numfields = ["size"]
710 137161c9 Michael Hanselmann
711 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
712 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
713 9fbfbb7b Iustin Pop
                       numfields=numfields, data=output, units=opts.units)
714 16be8703 Iustin Pop
715 16be8703 Iustin Pop
  for line in data:
716 3a24c527 Iustin Pop
    ToStdout(line)
717 dcb93971 Michael Hanselmann
718 dcb93971 Michael Hanselmann
  return 0
719 dcb93971 Michael Hanselmann
720 dcb93971 Michael Hanselmann
721 9b94905f Iustin Pop
def ListStorage(opts, args):
722 4007f57d Michael Hanselmann
  """List physical volumes on node(s).
723 4007f57d Michael Hanselmann

724 4007f57d Michael Hanselmann
  @param opts: the command line options selected by the user
725 4007f57d Michael Hanselmann
  @type args: list
726 4007f57d Michael Hanselmann
  @param args: should either be an empty list, in which case
727 4007f57d Michael Hanselmann
      we list data for all nodes, or contain a list of nodes
728 4007f57d Michael Hanselmann
      to display data only for those
729 4007f57d Michael Hanselmann
  @rtype: int
730 4007f57d Michael Hanselmann
  @return: the desired exit code
731 4007f57d Michael Hanselmann

732 4007f57d Michael Hanselmann
  """
733 53548798 Michael Hanselmann
  # TODO: Default to ST_FILE if LVM is disabled on the cluster
734 53548798 Michael Hanselmann
  if opts.user_storage_type is None:
735 53548798 Michael Hanselmann
    opts.user_storage_type = constants.ST_LVM_PV
736 53548798 Michael Hanselmann
737 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(opts.user_storage_type)
738 53548798 Michael Hanselmann
739 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_STOR_DEF_FIELDS)
740 4007f57d Michael Hanselmann
741 ad8d0595 Iustin Pop
  op = opcodes.OpNodeQueryStorage(nodes=args,
742 53548798 Michael Hanselmann
                                  storage_type=storage_type,
743 4007f57d Michael Hanselmann
                                  output_fields=selected_fields)
744 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
745 4007f57d Michael Hanselmann
746 4007f57d Michael Hanselmann
  if not opts.no_headers:
747 4007f57d Michael Hanselmann
    headers = {
748 620a85fd Iustin Pop
      constants.SF_NODE: "Node",
749 620a85fd Iustin Pop
      constants.SF_TYPE: "Type",
750 4007f57d Michael Hanselmann
      constants.SF_NAME: "Name",
751 4007f57d Michael Hanselmann
      constants.SF_SIZE: "Size",
752 4007f57d Michael Hanselmann
      constants.SF_USED: "Used",
753 4007f57d Michael Hanselmann
      constants.SF_FREE: "Free",
754 4007f57d Michael Hanselmann
      constants.SF_ALLOCATABLE: "Allocatable",
755 4007f57d Michael Hanselmann
      }
756 4007f57d Michael Hanselmann
  else:
757 4007f57d Michael Hanselmann
    headers = None
758 4007f57d Michael Hanselmann
759 4007f57d Michael Hanselmann
  unitfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
760 4007f57d Michael Hanselmann
  numfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
761 4007f57d Michael Hanselmann
762 dc09c3cf Iustin Pop
  # change raw values to nicer strings
763 dc09c3cf Iustin Pop
  for row in output:
764 dc09c3cf Iustin Pop
    for idx, field in enumerate(selected_fields):
765 dc09c3cf Iustin Pop
      val = row[idx]
766 dc09c3cf Iustin Pop
      if field == constants.SF_ALLOCATABLE:
767 dc09c3cf Iustin Pop
        if val:
768 dc09c3cf Iustin Pop
          val = "Y"
769 dc09c3cf Iustin Pop
        else:
770 dc09c3cf Iustin Pop
          val = "N"
771 dc09c3cf Iustin Pop
      row[idx] = str(val)
772 dc09c3cf Iustin Pop
773 4007f57d Michael Hanselmann
  data = GenerateTable(separator=opts.separator, headers=headers,
774 4007f57d Michael Hanselmann
                       fields=selected_fields, unitfields=unitfields,
775 4007f57d Michael Hanselmann
                       numfields=numfields, data=output, units=opts.units)
776 4007f57d Michael Hanselmann
777 4007f57d Michael Hanselmann
  for line in data:
778 4007f57d Michael Hanselmann
    ToStdout(line)
779 4007f57d Michael Hanselmann
780 4007f57d Michael Hanselmann
  return 0
781 4007f57d Michael Hanselmann
782 4007f57d Michael Hanselmann
783 9b94905f Iustin Pop
def ModifyStorage(opts, args):
784 0e89fc2d Michael Hanselmann
  """Modify storage volume on a node.
785 0e89fc2d Michael Hanselmann

786 0e89fc2d Michael Hanselmann
  @param opts: the command line options selected by the user
787 0e89fc2d Michael Hanselmann
  @type args: list
788 0e89fc2d Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
789 0e89fc2d Michael Hanselmann
  @rtype: int
790 0e89fc2d Michael Hanselmann
  @return: the desired exit code
791 0e89fc2d Michael Hanselmann

792 0e89fc2d Michael Hanselmann
  """
793 0e89fc2d Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
794 0e89fc2d Michael Hanselmann
795 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
796 0e89fc2d Michael Hanselmann
797 0e89fc2d Michael Hanselmann
  changes = {}
798 0e89fc2d Michael Hanselmann
799 0e89fc2d Michael Hanselmann
  if opts.allocatable is not None:
800 e7b61bb0 Iustin Pop
    changes[constants.SF_ALLOCATABLE] = opts.allocatable
801 0e89fc2d Michael Hanselmann
802 0e89fc2d Michael Hanselmann
  if changes:
803 2cee4077 Iustin Pop
    op = opcodes.OpNodeModifyStorage(node_name=node_name,
804 0e89fc2d Michael Hanselmann
                                     storage_type=storage_type,
805 0e89fc2d Michael Hanselmann
                                     name=volume_name,
806 0e89fc2d Michael Hanselmann
                                     changes=changes)
807 c5a66db3 Michael Hanselmann
    SubmitOrSend(op, opts)
808 620a85fd Iustin Pop
  else:
809 620a85fd Iustin Pop
    ToStderr("No changes to perform, exiting.")
810 0e89fc2d Michael Hanselmann
811 0e89fc2d Michael Hanselmann
812 9b94905f Iustin Pop
def RepairStorage(opts, args):
813 1e3463f1 Michael Hanselmann
  """Repairs a storage volume on a node.
814 1e3463f1 Michael Hanselmann

815 1e3463f1 Michael Hanselmann
  @param opts: the command line options selected by the user
816 1e3463f1 Michael Hanselmann
  @type args: list
817 1e3463f1 Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
818 1e3463f1 Michael Hanselmann
  @rtype: int
819 1e3463f1 Michael Hanselmann
  @return: the desired exit code
820 1e3463f1 Michael Hanselmann

821 1e3463f1 Michael Hanselmann
  """
822 1e3463f1 Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
823 1e3463f1 Michael Hanselmann
824 1e3463f1 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
825 1e3463f1 Michael Hanselmann
826 1e3463f1 Michael Hanselmann
  op = opcodes.OpRepairNodeStorage(node_name=node_name,
827 1e3463f1 Michael Hanselmann
                                   storage_type=storage_type,
828 7e9c6a78 Iustin Pop
                                   name=volume_name,
829 7e9c6a78 Iustin Pop
                                   ignore_consistency=opts.ignore_consistency)
830 c5a66db3 Michael Hanselmann
  SubmitOrSend(op, opts)
831 1e3463f1 Michael Hanselmann
832 1e3463f1 Michael Hanselmann
833 b31c8676 Iustin Pop
def SetNodeParams(opts, args):
834 b31c8676 Iustin Pop
  """Modifies a node.
835 b31c8676 Iustin Pop

836 b31c8676 Iustin Pop
  @param opts: the command line options selected by the user
837 b31c8676 Iustin Pop
  @type args: list
838 b31c8676 Iustin Pop
  @param args: should contain only one element, the node name
839 b31c8676 Iustin Pop
  @rtype: int
840 b31c8676 Iustin Pop
  @return: the desired exit code
841 b31c8676 Iustin Pop

842 b31c8676 Iustin Pop
  """
843 53919782 Iustin Pop
  all_changes = [opts.master_candidate, opts.drained, opts.offline,
844 4e37f591 René Nussbaumer
                 opts.master_capable, opts.vm_capable, opts.secondary_ip,
845 4e37f591 René Nussbaumer
                 opts.ndparams]
846 0ec2ce46 René Nussbaumer
  if (all_changes.count(None) == len(all_changes) and
847 0ec2ce46 René Nussbaumer
      not (opts.hv_state or opts.disk_state)):
848 b31c8676 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
849 b31c8676 Iustin Pop
    return 1
850 b31c8676 Iustin Pop
851 0ec2ce46 René Nussbaumer
  if opts.disk_state:
852 0ec2ce46 René Nussbaumer
    disk_state = utils.FlatToDict(opts.disk_state)
853 0ec2ce46 René Nussbaumer
  else:
854 0ec2ce46 René Nussbaumer
    disk_state = {}
855 0ec2ce46 René Nussbaumer
856 0ec2ce46 René Nussbaumer
  hv_state = dict(opts.hv_state)
857 0ec2ce46 René Nussbaumer
858 f13973c4 Iustin Pop
  op = opcodes.OpNodeSetParams(node_name=args[0],
859 e7b61bb0 Iustin Pop
                               master_candidate=opts.master_candidate,
860 e7b61bb0 Iustin Pop
                               offline=opts.offline,
861 e7b61bb0 Iustin Pop
                               drained=opts.drained,
862 f91e255a Iustin Pop
                               master_capable=opts.master_capable,
863 53919782 Iustin Pop
                               vm_capable=opts.vm_capable,
864 4d32c211 Guido Trotter
                               secondary_ip=opts.secondary_ip,
865 4c61d894 Iustin Pop
                               force=opts.force,
866 4e37f591 René Nussbaumer
                               ndparams=opts.ndparams,
867 dd94e9f6 René Nussbaumer
                               auto_promote=opts.auto_promote,
868 0ec2ce46 René Nussbaumer
                               powered=opts.node_powered,
869 0ec2ce46 René Nussbaumer
                               hv_state=hv_state,
870 0ec2ce46 René Nussbaumer
                               disk_state=disk_state)
871 b31c8676 Iustin Pop
872 b31c8676 Iustin Pop
  # even if here we process the result, we allow submit only
873 b31c8676 Iustin Pop
  result = SubmitOrSend(op, opts)
874 b31c8676 Iustin Pop
875 b31c8676 Iustin Pop
  if result:
876 b31c8676 Iustin Pop
    ToStdout("Modified node %s", args[0])
877 b31c8676 Iustin Pop
    for param, data in result:
878 b31c8676 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
879 b31c8676 Iustin Pop
  return 0
880 b31c8676 Iustin Pop
881 b31c8676 Iustin Pop
882 7acbda7b Iustin Pop
class ReplyStatus(object):
883 7acbda7b Iustin Pop
  """Class holding a reply status for synchronous confd clients.
884 7acbda7b Iustin Pop

885 7acbda7b Iustin Pop
  """
886 7acbda7b Iustin Pop
  def __init__(self):
887 7acbda7b Iustin Pop
    self.failure = True
888 7acbda7b Iustin Pop
    self.answer = False
889 7acbda7b Iustin Pop
890 7acbda7b Iustin Pop
891 7acbda7b Iustin Pop
def ListDrbd(opts, args):
892 7acbda7b Iustin Pop
  """Modifies a node.
893 7acbda7b Iustin Pop

894 7acbda7b Iustin Pop
  @param opts: the command line options selected by the user
895 7acbda7b Iustin Pop
  @type args: list
896 7acbda7b Iustin Pop
  @param args: should contain only one element, the node name
897 7acbda7b Iustin Pop
  @rtype: int
898 7acbda7b Iustin Pop
  @return: the desired exit code
899 7acbda7b Iustin Pop

900 7acbda7b Iustin Pop
  """
901 7acbda7b Iustin Pop
  if len(args) != 1:
902 7acbda7b Iustin Pop
    ToStderr("Please give one (and only one) node.")
903 7acbda7b Iustin Pop
    return constants.EXIT_FAILURE
904 7acbda7b Iustin Pop
905 7acbda7b Iustin Pop
  if not constants.ENABLE_CONFD:
906 7acbda7b Iustin Pop
    ToStderr("Error: this command requires confd support, but it has not"
907 7acbda7b Iustin Pop
             " been enabled at build time.")
908 7acbda7b Iustin Pop
    return constants.EXIT_FAILURE
909 7acbda7b Iustin Pop
910 7acbda7b Iustin Pop
  if not constants.HS_CONFD:
911 7acbda7b Iustin Pop
    ToStderr("Error: this command requires the Haskell version of confd,"
912 7acbda7b Iustin Pop
             " but it has not been enabled at build time.")
913 7acbda7b Iustin Pop
    return constants.EXIT_FAILURE
914 7acbda7b Iustin Pop
915 7acbda7b Iustin Pop
  status = ReplyStatus()
916 7acbda7b Iustin Pop
917 7acbda7b Iustin Pop
  def ListDrbdConfdCallback(reply):
918 7acbda7b Iustin Pop
    """Callback for confd queries"""
919 7acbda7b Iustin Pop
    if reply.type == confd_client.UPCALL_REPLY:
920 7acbda7b Iustin Pop
      answer = reply.server_reply.answer
921 7acbda7b Iustin Pop
      reqtype = reply.orig_request.type
922 7acbda7b Iustin Pop
      if reqtype == constants.CONFD_REQ_NODE_DRBD:
923 7acbda7b Iustin Pop
        if reply.server_reply.status != constants.CONFD_REPL_STATUS_OK:
924 7acbda7b Iustin Pop
          ToStderr("Query gave non-ok status '%s': %s" %
925 7acbda7b Iustin Pop
                   (reply.server_reply.status,
926 7acbda7b Iustin Pop
                    reply.server_reply.answer))
927 7acbda7b Iustin Pop
          status.failure = True
928 7acbda7b Iustin Pop
          return
929 7acbda7b Iustin Pop
        if not confd.HTNodeDrbd(answer):
930 7acbda7b Iustin Pop
          ToStderr("Invalid response from server: expected %s, got %s",
931 7acbda7b Iustin Pop
                   confd.HTNodeDrbd, answer)
932 7acbda7b Iustin Pop
          status.failure = True
933 7acbda7b Iustin Pop
        else:
934 7acbda7b Iustin Pop
          status.failure = False
935 7acbda7b Iustin Pop
          status.answer = answer
936 7acbda7b Iustin Pop
      else:
937 7acbda7b Iustin Pop
        ToStderr("Unexpected reply %s!?", reqtype)
938 7acbda7b Iustin Pop
        status.failure = True
939 7acbda7b Iustin Pop
940 7acbda7b Iustin Pop
  node = args[0]
941 7acbda7b Iustin Pop
  hmac = utils.ReadFile(constants.CONFD_HMAC_KEY)
942 7acbda7b Iustin Pop
  filter_callback = confd_client.ConfdFilterCallback(ListDrbdConfdCallback)
943 7acbda7b Iustin Pop
  counting_callback = confd_client.ConfdCountingCallback(filter_callback)
944 7acbda7b Iustin Pop
  cf_client = confd_client.ConfdClient(hmac, [constants.IP4_ADDRESS_LOCALHOST],
945 7acbda7b Iustin Pop
                                       counting_callback)
946 7acbda7b Iustin Pop
  req = confd_client.ConfdClientRequest(type=constants.CONFD_REQ_NODE_DRBD,
947 7acbda7b Iustin Pop
                                        query=node)
948 7acbda7b Iustin Pop
949 7acbda7b Iustin Pop
  def DoConfdRequestReply(req):
950 7acbda7b Iustin Pop
    counting_callback.RegisterQuery(req.rsalt)
951 7acbda7b Iustin Pop
    cf_client.SendRequest(req, async=False)
952 7acbda7b Iustin Pop
    while not counting_callback.AllAnswered():
953 7acbda7b Iustin Pop
      if not cf_client.ReceiveReply():
954 7acbda7b Iustin Pop
        ToStderr("Did not receive all expected confd replies")
955 7acbda7b Iustin Pop
        break
956 7acbda7b Iustin Pop
957 7acbda7b Iustin Pop
  DoConfdRequestReply(req)
958 7acbda7b Iustin Pop
959 7acbda7b Iustin Pop
  if status.failure:
960 7acbda7b Iustin Pop
    return constants.EXIT_FAILURE
961 7acbda7b Iustin Pop
962 7acbda7b Iustin Pop
  fields = ["node", "minor", "instance", "disk", "role", "peer"]
963 2da31181 Iustin Pop
  if opts.no_headers:
964 2da31181 Iustin Pop
    headers = None
965 2da31181 Iustin Pop
  else:
966 2da31181 Iustin Pop
    headers = {"node": "Node", "minor": "Minor", "instance": "Instance",
967 2da31181 Iustin Pop
               "disk": "Disk", "role": "Role", "peer": "PeerNode"}
968 7acbda7b Iustin Pop
969 7acbda7b Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
970 7acbda7b Iustin Pop
                       fields=fields, data=sorted(status.answer),
971 7acbda7b Iustin Pop
                       numfields=["minor"])
972 7acbda7b Iustin Pop
  for line in data:
973 7acbda7b Iustin Pop
    ToStdout(line)
974 7acbda7b Iustin Pop
975 7acbda7b Iustin Pop
  return constants.EXIT_SUCCESS
976 7acbda7b Iustin Pop
977 a8083063 Iustin Pop
commands = {
978 d0c8c01d Iustin Pop
  "add": (
979 6ea815cf Iustin Pop
    AddNode, [ArgHost(min=1, max=1)],
980 61413377 Stephen Shirley
    [SECONDARY_IP_OPT, READD_OPT, NOSSH_KEYCHECK_OPT, NODE_FORCE_JOIN_OPT,
981 61413377 Stephen Shirley
     NONODE_SETUP_OPT, VERBOSE_OPT, NODEGROUP_OPT, PRIORITY_OPT,
982 085e0d9f René Nussbaumer
     CAPAB_MASTER_OPT, CAPAB_VM_OPT, NODE_PARAMS_OPT, HV_STATE_OPT,
983 085e0d9f René Nussbaumer
     DISK_STATE_OPT],
984 61413377 Stephen Shirley
    "[-s ip] [--readd] [--no-ssh-key-check] [--force-join]"
985 61413377 Stephen Shirley
    " [--no-node-setup] [--verbose]"
986 2e6469a1 René Nussbaumer
    " <node_name>",
987 6ea815cf Iustin Pop
    "Add a node to the cluster"),
988 aafee533 Michael Hanselmann
  "evacuate": (
989 aafee533 Michael Hanselmann
    EvacuateNode, ARGS_ONE_NODE,
990 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, IALLOCATOR_OPT, NEW_SECONDARY_OPT, EARLY_RELEASE_OPT,
991 c5a66db3 Michael Hanselmann
     PRIORITY_OPT, PRIMARY_ONLY_OPT, SECONDARY_ONLY_OPT, SUBMIT_OPT],
992 5ec23388 Iustin Pop
    "[-f] {-I <iallocator> | -n <dst>} [-p | -s] [options...] <node>",
993 f1dff7ec Iustin Pop
    "Relocate the primary and/or secondary instances from a node"),
994 d0c8c01d Iustin Pop
  "failover": (
995 1b7761fd Apollon Oikonomopoulos
    FailoverNode, ARGS_ONE_NODE, [FORCE_OPT, IGNORE_CONSIST_OPT,
996 1b7761fd Apollon Oikonomopoulos
                                  IALLOCATOR_OPT, PRIORITY_OPT],
997 6ea815cf Iustin Pop
    "[-f] <node>",
998 6ea815cf Iustin Pop
    "Stops the primary instances on a node and start them on their"
999 6ea815cf Iustin Pop
    " secondary node (only for instances with drbd disk template)"),
1000 d0c8c01d Iustin Pop
  "migrate": (
1001 aa06f8c6 Michael Hanselmann
    MigrateNode, ARGS_ONE_NODE,
1002 f8fa4175 Michael Hanselmann
    [FORCE_OPT, NONLIVE_OPT, MIGRATION_MODE_OPT, DST_NODE_OPT,
1003 8c0b16f6 Guido Trotter
     IALLOCATOR_OPT, PRIORITY_OPT, IGNORE_IPOLICY_OPT,
1004 c5a66db3 Michael Hanselmann
     NORUNTIME_CHGS_OPT, SUBMIT_OPT, PRIORITY_OPT],
1005 6ea815cf Iustin Pop
    "[-f] <node>",
1006 6ea815cf Iustin Pop
    "Migrate all the primary instance on a node away from it"
1007 6ea815cf Iustin Pop
    " (only for instances of type drbd)"),
1008 d0c8c01d Iustin Pop
  "info": (
1009 064c21f8 Iustin Pop
    ShowNodeConfig, ARGS_MANY_NODES, [],
1010 6ea815cf Iustin Pop
    "[<node_name>...]", "Show information about the node(s)"),
1011 d0c8c01d Iustin Pop
  "list": (
1012 6ea815cf Iustin Pop
    ListNodes, ARGS_MANY_NODES,
1013 2afd577f Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, VERBOSE_OPT,
1014 2afd577f Michael Hanselmann
     FORCE_FILTER_OPT],
1015 6ea815cf Iustin Pop
    "[nodes...]",
1016 7f5443a0 Michael Hanselmann
    "Lists the nodes in the cluster. The available fields can be shown using"
1017 7f5443a0 Michael Hanselmann
    " the \"list-fields\" command (see the man page for details)."
1018 7f5443a0 Michael Hanselmann
    " The default field list is (in order): %s." %
1019 7f5443a0 Michael Hanselmann
    utils.CommaJoin(_LIST_DEF_FIELDS)),
1020 7f5443a0 Michael Hanselmann
  "list-fields": (
1021 7f5443a0 Michael Hanselmann
    ListNodeFields, [ArgUnknown()],
1022 7f5443a0 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT],
1023 7f5443a0 Michael Hanselmann
    "[fields...]",
1024 7f5443a0 Michael Hanselmann
    "Lists all available fields for nodes"),
1025 d0c8c01d Iustin Pop
  "modify": (
1026 6ea815cf Iustin Pop
    SetNodeParams, ARGS_ONE_NODE,
1027 53919782 Iustin Pop
    [FORCE_OPT, SUBMIT_OPT, MC_OPT, DRAINED_OPT, OFFLINE_OPT,
1028 4d32c211 Guido Trotter
     CAPAB_MASTER_OPT, CAPAB_VM_OPT, SECONDARY_IP_OPT,
1029 dd94e9f6 René Nussbaumer
     AUTO_PROMOTE_OPT, DRY_RUN_OPT, PRIORITY_OPT, NODE_PARAMS_OPT,
1030 0ec2ce46 René Nussbaumer
     NODE_POWERED_OPT, HV_STATE_OPT, DISK_STATE_OPT],
1031 6ea815cf Iustin Pop
    "<node_name>", "Alters the parameters of a node"),
1032 d0c8c01d Iustin Pop
  "powercycle": (
1033 6ea815cf Iustin Pop
    PowercycleNode, ARGS_ONE_NODE,
1034 c5a66db3 Michael Hanselmann
    [FORCE_OPT, CONFIRM_OPT, DRY_RUN_OPT, PRIORITY_OPT, SUBMIT_OPT],
1035 6ea815cf Iustin Pop
    "<node_name>", "Tries to forcefully powercycle a node"),
1036 d0c8c01d Iustin Pop
  "power": (
1037 abefdcff René Nussbaumer
    PowerNode,
1038 abefdcff René Nussbaumer
    [ArgChoice(min=1, max=1, choices=_LIST_POWER_COMMANDS),
1039 c832b6c8 René Nussbaumer
     ArgNode()],
1040 efae0fdd René Nussbaumer
    [SUBMIT_OPT, AUTO_PROMOTE_OPT, PRIORITY_OPT, IGNORE_STATUS_OPT,
1041 0a1fc31c René Nussbaumer
     FORCE_OPT, NOHDR_OPT, SEP_OPT, OOB_TIMEOUT_OPT, POWER_DELAY_OPT],
1042 c832b6c8 René Nussbaumer
    "on|off|cycle|status [nodes...]",
1043 abefdcff René Nussbaumer
    "Change power state of node by calling out-of-band helper."),
1044 d0c8c01d Iustin Pop
  "remove": (
1045 aa06f8c6 Michael Hanselmann
    RemoveNode, ARGS_ONE_NODE, [DRY_RUN_OPT, PRIORITY_OPT],
1046 6ea815cf Iustin Pop
    "<node_name>", "Removes a node from the cluster"),
1047 d0c8c01d Iustin Pop
  "volumes": (
1048 6ea815cf Iustin Pop
    ListVolumes, [ArgNode()],
1049 aa06f8c6 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, PRIORITY_OPT],
1050 6ea815cf Iustin Pop
    "[<node_name>...]", "List logical volumes on node(s)"),
1051 d0c8c01d Iustin Pop
  "list-storage": (
1052 9b94905f Iustin Pop
    ListStorage, ARGS_MANY_NODES,
1053 aa06f8c6 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, _STORAGE_TYPE_OPT,
1054 aa06f8c6 Michael Hanselmann
     PRIORITY_OPT],
1055 620a85fd Iustin Pop
    "[<node_name>...]", "List physical volumes on node(s). The available"
1056 620a85fd Iustin Pop
    " fields are (see the man page for details): %s." %
1057 1f864b60 Iustin Pop
    (utils.CommaJoin(_LIST_STOR_HEADERS))),
1058 d0c8c01d Iustin Pop
  "modify-storage": (
1059 9b94905f Iustin Pop
    ModifyStorage,
1060 6ea815cf Iustin Pop
    [ArgNode(min=1, max=1),
1061 6ea815cf Iustin Pop
     ArgChoice(min=1, max=1, choices=_MODIFIABLE_STORAGE_TYPES),
1062 6ea815cf Iustin Pop
     ArgFile(min=1, max=1)],
1063 c5a66db3 Michael Hanselmann
    [ALLOCATABLE_OPT, DRY_RUN_OPT, PRIORITY_OPT, SUBMIT_OPT],
1064 064c21f8 Iustin Pop
    "<node_name> <storage_type> <name>", "Modify storage volume on a node"),
1065 d0c8c01d Iustin Pop
  "repair-storage": (
1066 9b94905f Iustin Pop
    RepairStorage,
1067 6ea815cf Iustin Pop
    [ArgNode(min=1, max=1),
1068 6ea815cf Iustin Pop
     ArgChoice(min=1, max=1, choices=_REPAIRABLE_STORAGE_TYPES),
1069 6ea815cf Iustin Pop
     ArgFile(min=1, max=1)],
1070 c5a66db3 Michael Hanselmann
    [IGNORE_CONSIST_OPT, DRY_RUN_OPT, PRIORITY_OPT, SUBMIT_OPT],
1071 6ea815cf Iustin Pop
    "<node_name> <storage_type> <name>",
1072 6ea815cf Iustin Pop
    "Repairs a storage volume on a node"),
1073 d0c8c01d Iustin Pop
  "list-tags": (
1074 064c21f8 Iustin Pop
    ListTags, ARGS_ONE_NODE, [],
1075 6ea815cf Iustin Pop
    "<node_name>", "List the tags of the given node"),
1076 d0c8c01d Iustin Pop
  "add-tags": (
1077 6bc3ed14 Michael Hanselmann
    AddTags, [ArgNode(min=1, max=1), ArgUnknown()],
1078 6bc3ed14 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
1079 6ea815cf Iustin Pop
    "<node_name> tag...", "Add tags to the given node"),
1080 d0c8c01d Iustin Pop
  "remove-tags": (
1081 aa06f8c6 Michael Hanselmann
    RemoveTags, [ArgNode(min=1, max=1), ArgUnknown()],
1082 6bc3ed14 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
1083 6ea815cf Iustin Pop
    "<node_name> tag...", "Remove tags from the given node"),
1084 a0724772 René Nussbaumer
  "health": (
1085 a0724772 René Nussbaumer
    Health, ARGS_MANY_NODES,
1086 6bc3ed14 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, PRIORITY_OPT, OOB_TIMEOUT_OPT],
1087 a0724772 René Nussbaumer
    "[<node_name>...]", "List health of node(s) using out-of-band"),
1088 7acbda7b Iustin Pop
  "list-drbd": (
1089 7acbda7b Iustin Pop
    ListDrbd, ARGS_ONE_NODE,
1090 7acbda7b Iustin Pop
    [NOHDR_OPT, SEP_OPT],
1091 7acbda7b Iustin Pop
    "[<node_name>]", "Query the list of used DRBD minors on the given node"),
1092 a8083063 Iustin Pop
  }
1093 a8083063 Iustin Pop
1094 96897af7 Alexander Schreiber
#: dictionary with aliases for commands
1095 96897af7 Alexander Schreiber
aliases = {
1096 96897af7 Alexander Schreiber
  "show": "info",
1097 96897af7 Alexander Schreiber
  }
1098 96897af7 Alexander Schreiber
1099 a8083063 Iustin Pop
1100 37494fa4 Michael Hanselmann
def Main():
1101 96897af7 Alexander Schreiber
  return GenericMain(commands, aliases=aliases,
1102 96897af7 Alexander Schreiber
                     override={"tag_type": constants.TAG_NODE},
1103 ef9fa5b9 René Nussbaumer
                     env_override=_ENV_OVERRIDE)