Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ 1fa2c40b

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

133 86f5eae3 Michael Hanselmann
  """
134 86f5eae3 Michael Hanselmann
  try:
135 86f5eae3 Michael Hanselmann
    return _USER_STORAGE_TYPE[user_storage_type]
136 86f5eae3 Michael Hanselmann
  except KeyError:
137 debac808 Iustin Pop
    raise errors.OpPrereqError("Unknown storage type: %s" % user_storage_type,
138 debac808 Iustin Pop
                               errors.ECODE_INVAL)
139 86f5eae3 Michael Hanselmann
140 86f5eae3 Michael Hanselmann
141 224ff0f7 Michael Hanselmann
def _TryReadFile(path):
142 224ff0f7 Michael Hanselmann
  """Tries to read a file.
143 2e6469a1 René Nussbaumer

144 224ff0f7 Michael Hanselmann
  If the file is not found, C{None} is returned.
145 224ff0f7 Michael Hanselmann

146 224ff0f7 Michael Hanselmann
  @type path: string
147 224ff0f7 Michael Hanselmann
  @param path: Filename
148 224ff0f7 Michael Hanselmann
  @rtype: None or string
149 224ff0f7 Michael Hanselmann
  @todo: Consider adding a generic ENOENT wrapper
150 224ff0f7 Michael Hanselmann

151 224ff0f7 Michael Hanselmann
  """
152 224ff0f7 Michael Hanselmann
  try:
153 224ff0f7 Michael Hanselmann
    return utils.ReadFile(path)
154 224ff0f7 Michael Hanselmann
  except EnvironmentError, err:
155 224ff0f7 Michael Hanselmann
    if err.errno == errno.ENOENT:
156 224ff0f7 Michael Hanselmann
      return None
157 224ff0f7 Michael Hanselmann
    else:
158 224ff0f7 Michael Hanselmann
      raise
159 224ff0f7 Michael Hanselmann
160 224ff0f7 Michael Hanselmann
161 224ff0f7 Michael Hanselmann
def _ReadSshKeys(keyfiles, _tostderr_fn=ToStderr):
162 224ff0f7 Michael Hanselmann
  """Reads SSH keys according to C{keyfiles}.
163 224ff0f7 Michael Hanselmann

164 224ff0f7 Michael Hanselmann
  @type keyfiles: dict
165 224ff0f7 Michael Hanselmann
  @param keyfiles: Dictionary with keys of L{constants.SSHK_ALL} and two-values
166 224ff0f7 Michael Hanselmann
    tuples (private and public key file)
167 224ff0f7 Michael Hanselmann
  @rtype: list
168 224ff0f7 Michael Hanselmann
  @return: List of three-values tuples (L{constants.SSHK_ALL}, private and
169 224ff0f7 Michael Hanselmann
    public key as strings)
170 2e6469a1 René Nussbaumer

171 2e6469a1 René Nussbaumer
  """
172 224ff0f7 Michael Hanselmann
  result = []
173 224ff0f7 Michael Hanselmann
174 224ff0f7 Michael Hanselmann
  for (kind, (private_file, public_file)) in keyfiles.items():
175 224ff0f7 Michael Hanselmann
    private_key = _TryReadFile(private_file)
176 224ff0f7 Michael Hanselmann
    public_key = _TryReadFile(public_file)
177 224ff0f7 Michael Hanselmann
178 224ff0f7 Michael Hanselmann
    if public_key and private_key:
179 224ff0f7 Michael Hanselmann
      result.append((kind, private_key, public_key))
180 224ff0f7 Michael Hanselmann
    elif public_key or private_key:
181 224ff0f7 Michael Hanselmann
      _tostderr_fn("Couldn't find a complete set of keys for kind '%s'; files"
182 224ff0f7 Michael Hanselmann
                   " '%s' and '%s'", kind, private_file, public_file)
183 224ff0f7 Michael Hanselmann
184 224ff0f7 Michael Hanselmann
  return result
185 224ff0f7 Michael Hanselmann
186 224ff0f7 Michael Hanselmann
187 224ff0f7 Michael Hanselmann
def _SetupSSH(options, cluster_name, node):
188 224ff0f7 Michael Hanselmann
  """Configures a destination node's SSH daemon.
189 f1bebf4c Iustin Pop

190 224ff0f7 Michael Hanselmann
  @param options: Command line options
191 224ff0f7 Michael Hanselmann
  @type cluster_name
192 224ff0f7 Michael Hanselmann
  @param cluster_name: Cluster name
193 224ff0f7 Michael Hanselmann
  @type node: string
194 224ff0f7 Michael Hanselmann
  @param node: Destination node name
195 f1bebf4c Iustin Pop

196 224ff0f7 Michael Hanselmann
  """
197 224ff0f7 Michael Hanselmann
  if options.force_join:
198 224ff0f7 Michael Hanselmann
    ToStderr("The \"--force-join\" option is no longer supported and will be"
199 224ff0f7 Michael Hanselmann
             " ignored.")
200 224ff0f7 Michael Hanselmann
201 224ff0f7 Michael Hanselmann
  cmd = [pathutils.PREPARE_NODE_JOIN]
202 2e6469a1 René Nussbaumer
203 224ff0f7 Michael Hanselmann
  # Pass --debug/--verbose to the external script if set on our invocation
204 2e6469a1 René Nussbaumer
  if options.debug:
205 2e6469a1 René Nussbaumer
    cmd.append("--debug")
206 224ff0f7 Michael Hanselmann
207 224ff0f7 Michael Hanselmann
  if options.verbose:
208 2e6469a1 René Nussbaumer
    cmd.append("--verbose")
209 2e6469a1 René Nussbaumer
210 224ff0f7 Michael Hanselmann
  host_keys = _ReadSshKeys(constants.SSH_DAEMON_KEYFILES)
211 224ff0f7 Michael Hanselmann
212 224ff0f7 Michael Hanselmann
  (_, root_keyfiles) = \
213 224ff0f7 Michael Hanselmann
    ssh.GetAllUserFiles(constants.SSH_LOGIN_USER, mkdir=False, dircheck=False)
214 224ff0f7 Michael Hanselmann
215 224ff0f7 Michael Hanselmann
  root_keys = _ReadSshKeys(root_keyfiles)
216 224ff0f7 Michael Hanselmann
217 224ff0f7 Michael Hanselmann
  (_, cert_pem) = \
218 224ff0f7 Michael Hanselmann
    utils.ExtractX509Certificate(utils.ReadFile(pathutils.NODED_CERT_FILE))
219 224ff0f7 Michael Hanselmann
220 224ff0f7 Michael Hanselmann
  data = {
221 224ff0f7 Michael Hanselmann
    constants.SSHS_CLUSTER_NAME: cluster_name,
222 224ff0f7 Michael Hanselmann
    constants.SSHS_NODE_DAEMON_CERTIFICATE: cert_pem,
223 224ff0f7 Michael Hanselmann
    constants.SSHS_SSH_HOST_KEY: host_keys,
224 224ff0f7 Michael Hanselmann
    constants.SSHS_SSH_ROOT_KEY: root_keys,
225 224ff0f7 Michael Hanselmann
    }
226 224ff0f7 Michael Hanselmann
227 224ff0f7 Michael Hanselmann
  srun = ssh.SshRunner(cluster_name)
228 224ff0f7 Michael Hanselmann
  scmd = srun.BuildCmd(node, constants.SSH_LOGIN_USER,
229 224ff0f7 Michael Hanselmann
                       utils.ShellQuoteArgs(cmd),
230 224ff0f7 Michael Hanselmann
                       batch=False, ask_key=options.ssh_key_check,
231 224ff0f7 Michael Hanselmann
                       strict_host_check=options.ssh_key_check, quiet=False,
232 224ff0f7 Michael Hanselmann
                       use_cluster_key=False)
233 224ff0f7 Michael Hanselmann
234 224ff0f7 Michael Hanselmann
  tempfh = tempfile.TemporaryFile()
235 224ff0f7 Michael Hanselmann
  try:
236 224ff0f7 Michael Hanselmann
    tempfh.write(serializer.DumpJson(data))
237 224ff0f7 Michael Hanselmann
    tempfh.seek(0)
238 2e6469a1 René Nussbaumer
239 224ff0f7 Michael Hanselmann
    result = utils.RunCmd(scmd, interactive=True, input_fd=tempfh)
240 224ff0f7 Michael Hanselmann
  finally:
241 224ff0f7 Michael Hanselmann
    tempfh.close()
242 2e6469a1 René Nussbaumer
243 2e6469a1 René Nussbaumer
  if result.failed:
244 224ff0f7 Michael Hanselmann
    raise errors.OpExecError("Command '%s' failed: %s" %
245 224ff0f7 Michael Hanselmann
                             (result.cmd, result.fail_reason))
246 2e6469a1 René Nussbaumer
247 2e6469a1 René Nussbaumer
248 4331f6cd Michael Hanselmann
@UsesRPC
249 a8083063 Iustin Pop
def AddNode(opts, args):
250 ebf366ee Iustin Pop
  """Add a node to the cluster.
251 ebf366ee Iustin Pop

252 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
253 ebf366ee Iustin Pop
  @type args: list
254 ebf366ee Iustin Pop
  @param args: should contain only one element, the new node name
255 ebf366ee Iustin Pop
  @rtype: int
256 ebf366ee Iustin Pop
  @return: the desired exit code
257 05ccd983 Guido Trotter

258 05ccd983 Guido Trotter
  """
259 87622829 Iustin Pop
  cl = GetClient()
260 b705c7a6 Manuel Franceschini
  node = netutils.GetHostname(name=args[0]).name
261 82e12743 Iustin Pop
  readd = opts.readd
262 82e12743 Iustin Pop
263 82e12743 Iustin Pop
  try:
264 d0c8c01d Iustin Pop
    output = cl.QueryNodes(names=[node], fields=["name", "sip", "master"],
265 77921a95 Iustin Pop
                           use_locking=False)
266 d833acc6 Iustin Pop
    node_exists, sip, is_master = output[0]
267 82e12743 Iustin Pop
  except (errors.OpPrereqError, errors.OpExecError):
268 82e12743 Iustin Pop
    node_exists = ""
269 82e12743 Iustin Pop
    sip = None
270 82e12743 Iustin Pop
271 82e12743 Iustin Pop
  if readd:
272 82e12743 Iustin Pop
    if not node_exists:
273 82e12743 Iustin Pop
      ToStderr("Node %s not in the cluster"
274 82e12743 Iustin Pop
               " - please retry without '--readd'", node)
275 82e12743 Iustin Pop
      return 1
276 d833acc6 Iustin Pop
    if is_master:
277 d833acc6 Iustin Pop
      ToStderr("Node %s is the master, cannot readd", node)
278 d833acc6 Iustin Pop
      return 1
279 82e12743 Iustin Pop
  else:
280 82e12743 Iustin Pop
    if node_exists:
281 3a24c527 Iustin Pop
      ToStderr("Node %s already in the cluster (as %s)"
282 82e12743 Iustin Pop
               " - please retry with '--readd'", node, node_exists)
283 05ccd983 Guido Trotter
      return 1
284 82e12743 Iustin Pop
    sip = opts.secondary_ip
285 05ccd983 Guido Trotter
286 87622829 Iustin Pop
  # read the cluster name from the master
287 224ff0f7 Michael Hanselmann
  (cluster_name, ) = cl.QueryConfigValues(["cluster_name"])
288 87622829 Iustin Pop
289 3ef51126 René Nussbaumer
  if not readd and opts.node_setup:
290 82e12743 Iustin Pop
    ToStderr("-- WARNING -- \n"
291 82e12743 Iustin Pop
             "Performing this operation is going to replace the ssh daemon"
292 82e12743 Iustin Pop
             " keypair\n"
293 82e12743 Iustin Pop
             "on the target machine (%s) with the ones of the"
294 82e12743 Iustin Pop
             " current one\n"
295 82e12743 Iustin Pop
             "and grant full intra-cluster ssh root access to/from it\n", node)
296 05ccd983 Guido Trotter
297 2e6469a1 René Nussbaumer
  if opts.node_setup:
298 224ff0f7 Michael Hanselmann
    _SetupSSH(opts, cluster_name, node)
299 827f753e Guido Trotter
300 3ef51126 René Nussbaumer
  bootstrap.SetupNodeDaemon(cluster_name, node, opts.ssh_key_check)
301 3ef51126 René Nussbaumer
302 085e0d9f René Nussbaumer
  if opts.disk_state:
303 085e0d9f René Nussbaumer
    disk_state = utils.FlatToDict(opts.disk_state)
304 085e0d9f René Nussbaumer
  else:
305 085e0d9f René Nussbaumer
    disk_state = {}
306 085e0d9f René Nussbaumer
307 085e0d9f René Nussbaumer
  hv_state = dict(opts.hv_state)
308 085e0d9f René Nussbaumer
309 d817d49f Iustin Pop
  op = opcodes.OpNodeAdd(node_name=args[0], secondary_ip=sip,
310 fd3d37b6 Iustin Pop
                         readd=opts.readd, group=opts.nodegroup,
311 4e37f591 René Nussbaumer
                         vm_capable=opts.vm_capable, ndparams=opts.ndparams,
312 085e0d9f René Nussbaumer
                         master_capable=opts.master_capable,
313 085e0d9f René Nussbaumer
                         disk_state=disk_state,
314 085e0d9f René Nussbaumer
                         hv_state=hv_state)
315 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
316 a8083063 Iustin Pop
317 a8083063 Iustin Pop
318 a8083063 Iustin Pop
def ListNodes(opts, args):
319 a8083063 Iustin Pop
  """List nodes and their properties.
320 a8083063 Iustin Pop

321 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
322 ebf366ee Iustin Pop
  @type args: list
323 982ed68e Adeodato Simo
  @param args: nodes to list, or empty for all
324 ebf366ee Iustin Pop
  @rtype: int
325 ebf366ee Iustin Pop
  @return: the desired exit code
326 ebf366ee Iustin Pop

327 a8083063 Iustin Pop
  """
328 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
329 a8083063 Iustin Pop
330 7f5443a0 Michael Hanselmann
  fmtoverride = dict.fromkeys(["pinst_list", "sinst_list", "tags"],
331 a36f605d Michael Hanselmann
                              (",".join, False))
332 a8083063 Iustin Pop
333 9fbf0098 Iustin Pop
  cl = GetClient(query=True)
334 9fbf0098 Iustin Pop
335 7f5443a0 Michael Hanselmann
  return GenericList(constants.QR_NODE, selected_fields, args, opts.units,
336 7f5443a0 Michael Hanselmann
                     opts.separator, not opts.no_headers,
337 2afd577f Michael Hanselmann
                     format_override=fmtoverride, verbose=opts.verbose,
338 9fbf0098 Iustin Pop
                     force_filter=opts.force_filter, cl=cl)
339 137161c9 Michael Hanselmann
340 137161c9 Michael Hanselmann
341 7f5443a0 Michael Hanselmann
def ListNodeFields(opts, args):
342 7f5443a0 Michael Hanselmann
  """List node fields.
343 ec223efb Iustin Pop

344 7f5443a0 Michael Hanselmann
  @param opts: the command line options selected by the user
345 7f5443a0 Michael Hanselmann
  @type args: list
346 7f5443a0 Michael Hanselmann
  @param args: fields to list, or empty for all
347 7f5443a0 Michael Hanselmann
  @rtype: int
348 7f5443a0 Michael Hanselmann
  @return: the desired exit code
349 a8083063 Iustin Pop

350 7f5443a0 Michael Hanselmann
  """
351 9fbf0098 Iustin Pop
  cl = GetClient(query=True)
352 9fbf0098 Iustin Pop
353 7f5443a0 Michael Hanselmann
  return GenericListFields(constants.QR_NODE, args, opts.separator,
354 9fbf0098 Iustin Pop
                           not opts.no_headers, cl=cl)
355 a8083063 Iustin Pop
356 a8083063 Iustin Pop
357 a5bc662a Iustin Pop
def EvacuateNode(opts, args):
358 a5bc662a Iustin Pop
  """Relocate all secondary instance from a node.
359 a5bc662a Iustin Pop

360 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
361 ebf366ee Iustin Pop
  @type args: list
362 ebf366ee Iustin Pop
  @param args: should be an empty list
363 ebf366ee Iustin Pop
  @rtype: int
364 ebf366ee Iustin Pop
  @return: the desired exit code
365 ebf366ee Iustin Pop

366 a5bc662a Iustin Pop
  """
367 aafee533 Michael Hanselmann
  if opts.dst_node is not None:
368 aafee533 Michael Hanselmann
    ToStderr("New secondary node given (disabling iallocator), hence evacuating"
369 aafee533 Michael Hanselmann
             " secondary instances only.")
370 aafee533 Michael Hanselmann
    opts.secondary_only = True
371 aafee533 Michael Hanselmann
    opts.primary_only = False
372 aafee533 Michael Hanselmann
373 aafee533 Michael Hanselmann
  if opts.secondary_only and opts.primary_only:
374 aafee533 Michael Hanselmann
    raise errors.OpPrereqError("Only one of the --primary-only and"
375 aafee533 Michael Hanselmann
                               " --secondary-only options can be passed",
376 aafee533 Michael Hanselmann
                               errors.ECODE_INVAL)
377 aafee533 Michael Hanselmann
  elif opts.primary_only:
378 cb92e7a1 Michael Hanselmann
    mode = constants.NODE_EVAC_PRI
379 aafee533 Michael Hanselmann
  elif opts.secondary_only:
380 cb92e7a1 Michael Hanselmann
    mode = constants.NODE_EVAC_SEC
381 aafee533 Michael Hanselmann
  else:
382 cb92e7a1 Michael Hanselmann
    mode = constants.NODE_EVAC_ALL
383 c4ed32cb Iustin Pop
384 aafee533 Michael Hanselmann
  # Determine affected instances
385 aafee533 Michael Hanselmann
  fields = []
386 c4ed32cb Iustin Pop
387 aafee533 Michael Hanselmann
  if not opts.secondary_only:
388 aafee533 Michael Hanselmann
    fields.append("pinst_list")
389 aafee533 Michael Hanselmann
  if not opts.primary_only:
390 aafee533 Michael Hanselmann
    fields.append("sinst_list")
391 f8c9fa5c Iustin Pop
392 aafee533 Michael Hanselmann
  cl = GetClient()
393 aafee533 Michael Hanselmann
394 9fbf0098 Iustin Pop
  qcl = GetClient(query=True)
395 9fbf0098 Iustin Pop
  result = qcl.QueryNodes(names=args, fields=fields, use_locking=False)
396 9fbf0098 Iustin Pop
  qcl.Close()
397 9fbf0098 Iustin Pop
398 aafee533 Michael Hanselmann
  instances = set(itertools.chain(*itertools.chain(*itertools.chain(result))))
399 aafee533 Michael Hanselmann
400 aafee533 Michael Hanselmann
  if not instances:
401 aafee533 Michael Hanselmann
    # No instances to evacuate
402 aafee533 Michael Hanselmann
    ToStderr("No instances to evacuate on node(s) %s, exiting.",
403 f8c9fa5c Iustin Pop
             utils.CommaJoin(args))
404 a5bc662a Iustin Pop
    return constants.EXIT_SUCCESS
405 a5bc662a Iustin Pop
406 aafee533 Michael Hanselmann
  if not (opts.force or
407 aafee533 Michael Hanselmann
          AskUser("Relocate instance(s) %s from node(s) %s?" %
408 aafee533 Michael Hanselmann
                  (utils.CommaJoin(utils.NiceSort(instances)),
409 aafee533 Michael Hanselmann
                   utils.CommaJoin(args)))):
410 a5bc662a Iustin Pop
    return constants.EXIT_CONFIRMATION
411 a5bc662a Iustin Pop
412 aafee533 Michael Hanselmann
  # Evacuate node
413 aafee533 Michael Hanselmann
  op = opcodes.OpNodeEvacuate(node_name=args[0], mode=mode,
414 aafee533 Michael Hanselmann
                              remote_node=opts.dst_node,
415 aafee533 Michael Hanselmann
                              iallocator=opts.iallocator,
416 aafee533 Michael Hanselmann
                              early_release=opts.early_release)
417 c5a66db3 Michael Hanselmann
  result = SubmitOrSend(op, opts, cl=cl)
418 aafee533 Michael Hanselmann
419 aafee533 Michael Hanselmann
  # Keep track of submitted jobs
420 f8c9fa5c Iustin Pop
  jex = JobExecutor(cl=cl, opts=opts)
421 aafee533 Michael Hanselmann
422 aafee533 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
423 aafee533 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
424 aafee533 Michael Hanselmann
425 f8c9fa5c Iustin Pop
  results = jex.GetResults()
426 f8c9fa5c Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
427 f8c9fa5c Iustin Pop
  if bad_cnt == 0:
428 aafee533 Michael Hanselmann
    ToStdout("All instances evacuated successfully.")
429 f8c9fa5c Iustin Pop
    rcode = constants.EXIT_SUCCESS
430 f8c9fa5c Iustin Pop
  else:
431 aafee533 Michael Hanselmann
    ToStdout("There were %s errors during the evacuation.", bad_cnt)
432 f8c9fa5c Iustin Pop
    rcode = constants.EXIT_FAILURE
433 aafee533 Michael Hanselmann
434 f8c9fa5c Iustin Pop
  return rcode
435 a5bc662a Iustin Pop
436 a5bc662a Iustin Pop
437 c450e9b0 Iustin Pop
def FailoverNode(opts, args):
438 c450e9b0 Iustin Pop
  """Failover all primary instance on a node.
439 c450e9b0 Iustin Pop

440 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
441 ebf366ee Iustin Pop
  @type args: list
442 ebf366ee Iustin Pop
  @param args: should be an empty list
443 ebf366ee Iustin Pop
  @rtype: int
444 ebf366ee Iustin Pop
  @return: the desired exit code
445 ebf366ee Iustin Pop

446 c450e9b0 Iustin Pop
  """
447 479636a3 Iustin Pop
  cl = GetClient()
448 c450e9b0 Iustin Pop
  force = opts.force
449 c450e9b0 Iustin Pop
  selected_fields = ["name", "pinst_list"]
450 c450e9b0 Iustin Pop
451 2e7b8369 Iustin Pop
  # these fields are static data anyway, so it doesn't matter, but
452 2e7b8369 Iustin Pop
  # locking=True should be safer
453 9fbf0098 Iustin Pop
  qcl = GetClient(query=True)
454 2e7b8369 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields,
455 77921a95 Iustin Pop
                         use_locking=False)
456 9fbf0098 Iustin Pop
  qcl.Close()
457 c450e9b0 Iustin Pop
  node, pinst = result[0]
458 c450e9b0 Iustin Pop
459 c450e9b0 Iustin Pop
  if not pinst:
460 3a24c527 Iustin Pop
    ToStderr("No primary instances on node %s, exiting.", node)
461 c450e9b0 Iustin Pop
    return 0
462 c450e9b0 Iustin Pop
463 c450e9b0 Iustin Pop
  pinst = utils.NiceSort(pinst)
464 c450e9b0 Iustin Pop
465 c450e9b0 Iustin Pop
  retcode = 0
466 c450e9b0 Iustin Pop
467 c450e9b0 Iustin Pop
  if not force and not AskUser("Fail over instance(s) %s?" %
468 c450e9b0 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
469 c450e9b0 Iustin Pop
    return 2
470 c450e9b0 Iustin Pop
471 cb573a31 Iustin Pop
  jex = JobExecutor(cl=cl, opts=opts)
472 c450e9b0 Iustin Pop
  for iname in pinst:
473 019dbee1 Iustin Pop
    op = opcodes.OpInstanceFailover(instance_name=iname,
474 1b7761fd Apollon Oikonomopoulos
                                    ignore_consistency=opts.ignore_consistency,
475 1b7761fd Apollon Oikonomopoulos
                                    iallocator=opts.iallocator)
476 479636a3 Iustin Pop
    jex.QueueJob(iname, op)
477 479636a3 Iustin Pop
  results = jex.GetResults()
478 479636a3 Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
479 479636a3 Iustin Pop
  if bad_cnt == 0:
480 479636a3 Iustin Pop
    ToStdout("All %d instance(s) failed over successfully.", len(results))
481 c450e9b0 Iustin Pop
  else:
482 3a24c527 Iustin Pop
    ToStdout("There were errors during the failover:\n"
483 479636a3 Iustin Pop
             "%d error(s) out of %d instance(s).", bad_cnt, len(results))
484 c450e9b0 Iustin Pop
  return retcode
485 c450e9b0 Iustin Pop
486 c450e9b0 Iustin Pop
487 40ef0ed6 Iustin Pop
def MigrateNode(opts, args):
488 40ef0ed6 Iustin Pop
  """Migrate all primary instance on a node.
489 40ef0ed6 Iustin Pop

490 40ef0ed6 Iustin Pop
  """
491 40ef0ed6 Iustin Pop
  cl = GetClient()
492 40ef0ed6 Iustin Pop
  force = opts.force
493 40ef0ed6 Iustin Pop
  selected_fields = ["name", "pinst_list"]
494 40ef0ed6 Iustin Pop
495 9fbf0098 Iustin Pop
  qcl = GetClient(query=True)
496 77921a95 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields, use_locking=False)
497 9fbf0098 Iustin Pop
  qcl.Close()
498 b7a1c816 Michael Hanselmann
  ((node, pinst), ) = result
499 40ef0ed6 Iustin Pop
500 40ef0ed6 Iustin Pop
  if not pinst:
501 40ef0ed6 Iustin Pop
    ToStdout("No primary instances on node %s, exiting." % node)
502 40ef0ed6 Iustin Pop
    return 0
503 40ef0ed6 Iustin Pop
504 40ef0ed6 Iustin Pop
  pinst = utils.NiceSort(pinst)
505 40ef0ed6 Iustin Pop
506 b7a1c816 Michael Hanselmann
  if not (force or
507 b7a1c816 Michael Hanselmann
          AskUser("Migrate instance(s) %s?" %
508 b7a1c816 Michael Hanselmann
                  utils.CommaJoin(utils.NiceSort(pinst)))):
509 b7a1c816 Michael Hanselmann
    return constants.EXIT_CONFIRMATION
510 40ef0ed6 Iustin Pop
511 e71b9ef4 Iustin Pop
  # this should be removed once --non-live is deprecated
512 783a6c0b Iustin Pop
  if not opts.live and opts.migration_mode is not None:
513 e71b9ef4 Iustin Pop
    raise errors.OpPrereqError("Only one of the --non-live and "
514 783a6c0b Iustin Pop
                               "--migration-mode options can be passed",
515 e71b9ef4 Iustin Pop
                               errors.ECODE_INVAL)
516 e71b9ef4 Iustin Pop
  if not opts.live: # --non-live passed
517 8c35561f Iustin Pop
    mode = constants.HT_MIGRATION_NONLIVE
518 e71b9ef4 Iustin Pop
  else:
519 8c35561f Iustin Pop
    mode = opts.migration_mode
520 b7a1c816 Michael Hanselmann
521 1b7761fd Apollon Oikonomopoulos
  op = opcodes.OpNodeMigrate(node_name=args[0], mode=mode,
522 f8fa4175 Michael Hanselmann
                             iallocator=opts.iallocator,
523 9fa567b3 René Nussbaumer
                             target_node=opts.dst_node,
524 8c0b16f6 Guido Trotter
                             allow_runtime_changes=opts.allow_runtime_chgs,
525 9fa567b3 René Nussbaumer
                             ignore_ipolicy=opts.ignore_ipolicy)
526 b7a1c816 Michael Hanselmann
527 c5a66db3 Michael Hanselmann
  result = SubmitOrSend(op, opts, cl=cl)
528 b7a1c816 Michael Hanselmann
529 b7a1c816 Michael Hanselmann
  # Keep track of submitted jobs
530 b7a1c816 Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
531 b7a1c816 Michael Hanselmann
532 b7a1c816 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
533 b7a1c816 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
534 b7a1c816 Michael Hanselmann
535 b7a1c816 Michael Hanselmann
  results = jex.GetResults()
536 b7a1c816 Michael Hanselmann
  bad_cnt = len([row for row in results if not row[0]])
537 b7a1c816 Michael Hanselmann
  if bad_cnt == 0:
538 b7a1c816 Michael Hanselmann
    ToStdout("All instances migrated successfully.")
539 b7a1c816 Michael Hanselmann
    rcode = constants.EXIT_SUCCESS
540 b7a1c816 Michael Hanselmann
  else:
541 b7a1c816 Michael Hanselmann
    ToStdout("There were %s errors during the node migration.", bad_cnt)
542 b7a1c816 Michael Hanselmann
    rcode = constants.EXIT_FAILURE
543 b7a1c816 Michael Hanselmann
544 b7a1c816 Michael Hanselmann
  return rcode
545 40ef0ed6 Iustin Pop
546 40ef0ed6 Iustin Pop
547 a8083063 Iustin Pop
def ShowNodeConfig(opts, args):
548 a8083063 Iustin Pop
  """Show node information.
549 a8083063 Iustin Pop

550 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
551 ebf366ee Iustin Pop
  @type args: list
552 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
553 ebf366ee Iustin Pop
      we show information about all nodes, or should contain
554 ebf366ee Iustin Pop
      a list of nodes to be queried for information
555 ebf366ee Iustin Pop
  @rtype: int
556 ebf366ee Iustin Pop
  @return: the desired exit code
557 ebf366ee Iustin Pop

558 a8083063 Iustin Pop
  """
559 9fbf0098 Iustin Pop
  cl = GetClient(query=True)
560 2e7b8369 Iustin Pop
  result = cl.QueryNodes(fields=["name", "pip", "sip",
561 0b2454b9 Iustin Pop
                                 "pinst_list", "sinst_list",
562 7b4978ad Iustin Pop
                                 "master_candidate", "drained", "offline",
563 8572f1fe René Nussbaumer
                                 "master_capable", "vm_capable", "powered",
564 8572f1fe René Nussbaumer
                                 "ndparams", "custom_ndparams"],
565 77921a95 Iustin Pop
                         names=args, use_locking=False)
566 a8083063 Iustin Pop
567 8572f1fe René Nussbaumer
  for (name, primary_ip, secondary_ip, pinst, sinst, is_mc, drained, offline,
568 8572f1fe René Nussbaumer
       master_capable, vm_capable, powered, ndparams,
569 8572f1fe René Nussbaumer
       ndparams_custom) in result:
570 3a24c527 Iustin Pop
    ToStdout("Node name: %s", name)
571 3a24c527 Iustin Pop
    ToStdout("  primary ip: %s", primary_ip)
572 3a24c527 Iustin Pop
    ToStdout("  secondary ip: %s", secondary_ip)
573 0b2454b9 Iustin Pop
    ToStdout("  master candidate: %s", is_mc)
574 0b2454b9 Iustin Pop
    ToStdout("  drained: %s", drained)
575 0b2454b9 Iustin Pop
    ToStdout("  offline: %s", offline)
576 016acd85 René Nussbaumer
    if powered is not None:
577 016acd85 René Nussbaumer
      ToStdout("  powered: %s", powered)
578 7b4978ad Iustin Pop
    ToStdout("  master_capable: %s", master_capable)
579 7b4978ad Iustin Pop
    ToStdout("  vm_capable: %s", vm_capable)
580 7b4978ad Iustin Pop
    if vm_capable:
581 7b4978ad Iustin Pop
      if pinst:
582 7b4978ad Iustin Pop
        ToStdout("  primary for instances:")
583 7b4978ad Iustin Pop
        for iname in utils.NiceSort(pinst):
584 7b4978ad Iustin Pop
          ToStdout("    - %s", iname)
585 7b4978ad Iustin Pop
      else:
586 7b4978ad Iustin Pop
        ToStdout("  primary for no instances")
587 7b4978ad Iustin Pop
      if sinst:
588 7b4978ad Iustin Pop
        ToStdout("  secondary for instances:")
589 7b4978ad Iustin Pop
        for iname in utils.NiceSort(sinst):
590 7b4978ad Iustin Pop
          ToStdout("    - %s", iname)
591 7b4978ad Iustin Pop
      else:
592 7b4978ad Iustin Pop
        ToStdout("  secondary for no instances")
593 8572f1fe René Nussbaumer
    ToStdout("  node parameters:")
594 8572f1fe René Nussbaumer
    buf = StringIO()
595 8572f1fe René Nussbaumer
    FormatParameterDict(buf, ndparams_custom, ndparams, level=2)
596 8572f1fe René Nussbaumer
    ToStdout(buf.getvalue().rstrip("\n"))
597 a8083063 Iustin Pop
598 a8083063 Iustin Pop
  return 0
599 a8083063 Iustin Pop
600 a8083063 Iustin Pop
601 a8083063 Iustin Pop
def RemoveNode(opts, args):
602 ebf366ee Iustin Pop
  """Remove a node from the cluster.
603 ebf366ee Iustin Pop

604 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
605 ebf366ee Iustin Pop
  @type args: list
606 ebf366ee Iustin Pop
  @param args: should contain only one element, the name of
607 ebf366ee Iustin Pop
      the node to be removed
608 ebf366ee Iustin Pop
  @rtype: int
609 ebf366ee Iustin Pop
  @return: the desired exit code
610 ebf366ee Iustin Pop

611 ebf366ee Iustin Pop
  """
612 73d565a3 Iustin Pop
  op = opcodes.OpNodeRemove(node_name=args[0])
613 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
614 ebf366ee Iustin Pop
  return 0
615 a8083063 Iustin Pop
616 a8083063 Iustin Pop
617 f5118ade Iustin Pop
def PowercycleNode(opts, args):
618 f5118ade Iustin Pop
  """Remove a node from the cluster.
619 f5118ade Iustin Pop

620 f5118ade Iustin Pop
  @param opts: the command line options selected by the user
621 f5118ade Iustin Pop
  @type args: list
622 f5118ade Iustin Pop
  @param args: should contain only one element, the name of
623 f5118ade Iustin Pop
      the node to be removed
624 f5118ade Iustin Pop
  @rtype: int
625 f5118ade Iustin Pop
  @return: the desired exit code
626 f5118ade Iustin Pop

627 f5118ade Iustin Pop
  """
628 f5118ade Iustin Pop
  node = args[0]
629 f5118ade Iustin Pop
  if (not opts.confirm and
630 f5118ade Iustin Pop
      not AskUser("Are you sure you want to hard powercycle node %s?" % node)):
631 f5118ade Iustin Pop
    return 2
632 f5118ade Iustin Pop
633 e0d4735f Iustin Pop
  op = opcodes.OpNodePowercycle(node_name=node, force=opts.force)
634 c5a66db3 Michael Hanselmann
  result = SubmitOrSend(op, opts)
635 48418fea Iustin Pop
  if result:
636 48418fea Iustin Pop
    ToStderr(result)
637 f5118ade Iustin Pop
  return 0
638 f5118ade Iustin Pop
639 f5118ade Iustin Pop
640 abefdcff René Nussbaumer
def PowerNode(opts, args):
641 abefdcff René Nussbaumer
  """Change/ask power state of a node.
642 abefdcff René Nussbaumer

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

650 abefdcff René Nussbaumer
  """
651 c832b6c8 René Nussbaumer
  command = args.pop(0)
652 c832b6c8 René Nussbaumer
653 c832b6c8 René Nussbaumer
  if opts.no_headers:
654 c832b6c8 René Nussbaumer
    headers = None
655 c832b6c8 René Nussbaumer
  else:
656 c832b6c8 René Nussbaumer
    headers = {"node": "Node", "status": "Status"}
657 abefdcff René Nussbaumer
658 abefdcff René Nussbaumer
  if command not in _LIST_POWER_COMMANDS:
659 abefdcff René Nussbaumer
    ToStderr("power subcommand %s not supported." % command)
660 abefdcff René Nussbaumer
    return constants.EXIT_FAILURE
661 abefdcff René Nussbaumer
662 abefdcff René Nussbaumer
  oob_command = "power-%s" % command
663 abefdcff René Nussbaumer
664 c832b6c8 René Nussbaumer
  if oob_command in _OOB_COMMAND_ASK:
665 fed67843 René Nussbaumer
    if not args:
666 fed67843 René Nussbaumer
      ToStderr("Please provide at least one node for this command")
667 c832b6c8 René Nussbaumer
      return constants.EXIT_FAILURE
668 fed67843 René Nussbaumer
    elif not opts.force and not ConfirmOperation(args, "nodes",
669 c832b6c8 René Nussbaumer
                                                 "power %s" % command):
670 c832b6c8 René Nussbaumer
      return constants.EXIT_FAILURE
671 fed67843 René Nussbaumer
    assert len(args) > 0
672 c832b6c8 René Nussbaumer
673 d363797e René Nussbaumer
  opcodelist = []
674 efae0fdd René Nussbaumer
  if not opts.ignore_status and oob_command == constants.OOB_POWER_OFF:
675 c832b6c8 René Nussbaumer
    # TODO: This is a little ugly as we can't catch and revert
676 fed67843 René Nussbaumer
    for node in args:
677 c832b6c8 René Nussbaumer
      opcodelist.append(opcodes.OpNodeSetParams(node_name=node, offline=True,
678 c832b6c8 René Nussbaumer
                                                auto_promote=opts.auto_promote))
679 d363797e René Nussbaumer
680 fed67843 René Nussbaumer
  opcodelist.append(opcodes.OpOobCommand(node_names=args,
681 efae0fdd René Nussbaumer
                                         command=oob_command,
682 efae0fdd René Nussbaumer
                                         ignore_status=opts.ignore_status,
683 0a1fc31c René Nussbaumer
                                         timeout=opts.oob_timeout,
684 0a1fc31c René Nussbaumer
                                         power_delay=opts.power_delay))
685 d363797e René Nussbaumer
686 d363797e René Nussbaumer
  cli.SetGenericOpcodeOpts(opcodelist, opts)
687 d363797e René Nussbaumer
688 d363797e René Nussbaumer
  job_id = cli.SendJob(opcodelist)
689 d363797e René Nussbaumer
690 d363797e René Nussbaumer
  # We just want the OOB Opcode status
691 d363797e René Nussbaumer
  # If it fails PollJob gives us the error message in it
692 d363797e René Nussbaumer
  result = cli.PollJob(job_id)[-1]
693 d363797e René Nussbaumer
694 c832b6c8 René Nussbaumer
  errs = 0
695 c832b6c8 René Nussbaumer
  data = []
696 c832b6c8 René Nussbaumer
  for node_result in result:
697 c832b6c8 René Nussbaumer
    (node_tuple, data_tuple) = node_result
698 c832b6c8 René Nussbaumer
    (_, node_name) = node_tuple
699 c832b6c8 René Nussbaumer
    (data_status, data_node) = data_tuple
700 c832b6c8 René Nussbaumer
    if data_status == constants.RS_NORMAL:
701 b04808ea René Nussbaumer
      if oob_command == constants.OOB_POWER_STATUS:
702 c832b6c8 René Nussbaumer
        if data_node[constants.OOB_POWER_STATUS_POWERED]:
703 c832b6c8 René Nussbaumer
          text = "powered"
704 b04808ea René Nussbaumer
        else:
705 c832b6c8 René Nussbaumer
          text = "unpowered"
706 c832b6c8 René Nussbaumer
        data.append([node_name, text])
707 c832b6c8 René Nussbaumer
      else:
708 c832b6c8 René Nussbaumer
        # We don't expect data here, so we just say, it was successfully invoked
709 c832b6c8 René Nussbaumer
        data.append([node_name, "invoked"])
710 c832b6c8 René Nussbaumer
    else:
711 c832b6c8 René Nussbaumer
      errs += 1
712 f2c6673d Michael Hanselmann
      data.append([node_name, cli.FormatResultError(data_status, True)])
713 c832b6c8 René Nussbaumer
714 c832b6c8 René Nussbaumer
  data = GenerateTable(separator=opts.separator, headers=headers,
715 c832b6c8 René Nussbaumer
                       fields=["node", "status"], data=data)
716 c832b6c8 René Nussbaumer
717 c832b6c8 René Nussbaumer
  for line in data:
718 c832b6c8 René Nussbaumer
    ToStdout(line)
719 abefdcff René Nussbaumer
720 c832b6c8 René Nussbaumer
  if errs:
721 c832b6c8 René Nussbaumer
    return constants.EXIT_FAILURE
722 c832b6c8 René Nussbaumer
  else:
723 c832b6c8 René Nussbaumer
    return constants.EXIT_SUCCESS
724 abefdcff René Nussbaumer
725 abefdcff René Nussbaumer
726 a0724772 René Nussbaumer
def Health(opts, args):
727 a0724772 René Nussbaumer
  """Show health of a node using OOB.
728 a0724772 René Nussbaumer

729 a0724772 René Nussbaumer
  @param opts: the command line options selected by the user
730 a0724772 René Nussbaumer
  @type args: list
731 a0724772 René Nussbaumer
  @param args: should contain only one element, the name of
732 a0724772 René Nussbaumer
      the node to be removed
733 a0724772 René Nussbaumer
  @rtype: int
734 a0724772 René Nussbaumer
  @return: the desired exit code
735 a0724772 René Nussbaumer

736 a0724772 René Nussbaumer
  """
737 65a77fab René Nussbaumer
  op = opcodes.OpOobCommand(node_names=args, command=constants.OOB_HEALTH,
738 65a77fab René Nussbaumer
                            timeout=opts.oob_timeout)
739 a0724772 René Nussbaumer
  result = SubmitOpCode(op, opts=opts)
740 a0724772 René Nussbaumer
741 a0724772 René Nussbaumer
  if opts.no_headers:
742 a0724772 René Nussbaumer
    headers = None
743 a0724772 René Nussbaumer
  else:
744 a0724772 René Nussbaumer
    headers = {"node": "Node", "status": "Status"}
745 a0724772 René Nussbaumer
746 a0724772 René Nussbaumer
  errs = 0
747 a0724772 René Nussbaumer
  data = []
748 a0724772 René Nussbaumer
  for node_result in result:
749 a0724772 René Nussbaumer
    (node_tuple, data_tuple) = node_result
750 a0724772 René Nussbaumer
    (_, node_name) = node_tuple
751 a0724772 René Nussbaumer
    (data_status, data_node) = data_tuple
752 a0724772 René Nussbaumer
    if data_status == constants.RS_NORMAL:
753 a0724772 René Nussbaumer
      data.append([node_name, "%s=%s" % tuple(data_node[0])])
754 a0724772 René Nussbaumer
      for item, status in data_node[1:]:
755 a0724772 René Nussbaumer
        data.append(["", "%s=%s" % (item, status)])
756 a0724772 René Nussbaumer
    else:
757 a0724772 René Nussbaumer
      errs += 1
758 f2c6673d Michael Hanselmann
      data.append([node_name, cli.FormatResultError(data_status, True)])
759 a0724772 René Nussbaumer
760 a0724772 René Nussbaumer
  data = GenerateTable(separator=opts.separator, headers=headers,
761 a0724772 René Nussbaumer
                       fields=["node", "status"], data=data)
762 a0724772 René Nussbaumer
763 a0724772 René Nussbaumer
  for line in data:
764 a0724772 René Nussbaumer
    ToStdout(line)
765 a0724772 René Nussbaumer
766 a0724772 René Nussbaumer
  if errs:
767 a0724772 René Nussbaumer
    return constants.EXIT_FAILURE
768 a0724772 René Nussbaumer
  else:
769 a0724772 René Nussbaumer
    return constants.EXIT_SUCCESS
770 a0724772 René Nussbaumer
771 a0724772 René Nussbaumer
772 dcb93971 Michael Hanselmann
def ListVolumes(opts, args):
773 dcb93971 Michael Hanselmann
  """List logical volumes on node(s).
774 dcb93971 Michael Hanselmann

775 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
776 ebf366ee Iustin Pop
  @type args: list
777 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
778 ebf366ee Iustin Pop
      we list data for all nodes, or contain a list of nodes
779 ebf366ee Iustin Pop
      to display data only for those
780 ebf366ee Iustin Pop
  @rtype: int
781 ebf366ee Iustin Pop
  @return: the desired exit code
782 ebf366ee Iustin Pop

783 dcb93971 Michael Hanselmann
  """
784 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_VOL_DEF_FIELDS)
785 dcb93971 Michael Hanselmann
786 8ed55bfd Iustin Pop
  op = opcodes.OpNodeQueryvols(nodes=args, output_fields=selected_fields)
787 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
788 dcb93971 Michael Hanselmann
789 dcb93971 Michael Hanselmann
  if not opts.no_headers:
790 137161c9 Michael Hanselmann
    headers = {"node": "Node", "phys": "PhysDev",
791 137161c9 Michael Hanselmann
               "vg": "VG", "name": "Name",
792 137161c9 Michael Hanselmann
               "size": "Size", "instance": "Instance"}
793 137161c9 Michael Hanselmann
  else:
794 137161c9 Michael Hanselmann
    headers = None
795 137161c9 Michael Hanselmann
796 9fbfbb7b Iustin Pop
  unitfields = ["size"]
797 137161c9 Michael Hanselmann
798 137161c9 Michael Hanselmann
  numfields = ["size"]
799 137161c9 Michael Hanselmann
800 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
801 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
802 9fbfbb7b Iustin Pop
                       numfields=numfields, data=output, units=opts.units)
803 16be8703 Iustin Pop
804 16be8703 Iustin Pop
  for line in data:
805 3a24c527 Iustin Pop
    ToStdout(line)
806 dcb93971 Michael Hanselmann
807 dcb93971 Michael Hanselmann
  return 0
808 dcb93971 Michael Hanselmann
809 dcb93971 Michael Hanselmann
810 9b94905f Iustin Pop
def ListStorage(opts, args):
811 4007f57d Michael Hanselmann
  """List physical volumes on node(s).
812 4007f57d Michael Hanselmann

813 4007f57d Michael Hanselmann
  @param opts: the command line options selected by the user
814 4007f57d Michael Hanselmann
  @type args: list
815 4007f57d Michael Hanselmann
  @param args: should either be an empty list, in which case
816 4007f57d Michael Hanselmann
      we list data for all nodes, or contain a list of nodes
817 4007f57d Michael Hanselmann
      to display data only for those
818 4007f57d Michael Hanselmann
  @rtype: int
819 4007f57d Michael Hanselmann
  @return: the desired exit code
820 4007f57d Michael Hanselmann

821 4007f57d Michael Hanselmann
  """
822 53548798 Michael Hanselmann
  # TODO: Default to ST_FILE if LVM is disabled on the cluster
823 53548798 Michael Hanselmann
  if opts.user_storage_type is None:
824 53548798 Michael Hanselmann
    opts.user_storage_type = constants.ST_LVM_PV
825 53548798 Michael Hanselmann
826 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(opts.user_storage_type)
827 53548798 Michael Hanselmann
828 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_STOR_DEF_FIELDS)
829 4007f57d Michael Hanselmann
830 ad8d0595 Iustin Pop
  op = opcodes.OpNodeQueryStorage(nodes=args,
831 53548798 Michael Hanselmann
                                  storage_type=storage_type,
832 4007f57d Michael Hanselmann
                                  output_fields=selected_fields)
833 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
834 4007f57d Michael Hanselmann
835 4007f57d Michael Hanselmann
  if not opts.no_headers:
836 4007f57d Michael Hanselmann
    headers = {
837 620a85fd Iustin Pop
      constants.SF_NODE: "Node",
838 620a85fd Iustin Pop
      constants.SF_TYPE: "Type",
839 4007f57d Michael Hanselmann
      constants.SF_NAME: "Name",
840 4007f57d Michael Hanselmann
      constants.SF_SIZE: "Size",
841 4007f57d Michael Hanselmann
      constants.SF_USED: "Used",
842 4007f57d Michael Hanselmann
      constants.SF_FREE: "Free",
843 4007f57d Michael Hanselmann
      constants.SF_ALLOCATABLE: "Allocatable",
844 4007f57d Michael Hanselmann
      }
845 4007f57d Michael Hanselmann
  else:
846 4007f57d Michael Hanselmann
    headers = None
847 4007f57d Michael Hanselmann
848 4007f57d Michael Hanselmann
  unitfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
849 4007f57d Michael Hanselmann
  numfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
850 4007f57d Michael Hanselmann
851 dc09c3cf Iustin Pop
  # change raw values to nicer strings
852 dc09c3cf Iustin Pop
  for row in output:
853 dc09c3cf Iustin Pop
    for idx, field in enumerate(selected_fields):
854 dc09c3cf Iustin Pop
      val = row[idx]
855 dc09c3cf Iustin Pop
      if field == constants.SF_ALLOCATABLE:
856 dc09c3cf Iustin Pop
        if val:
857 dc09c3cf Iustin Pop
          val = "Y"
858 dc09c3cf Iustin Pop
        else:
859 dc09c3cf Iustin Pop
          val = "N"
860 dc09c3cf Iustin Pop
      row[idx] = str(val)
861 dc09c3cf Iustin Pop
862 4007f57d Michael Hanselmann
  data = GenerateTable(separator=opts.separator, headers=headers,
863 4007f57d Michael Hanselmann
                       fields=selected_fields, unitfields=unitfields,
864 4007f57d Michael Hanselmann
                       numfields=numfields, data=output, units=opts.units)
865 4007f57d Michael Hanselmann
866 4007f57d Michael Hanselmann
  for line in data:
867 4007f57d Michael Hanselmann
    ToStdout(line)
868 4007f57d Michael Hanselmann
869 4007f57d Michael Hanselmann
  return 0
870 4007f57d Michael Hanselmann
871 4007f57d Michael Hanselmann
872 9b94905f Iustin Pop
def ModifyStorage(opts, args):
873 0e89fc2d Michael Hanselmann
  """Modify storage volume on a node.
874 0e89fc2d Michael Hanselmann

875 0e89fc2d Michael Hanselmann
  @param opts: the command line options selected by the user
876 0e89fc2d Michael Hanselmann
  @type args: list
877 0e89fc2d Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
878 0e89fc2d Michael Hanselmann
  @rtype: int
879 0e89fc2d Michael Hanselmann
  @return: the desired exit code
880 0e89fc2d Michael Hanselmann

881 0e89fc2d Michael Hanselmann
  """
882 0e89fc2d Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
883 0e89fc2d Michael Hanselmann
884 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
885 0e89fc2d Michael Hanselmann
886 0e89fc2d Michael Hanselmann
  changes = {}
887 0e89fc2d Michael Hanselmann
888 0e89fc2d Michael Hanselmann
  if opts.allocatable is not None:
889 e7b61bb0 Iustin Pop
    changes[constants.SF_ALLOCATABLE] = opts.allocatable
890 0e89fc2d Michael Hanselmann
891 0e89fc2d Michael Hanselmann
  if changes:
892 2cee4077 Iustin Pop
    op = opcodes.OpNodeModifyStorage(node_name=node_name,
893 0e89fc2d Michael Hanselmann
                                     storage_type=storage_type,
894 0e89fc2d Michael Hanselmann
                                     name=volume_name,
895 0e89fc2d Michael Hanselmann
                                     changes=changes)
896 c5a66db3 Michael Hanselmann
    SubmitOrSend(op, opts)
897 620a85fd Iustin Pop
  else:
898 620a85fd Iustin Pop
    ToStderr("No changes to perform, exiting.")
899 0e89fc2d Michael Hanselmann
900 0e89fc2d Michael Hanselmann
901 9b94905f Iustin Pop
def RepairStorage(opts, args):
902 1e3463f1 Michael Hanselmann
  """Repairs a storage volume on a node.
903 1e3463f1 Michael Hanselmann

904 1e3463f1 Michael Hanselmann
  @param opts: the command line options selected by the user
905 1e3463f1 Michael Hanselmann
  @type args: list
906 1e3463f1 Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
907 1e3463f1 Michael Hanselmann
  @rtype: int
908 1e3463f1 Michael Hanselmann
  @return: the desired exit code
909 1e3463f1 Michael Hanselmann

910 1e3463f1 Michael Hanselmann
  """
911 1e3463f1 Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
912 1e3463f1 Michael Hanselmann
913 1e3463f1 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
914 1e3463f1 Michael Hanselmann
915 1e3463f1 Michael Hanselmann
  op = opcodes.OpRepairNodeStorage(node_name=node_name,
916 1e3463f1 Michael Hanselmann
                                   storage_type=storage_type,
917 7e9c6a78 Iustin Pop
                                   name=volume_name,
918 7e9c6a78 Iustin Pop
                                   ignore_consistency=opts.ignore_consistency)
919 c5a66db3 Michael Hanselmann
  SubmitOrSend(op, opts)
920 1e3463f1 Michael Hanselmann
921 1e3463f1 Michael Hanselmann
922 b31c8676 Iustin Pop
def SetNodeParams(opts, args):
923 b31c8676 Iustin Pop
  """Modifies a node.
924 b31c8676 Iustin Pop

925 b31c8676 Iustin Pop
  @param opts: the command line options selected by the user
926 b31c8676 Iustin Pop
  @type args: list
927 b31c8676 Iustin Pop
  @param args: should contain only one element, the node name
928 b31c8676 Iustin Pop
  @rtype: int
929 b31c8676 Iustin Pop
  @return: the desired exit code
930 b31c8676 Iustin Pop

931 b31c8676 Iustin Pop
  """
932 53919782 Iustin Pop
  all_changes = [opts.master_candidate, opts.drained, opts.offline,
933 4e37f591 René Nussbaumer
                 opts.master_capable, opts.vm_capable, opts.secondary_ip,
934 4e37f591 René Nussbaumer
                 opts.ndparams]
935 0ec2ce46 René Nussbaumer
  if (all_changes.count(None) == len(all_changes) and
936 0ec2ce46 René Nussbaumer
      not (opts.hv_state or opts.disk_state)):
937 b31c8676 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
938 b31c8676 Iustin Pop
    return 1
939 b31c8676 Iustin Pop
940 0ec2ce46 René Nussbaumer
  if opts.disk_state:
941 0ec2ce46 René Nussbaumer
    disk_state = utils.FlatToDict(opts.disk_state)
942 0ec2ce46 René Nussbaumer
  else:
943 0ec2ce46 René Nussbaumer
    disk_state = {}
944 0ec2ce46 René Nussbaumer
945 0ec2ce46 René Nussbaumer
  hv_state = dict(opts.hv_state)
946 0ec2ce46 René Nussbaumer
947 f13973c4 Iustin Pop
  op = opcodes.OpNodeSetParams(node_name=args[0],
948 e7b61bb0 Iustin Pop
                               master_candidate=opts.master_candidate,
949 e7b61bb0 Iustin Pop
                               offline=opts.offline,
950 e7b61bb0 Iustin Pop
                               drained=opts.drained,
951 f91e255a Iustin Pop
                               master_capable=opts.master_capable,
952 53919782 Iustin Pop
                               vm_capable=opts.vm_capable,
953 4d32c211 Guido Trotter
                               secondary_ip=opts.secondary_ip,
954 4c61d894 Iustin Pop
                               force=opts.force,
955 4e37f591 René Nussbaumer
                               ndparams=opts.ndparams,
956 dd94e9f6 René Nussbaumer
                               auto_promote=opts.auto_promote,
957 0ec2ce46 René Nussbaumer
                               powered=opts.node_powered,
958 0ec2ce46 René Nussbaumer
                               hv_state=hv_state,
959 0ec2ce46 René Nussbaumer
                               disk_state=disk_state)
960 b31c8676 Iustin Pop
961 b31c8676 Iustin Pop
  # even if here we process the result, we allow submit only
962 b31c8676 Iustin Pop
  result = SubmitOrSend(op, opts)
963 b31c8676 Iustin Pop
964 b31c8676 Iustin Pop
  if result:
965 b31c8676 Iustin Pop
    ToStdout("Modified node %s", args[0])
966 b31c8676 Iustin Pop
    for param, data in result:
967 b31c8676 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
968 b31c8676 Iustin Pop
  return 0
969 b31c8676 Iustin Pop
970 b31c8676 Iustin Pop
971 7acbda7b Iustin Pop
class ReplyStatus(object):
972 7acbda7b Iustin Pop
  """Class holding a reply status for synchronous confd clients.
973 7acbda7b Iustin Pop

974 7acbda7b Iustin Pop
  """
975 7acbda7b Iustin Pop
  def __init__(self):
976 7acbda7b Iustin Pop
    self.failure = True
977 7acbda7b Iustin Pop
    self.answer = False
978 7acbda7b Iustin Pop
979 7acbda7b Iustin Pop
980 7acbda7b Iustin Pop
def ListDrbd(opts, args):
981 7acbda7b Iustin Pop
  """Modifies a node.
982 7acbda7b Iustin Pop

983 7acbda7b Iustin Pop
  @param opts: the command line options selected by the user
984 7acbda7b Iustin Pop
  @type args: list
985 7acbda7b Iustin Pop
  @param args: should contain only one element, the node name
986 7acbda7b Iustin Pop
  @rtype: int
987 7acbda7b Iustin Pop
  @return: the desired exit code
988 7acbda7b Iustin Pop

989 7acbda7b Iustin Pop
  """
990 7acbda7b Iustin Pop
  if len(args) != 1:
991 7acbda7b Iustin Pop
    ToStderr("Please give one (and only one) node.")
992 7acbda7b Iustin Pop
    return constants.EXIT_FAILURE
993 7acbda7b Iustin Pop
994 7acbda7b Iustin Pop
  if not constants.ENABLE_CONFD:
995 7acbda7b Iustin Pop
    ToStderr("Error: this command requires confd support, but it has not"
996 7acbda7b Iustin Pop
             " been enabled at build time.")
997 7acbda7b Iustin Pop
    return constants.EXIT_FAILURE
998 7acbda7b Iustin Pop
999 7acbda7b Iustin Pop
  status = ReplyStatus()
1000 7acbda7b Iustin Pop
1001 7acbda7b Iustin Pop
  def ListDrbdConfdCallback(reply):
1002 7acbda7b Iustin Pop
    """Callback for confd queries"""
1003 7acbda7b Iustin Pop
    if reply.type == confd_client.UPCALL_REPLY:
1004 7acbda7b Iustin Pop
      answer = reply.server_reply.answer
1005 7acbda7b Iustin Pop
      reqtype = reply.orig_request.type
1006 7acbda7b Iustin Pop
      if reqtype == constants.CONFD_REQ_NODE_DRBD:
1007 7acbda7b Iustin Pop
        if reply.server_reply.status != constants.CONFD_REPL_STATUS_OK:
1008 7acbda7b Iustin Pop
          ToStderr("Query gave non-ok status '%s': %s" %
1009 7acbda7b Iustin Pop
                   (reply.server_reply.status,
1010 7acbda7b Iustin Pop
                    reply.server_reply.answer))
1011 7acbda7b Iustin Pop
          status.failure = True
1012 7acbda7b Iustin Pop
          return
1013 7acbda7b Iustin Pop
        if not confd.HTNodeDrbd(answer):
1014 7acbda7b Iustin Pop
          ToStderr("Invalid response from server: expected %s, got %s",
1015 7acbda7b Iustin Pop
                   confd.HTNodeDrbd, answer)
1016 7acbda7b Iustin Pop
          status.failure = True
1017 7acbda7b Iustin Pop
        else:
1018 7acbda7b Iustin Pop
          status.failure = False
1019 7acbda7b Iustin Pop
          status.answer = answer
1020 7acbda7b Iustin Pop
      else:
1021 7acbda7b Iustin Pop
        ToStderr("Unexpected reply %s!?", reqtype)
1022 7acbda7b Iustin Pop
        status.failure = True
1023 7acbda7b Iustin Pop
1024 7acbda7b Iustin Pop
  node = args[0]
1025 78e706bb Michael Hanselmann
  hmac = utils.ReadFile(pathutils.CONFD_HMAC_KEY)
1026 7acbda7b Iustin Pop
  filter_callback = confd_client.ConfdFilterCallback(ListDrbdConfdCallback)
1027 7acbda7b Iustin Pop
  counting_callback = confd_client.ConfdCountingCallback(filter_callback)
1028 7acbda7b Iustin Pop
  cf_client = confd_client.ConfdClient(hmac, [constants.IP4_ADDRESS_LOCALHOST],
1029 7acbda7b Iustin Pop
                                       counting_callback)
1030 7acbda7b Iustin Pop
  req = confd_client.ConfdClientRequest(type=constants.CONFD_REQ_NODE_DRBD,
1031 7acbda7b Iustin Pop
                                        query=node)
1032 7acbda7b Iustin Pop
1033 7acbda7b Iustin Pop
  def DoConfdRequestReply(req):
1034 7acbda7b Iustin Pop
    counting_callback.RegisterQuery(req.rsalt)
1035 7acbda7b Iustin Pop
    cf_client.SendRequest(req, async=False)
1036 7acbda7b Iustin Pop
    while not counting_callback.AllAnswered():
1037 7acbda7b Iustin Pop
      if not cf_client.ReceiveReply():
1038 7acbda7b Iustin Pop
        ToStderr("Did not receive all expected confd replies")
1039 7acbda7b Iustin Pop
        break
1040 7acbda7b Iustin Pop
1041 7acbda7b Iustin Pop
  DoConfdRequestReply(req)
1042 7acbda7b Iustin Pop
1043 7acbda7b Iustin Pop
  if status.failure:
1044 7acbda7b Iustin Pop
    return constants.EXIT_FAILURE
1045 7acbda7b Iustin Pop
1046 7acbda7b Iustin Pop
  fields = ["node", "minor", "instance", "disk", "role", "peer"]
1047 2da31181 Iustin Pop
  if opts.no_headers:
1048 2da31181 Iustin Pop
    headers = None
1049 2da31181 Iustin Pop
  else:
1050 2da31181 Iustin Pop
    headers = {"node": "Node", "minor": "Minor", "instance": "Instance",
1051 2da31181 Iustin Pop
               "disk": "Disk", "role": "Role", "peer": "PeerNode"}
1052 7acbda7b Iustin Pop
1053 7acbda7b Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
1054 7acbda7b Iustin Pop
                       fields=fields, data=sorted(status.answer),
1055 7acbda7b Iustin Pop
                       numfields=["minor"])
1056 7acbda7b Iustin Pop
  for line in data:
1057 7acbda7b Iustin Pop
    ToStdout(line)
1058 7acbda7b Iustin Pop
1059 7acbda7b Iustin Pop
  return constants.EXIT_SUCCESS
1060 7acbda7b Iustin Pop
1061 a8083063 Iustin Pop
commands = {
1062 d0c8c01d Iustin Pop
  "add": (
1063 6ea815cf Iustin Pop
    AddNode, [ArgHost(min=1, max=1)],
1064 61413377 Stephen Shirley
    [SECONDARY_IP_OPT, READD_OPT, NOSSH_KEYCHECK_OPT, NODE_FORCE_JOIN_OPT,
1065 61413377 Stephen Shirley
     NONODE_SETUP_OPT, VERBOSE_OPT, NODEGROUP_OPT, PRIORITY_OPT,
1066 085e0d9f René Nussbaumer
     CAPAB_MASTER_OPT, CAPAB_VM_OPT, NODE_PARAMS_OPT, HV_STATE_OPT,
1067 085e0d9f René Nussbaumer
     DISK_STATE_OPT],
1068 61413377 Stephen Shirley
    "[-s ip] [--readd] [--no-ssh-key-check] [--force-join]"
1069 61413377 Stephen Shirley
    " [--no-node-setup] [--verbose]"
1070 2e6469a1 René Nussbaumer
    " <node_name>",
1071 6ea815cf Iustin Pop
    "Add a node to the cluster"),
1072 aafee533 Michael Hanselmann
  "evacuate": (
1073 aafee533 Michael Hanselmann
    EvacuateNode, ARGS_ONE_NODE,
1074 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, IALLOCATOR_OPT, NEW_SECONDARY_OPT, EARLY_RELEASE_OPT,
1075 c5a66db3 Michael Hanselmann
     PRIORITY_OPT, PRIMARY_ONLY_OPT, SECONDARY_ONLY_OPT, SUBMIT_OPT],
1076 5ec23388 Iustin Pop
    "[-f] {-I <iallocator> | -n <dst>} [-p | -s] [options...] <node>",
1077 f1dff7ec Iustin Pop
    "Relocate the primary and/or secondary instances from a node"),
1078 d0c8c01d Iustin Pop
  "failover": (
1079 1b7761fd Apollon Oikonomopoulos
    FailoverNode, ARGS_ONE_NODE, [FORCE_OPT, IGNORE_CONSIST_OPT,
1080 1b7761fd Apollon Oikonomopoulos
                                  IALLOCATOR_OPT, PRIORITY_OPT],
1081 6ea815cf Iustin Pop
    "[-f] <node>",
1082 6ea815cf Iustin Pop
    "Stops the primary instances on a node and start them on their"
1083 6ea815cf Iustin Pop
    " secondary node (only for instances with drbd disk template)"),
1084 d0c8c01d Iustin Pop
  "migrate": (
1085 aa06f8c6 Michael Hanselmann
    MigrateNode, ARGS_ONE_NODE,
1086 f8fa4175 Michael Hanselmann
    [FORCE_OPT, NONLIVE_OPT, MIGRATION_MODE_OPT, DST_NODE_OPT,
1087 8c0b16f6 Guido Trotter
     IALLOCATOR_OPT, PRIORITY_OPT, IGNORE_IPOLICY_OPT,
1088 7db596df Iustin Pop
     NORUNTIME_CHGS_OPT, SUBMIT_OPT],
1089 6ea815cf Iustin Pop
    "[-f] <node>",
1090 6ea815cf Iustin Pop
    "Migrate all the primary instance on a node away from it"
1091 6ea815cf Iustin Pop
    " (only for instances of type drbd)"),
1092 d0c8c01d Iustin Pop
  "info": (
1093 064c21f8 Iustin Pop
    ShowNodeConfig, ARGS_MANY_NODES, [],
1094 6ea815cf Iustin Pop
    "[<node_name>...]", "Show information about the node(s)"),
1095 d0c8c01d Iustin Pop
  "list": (
1096 6ea815cf Iustin Pop
    ListNodes, ARGS_MANY_NODES,
1097 2afd577f Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, VERBOSE_OPT,
1098 2afd577f Michael Hanselmann
     FORCE_FILTER_OPT],
1099 6ea815cf Iustin Pop
    "[nodes...]",
1100 7f5443a0 Michael Hanselmann
    "Lists the nodes in the cluster. The available fields can be shown using"
1101 7f5443a0 Michael Hanselmann
    " the \"list-fields\" command (see the man page for details)."
1102 7f5443a0 Michael Hanselmann
    " The default field list is (in order): %s." %
1103 7f5443a0 Michael Hanselmann
    utils.CommaJoin(_LIST_DEF_FIELDS)),
1104 7f5443a0 Michael Hanselmann
  "list-fields": (
1105 7f5443a0 Michael Hanselmann
    ListNodeFields, [ArgUnknown()],
1106 7f5443a0 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT],
1107 7f5443a0 Michael Hanselmann
    "[fields...]",
1108 7f5443a0 Michael Hanselmann
    "Lists all available fields for nodes"),
1109 d0c8c01d Iustin Pop
  "modify": (
1110 6ea815cf Iustin Pop
    SetNodeParams, ARGS_ONE_NODE,
1111 53919782 Iustin Pop
    [FORCE_OPT, SUBMIT_OPT, MC_OPT, DRAINED_OPT, OFFLINE_OPT,
1112 4d32c211 Guido Trotter
     CAPAB_MASTER_OPT, CAPAB_VM_OPT, SECONDARY_IP_OPT,
1113 dd94e9f6 René Nussbaumer
     AUTO_PROMOTE_OPT, DRY_RUN_OPT, PRIORITY_OPT, NODE_PARAMS_OPT,
1114 0ec2ce46 René Nussbaumer
     NODE_POWERED_OPT, HV_STATE_OPT, DISK_STATE_OPT],
1115 6ea815cf Iustin Pop
    "<node_name>", "Alters the parameters of a node"),
1116 d0c8c01d Iustin Pop
  "powercycle": (
1117 6ea815cf Iustin Pop
    PowercycleNode, ARGS_ONE_NODE,
1118 c5a66db3 Michael Hanselmann
    [FORCE_OPT, CONFIRM_OPT, DRY_RUN_OPT, PRIORITY_OPT, SUBMIT_OPT],
1119 6ea815cf Iustin Pop
    "<node_name>", "Tries to forcefully powercycle a node"),
1120 d0c8c01d Iustin Pop
  "power": (
1121 abefdcff René Nussbaumer
    PowerNode,
1122 abefdcff René Nussbaumer
    [ArgChoice(min=1, max=1, choices=_LIST_POWER_COMMANDS),
1123 c832b6c8 René Nussbaumer
     ArgNode()],
1124 efae0fdd René Nussbaumer
    [SUBMIT_OPT, AUTO_PROMOTE_OPT, PRIORITY_OPT, IGNORE_STATUS_OPT,
1125 0a1fc31c René Nussbaumer
     FORCE_OPT, NOHDR_OPT, SEP_OPT, OOB_TIMEOUT_OPT, POWER_DELAY_OPT],
1126 c832b6c8 René Nussbaumer
    "on|off|cycle|status [nodes...]",
1127 abefdcff René Nussbaumer
    "Change power state of node by calling out-of-band helper."),
1128 d0c8c01d Iustin Pop
  "remove": (
1129 aa06f8c6 Michael Hanselmann
    RemoveNode, ARGS_ONE_NODE, [DRY_RUN_OPT, PRIORITY_OPT],
1130 6ea815cf Iustin Pop
    "<node_name>", "Removes a node from the cluster"),
1131 d0c8c01d Iustin Pop
  "volumes": (
1132 6ea815cf Iustin Pop
    ListVolumes, [ArgNode()],
1133 aa06f8c6 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, PRIORITY_OPT],
1134 6ea815cf Iustin Pop
    "[<node_name>...]", "List logical volumes on node(s)"),
1135 d0c8c01d Iustin Pop
  "list-storage": (
1136 9b94905f Iustin Pop
    ListStorage, ARGS_MANY_NODES,
1137 aa06f8c6 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, _STORAGE_TYPE_OPT,
1138 aa06f8c6 Michael Hanselmann
     PRIORITY_OPT],
1139 620a85fd Iustin Pop
    "[<node_name>...]", "List physical volumes on node(s). The available"
1140 620a85fd Iustin Pop
    " fields are (see the man page for details): %s." %
1141 1f864b60 Iustin Pop
    (utils.CommaJoin(_LIST_STOR_HEADERS))),
1142 d0c8c01d Iustin Pop
  "modify-storage": (
1143 9b94905f Iustin Pop
    ModifyStorage,
1144 6ea815cf Iustin Pop
    [ArgNode(min=1, max=1),
1145 6ea815cf Iustin Pop
     ArgChoice(min=1, max=1, choices=_MODIFIABLE_STORAGE_TYPES),
1146 6ea815cf Iustin Pop
     ArgFile(min=1, max=1)],
1147 c5a66db3 Michael Hanselmann
    [ALLOCATABLE_OPT, DRY_RUN_OPT, PRIORITY_OPT, SUBMIT_OPT],
1148 064c21f8 Iustin Pop
    "<node_name> <storage_type> <name>", "Modify storage volume on a node"),
1149 d0c8c01d Iustin Pop
  "repair-storage": (
1150 9b94905f Iustin Pop
    RepairStorage,
1151 6ea815cf Iustin Pop
    [ArgNode(min=1, max=1),
1152 6ea815cf Iustin Pop
     ArgChoice(min=1, max=1, choices=_REPAIRABLE_STORAGE_TYPES),
1153 6ea815cf Iustin Pop
     ArgFile(min=1, max=1)],
1154 c5a66db3 Michael Hanselmann
    [IGNORE_CONSIST_OPT, DRY_RUN_OPT, PRIORITY_OPT, SUBMIT_OPT],
1155 6ea815cf Iustin Pop
    "<node_name> <storage_type> <name>",
1156 6ea815cf Iustin Pop
    "Repairs a storage volume on a node"),
1157 d0c8c01d Iustin Pop
  "list-tags": (
1158 064c21f8 Iustin Pop
    ListTags, ARGS_ONE_NODE, [],
1159 6ea815cf Iustin Pop
    "<node_name>", "List the tags of the given node"),
1160 d0c8c01d Iustin Pop
  "add-tags": (
1161 6bc3ed14 Michael Hanselmann
    AddTags, [ArgNode(min=1, max=1), ArgUnknown()],
1162 6bc3ed14 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
1163 6ea815cf Iustin Pop
    "<node_name> tag...", "Add tags to the given node"),
1164 d0c8c01d Iustin Pop
  "remove-tags": (
1165 aa06f8c6 Michael Hanselmann
    RemoveTags, [ArgNode(min=1, max=1), ArgUnknown()],
1166 6bc3ed14 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
1167 6ea815cf Iustin Pop
    "<node_name> tag...", "Remove tags from the given node"),
1168 a0724772 René Nussbaumer
  "health": (
1169 a0724772 René Nussbaumer
    Health, ARGS_MANY_NODES,
1170 6bc3ed14 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, PRIORITY_OPT, OOB_TIMEOUT_OPT],
1171 a0724772 René Nussbaumer
    "[<node_name>...]", "List health of node(s) using out-of-band"),
1172 7acbda7b Iustin Pop
  "list-drbd": (
1173 7acbda7b Iustin Pop
    ListDrbd, ARGS_ONE_NODE,
1174 7acbda7b Iustin Pop
    [NOHDR_OPT, SEP_OPT],
1175 7acbda7b Iustin Pop
    "[<node_name>]", "Query the list of used DRBD minors on the given node"),
1176 a8083063 Iustin Pop
  }
1177 a8083063 Iustin Pop
1178 96897af7 Alexander Schreiber
#: dictionary with aliases for commands
1179 96897af7 Alexander Schreiber
aliases = {
1180 96897af7 Alexander Schreiber
  "show": "info",
1181 96897af7 Alexander Schreiber
  }
1182 96897af7 Alexander Schreiber
1183 a8083063 Iustin Pop
1184 37494fa4 Michael Hanselmann
def Main():
1185 96897af7 Alexander Schreiber
  return GenericMain(commands, aliases=aliases,
1186 96897af7 Alexander Schreiber
                     override={"tag_type": constants.TAG_NODE},
1187 ef9fa5b9 René Nussbaumer
                     env_override=_ENV_OVERRIDE)