Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ 91c17910

History | View | Annotate | Download (37.5 kB)

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

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

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

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

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

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

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

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

194 224ff0f7 Michael Hanselmann
  """
195 224ff0f7 Michael Hanselmann
  if options.force_join:
196 224ff0f7 Michael Hanselmann
    ToStderr("The \"--force-join\" option is no longer supported and will be"
197 224ff0f7 Michael Hanselmann
             " ignored.")
198 224ff0f7 Michael Hanselmann
199 224ff0f7 Michael Hanselmann
  host_keys = _ReadSshKeys(constants.SSH_DAEMON_KEYFILES)
200 224ff0f7 Michael Hanselmann
201 224ff0f7 Michael Hanselmann
  (_, root_keyfiles) = \
202 224ff0f7 Michael Hanselmann
    ssh.GetAllUserFiles(constants.SSH_LOGIN_USER, mkdir=False, dircheck=False)
203 224ff0f7 Michael Hanselmann
204 224ff0f7 Michael Hanselmann
  root_keys = _ReadSshKeys(root_keyfiles)
205 224ff0f7 Michael Hanselmann
206 224ff0f7 Michael Hanselmann
  (_, cert_pem) = \
207 224ff0f7 Michael Hanselmann
    utils.ExtractX509Certificate(utils.ReadFile(pathutils.NODED_CERT_FILE))
208 224ff0f7 Michael Hanselmann
209 224ff0f7 Michael Hanselmann
  data = {
210 224ff0f7 Michael Hanselmann
    constants.SSHS_CLUSTER_NAME: cluster_name,
211 224ff0f7 Michael Hanselmann
    constants.SSHS_NODE_DAEMON_CERTIFICATE: cert_pem,
212 224ff0f7 Michael Hanselmann
    constants.SSHS_SSH_HOST_KEY: host_keys,
213 224ff0f7 Michael Hanselmann
    constants.SSHS_SSH_ROOT_KEY: root_keys,
214 224ff0f7 Michael Hanselmann
    }
215 224ff0f7 Michael Hanselmann
216 a698cdbb Michael Hanselmann
  bootstrap.RunNodeSetupCmd(cluster_name, node, pathutils.PREPARE_NODE_JOIN,
217 a698cdbb Michael Hanselmann
                            options.debug, options.verbose, False,
218 a698cdbb Michael Hanselmann
                            options.ssh_key_check, options.ssh_key_check, data)
219 2e6469a1 René Nussbaumer
220 2e6469a1 René Nussbaumer
221 4331f6cd Michael Hanselmann
@UsesRPC
222 a8083063 Iustin Pop
def AddNode(opts, args):
223 ebf366ee Iustin Pop
  """Add a node to the cluster.
224 ebf366ee Iustin Pop

225 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
226 ebf366ee Iustin Pop
  @type args: list
227 ebf366ee Iustin Pop
  @param args: should contain only one element, the new node name
228 ebf366ee Iustin Pop
  @rtype: int
229 ebf366ee Iustin Pop
  @return: the desired exit code
230 05ccd983 Guido Trotter

231 05ccd983 Guido Trotter
  """
232 87622829 Iustin Pop
  cl = GetClient()
233 b705c7a6 Manuel Franceschini
  node = netutils.GetHostname(name=args[0]).name
234 82e12743 Iustin Pop
  readd = opts.readd
235 82e12743 Iustin Pop
236 82e12743 Iustin Pop
  try:
237 d0c8c01d Iustin Pop
    output = cl.QueryNodes(names=[node], fields=["name", "sip", "master"],
238 77921a95 Iustin Pop
                           use_locking=False)
239 d833acc6 Iustin Pop
    node_exists, sip, is_master = output[0]
240 82e12743 Iustin Pop
  except (errors.OpPrereqError, errors.OpExecError):
241 82e12743 Iustin Pop
    node_exists = ""
242 82e12743 Iustin Pop
    sip = None
243 82e12743 Iustin Pop
244 82e12743 Iustin Pop
  if readd:
245 82e12743 Iustin Pop
    if not node_exists:
246 82e12743 Iustin Pop
      ToStderr("Node %s not in the cluster"
247 82e12743 Iustin Pop
               " - please retry without '--readd'", node)
248 82e12743 Iustin Pop
      return 1
249 d833acc6 Iustin Pop
    if is_master:
250 d833acc6 Iustin Pop
      ToStderr("Node %s is the master, cannot readd", node)
251 d833acc6 Iustin Pop
      return 1
252 82e12743 Iustin Pop
  else:
253 82e12743 Iustin Pop
    if node_exists:
254 3a24c527 Iustin Pop
      ToStderr("Node %s already in the cluster (as %s)"
255 82e12743 Iustin Pop
               " - please retry with '--readd'", node, node_exists)
256 05ccd983 Guido Trotter
      return 1
257 82e12743 Iustin Pop
    sip = opts.secondary_ip
258 05ccd983 Guido Trotter
259 87622829 Iustin Pop
  # read the cluster name from the master
260 224ff0f7 Michael Hanselmann
  (cluster_name, ) = cl.QueryConfigValues(["cluster_name"])
261 87622829 Iustin Pop
262 3ef51126 René Nussbaumer
  if not readd and opts.node_setup:
263 82e12743 Iustin Pop
    ToStderr("-- WARNING -- \n"
264 82e12743 Iustin Pop
             "Performing this operation is going to replace the ssh daemon"
265 82e12743 Iustin Pop
             " keypair\n"
266 82e12743 Iustin Pop
             "on the target machine (%s) with the ones of the"
267 82e12743 Iustin Pop
             " current one\n"
268 82e12743 Iustin Pop
             "and grant full intra-cluster ssh root access to/from it\n", node)
269 05ccd983 Guido Trotter
270 2e6469a1 René Nussbaumer
  if opts.node_setup:
271 224ff0f7 Michael Hanselmann
    _SetupSSH(opts, cluster_name, node)
272 827f753e Guido Trotter
273 7b8ba235 Michael Hanselmann
  bootstrap.SetupNodeDaemon(opts, cluster_name, node)
274 3ef51126 René Nussbaumer
275 085e0d9f René Nussbaumer
  if opts.disk_state:
276 085e0d9f René Nussbaumer
    disk_state = utils.FlatToDict(opts.disk_state)
277 085e0d9f René Nussbaumer
  else:
278 085e0d9f René Nussbaumer
    disk_state = {}
279 085e0d9f René Nussbaumer
280 085e0d9f René Nussbaumer
  hv_state = dict(opts.hv_state)
281 085e0d9f René Nussbaumer
282 d817d49f Iustin Pop
  op = opcodes.OpNodeAdd(node_name=args[0], secondary_ip=sip,
283 fd3d37b6 Iustin Pop
                         readd=opts.readd, group=opts.nodegroup,
284 4e37f591 René Nussbaumer
                         vm_capable=opts.vm_capable, ndparams=opts.ndparams,
285 085e0d9f René Nussbaumer
                         master_capable=opts.master_capable,
286 085e0d9f René Nussbaumer
                         disk_state=disk_state,
287 085e0d9f René Nussbaumer
                         hv_state=hv_state)
288 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
289 a8083063 Iustin Pop
290 a8083063 Iustin Pop
291 a8083063 Iustin Pop
def ListNodes(opts, args):
292 a8083063 Iustin Pop
  """List nodes and their properties.
293 a8083063 Iustin Pop

294 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
295 ebf366ee Iustin Pop
  @type args: list
296 982ed68e Adeodato Simo
  @param args: nodes to list, or empty for all
297 ebf366ee Iustin Pop
  @rtype: int
298 ebf366ee Iustin Pop
  @return: the desired exit code
299 ebf366ee Iustin Pop

300 a8083063 Iustin Pop
  """
301 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
302 a8083063 Iustin Pop
303 7f5443a0 Michael Hanselmann
  fmtoverride = dict.fromkeys(["pinst_list", "sinst_list", "tags"],
304 a36f605d Michael Hanselmann
                              (",".join, False))
305 a8083063 Iustin Pop
306 fb251c2c Iustin Pop
  cl = GetClient(query=False)
307 9fbf0098 Iustin Pop
308 7f5443a0 Michael Hanselmann
  return GenericList(constants.QR_NODE, selected_fields, args, opts.units,
309 7f5443a0 Michael Hanselmann
                     opts.separator, not opts.no_headers,
310 2afd577f Michael Hanselmann
                     format_override=fmtoverride, verbose=opts.verbose,
311 9fbf0098 Iustin Pop
                     force_filter=opts.force_filter, cl=cl)
312 137161c9 Michael Hanselmann
313 137161c9 Michael Hanselmann
314 7f5443a0 Michael Hanselmann
def ListNodeFields(opts, args):
315 7f5443a0 Michael Hanselmann
  """List node fields.
316 ec223efb Iustin Pop

317 7f5443a0 Michael Hanselmann
  @param opts: the command line options selected by the user
318 7f5443a0 Michael Hanselmann
  @type args: list
319 7f5443a0 Michael Hanselmann
  @param args: fields to list, or empty for all
320 7f5443a0 Michael Hanselmann
  @rtype: int
321 7f5443a0 Michael Hanselmann
  @return: the desired exit code
322 a8083063 Iustin Pop

323 7f5443a0 Michael Hanselmann
  """
324 9fbf0098 Iustin Pop
  cl = GetClient(query=True)
325 9fbf0098 Iustin Pop
326 7f5443a0 Michael Hanselmann
  return GenericListFields(constants.QR_NODE, args, opts.separator,
327 9fbf0098 Iustin Pop
                           not opts.no_headers, cl=cl)
328 a8083063 Iustin Pop
329 a8083063 Iustin Pop
330 a5bc662a Iustin Pop
def EvacuateNode(opts, args):
331 a5bc662a Iustin Pop
  """Relocate all secondary instance from a node.
332 a5bc662a Iustin Pop

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

339 a5bc662a Iustin Pop
  """
340 aafee533 Michael Hanselmann
  if opts.dst_node is not None:
341 aafee533 Michael Hanselmann
    ToStderr("New secondary node given (disabling iallocator), hence evacuating"
342 aafee533 Michael Hanselmann
             " secondary instances only.")
343 aafee533 Michael Hanselmann
    opts.secondary_only = True
344 aafee533 Michael Hanselmann
    opts.primary_only = False
345 aafee533 Michael Hanselmann
346 aafee533 Michael Hanselmann
  if opts.secondary_only and opts.primary_only:
347 aafee533 Michael Hanselmann
    raise errors.OpPrereqError("Only one of the --primary-only and"
348 aafee533 Michael Hanselmann
                               " --secondary-only options can be passed",
349 aafee533 Michael Hanselmann
                               errors.ECODE_INVAL)
350 aafee533 Michael Hanselmann
  elif opts.primary_only:
351 cb92e7a1 Michael Hanselmann
    mode = constants.NODE_EVAC_PRI
352 aafee533 Michael Hanselmann
  elif opts.secondary_only:
353 cb92e7a1 Michael Hanselmann
    mode = constants.NODE_EVAC_SEC
354 aafee533 Michael Hanselmann
  else:
355 cb92e7a1 Michael Hanselmann
    mode = constants.NODE_EVAC_ALL
356 c4ed32cb Iustin Pop
357 aafee533 Michael Hanselmann
  # Determine affected instances
358 aafee533 Michael Hanselmann
  fields = []
359 c4ed32cb Iustin Pop
360 aafee533 Michael Hanselmann
  if not opts.secondary_only:
361 aafee533 Michael Hanselmann
    fields.append("pinst_list")
362 aafee533 Michael Hanselmann
  if not opts.primary_only:
363 aafee533 Michael Hanselmann
    fields.append("sinst_list")
364 f8c9fa5c Iustin Pop
365 aafee533 Michael Hanselmann
  cl = GetClient()
366 aafee533 Michael Hanselmann
367 9fbf0098 Iustin Pop
  qcl = GetClient(query=True)
368 9fbf0098 Iustin Pop
  result = qcl.QueryNodes(names=args, fields=fields, use_locking=False)
369 9fbf0098 Iustin Pop
  qcl.Close()
370 9fbf0098 Iustin Pop
371 aafee533 Michael Hanselmann
  instances = set(itertools.chain(*itertools.chain(*itertools.chain(result))))
372 aafee533 Michael Hanselmann
373 aafee533 Michael Hanselmann
  if not instances:
374 aafee533 Michael Hanselmann
    # No instances to evacuate
375 aafee533 Michael Hanselmann
    ToStderr("No instances to evacuate on node(s) %s, exiting.",
376 f8c9fa5c Iustin Pop
             utils.CommaJoin(args))
377 a5bc662a Iustin Pop
    return constants.EXIT_SUCCESS
378 a5bc662a Iustin Pop
379 aafee533 Michael Hanselmann
  if not (opts.force or
380 aafee533 Michael Hanselmann
          AskUser("Relocate instance(s) %s from node(s) %s?" %
381 aafee533 Michael Hanselmann
                  (utils.CommaJoin(utils.NiceSort(instances)),
382 aafee533 Michael Hanselmann
                   utils.CommaJoin(args)))):
383 a5bc662a Iustin Pop
    return constants.EXIT_CONFIRMATION
384 a5bc662a Iustin Pop
385 aafee533 Michael Hanselmann
  # Evacuate node
386 aafee533 Michael Hanselmann
  op = opcodes.OpNodeEvacuate(node_name=args[0], mode=mode,
387 aafee533 Michael Hanselmann
                              remote_node=opts.dst_node,
388 aafee533 Michael Hanselmann
                              iallocator=opts.iallocator,
389 aafee533 Michael Hanselmann
                              early_release=opts.early_release)
390 c5a66db3 Michael Hanselmann
  result = SubmitOrSend(op, opts, cl=cl)
391 aafee533 Michael Hanselmann
392 aafee533 Michael Hanselmann
  # Keep track of submitted jobs
393 f8c9fa5c Iustin Pop
  jex = JobExecutor(cl=cl, opts=opts)
394 aafee533 Michael Hanselmann
395 aafee533 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
396 aafee533 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
397 aafee533 Michael Hanselmann
398 f8c9fa5c Iustin Pop
  results = jex.GetResults()
399 f8c9fa5c Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
400 f8c9fa5c Iustin Pop
  if bad_cnt == 0:
401 aafee533 Michael Hanselmann
    ToStdout("All instances evacuated successfully.")
402 f8c9fa5c Iustin Pop
    rcode = constants.EXIT_SUCCESS
403 f8c9fa5c Iustin Pop
  else:
404 aafee533 Michael Hanselmann
    ToStdout("There were %s errors during the evacuation.", bad_cnt)
405 f8c9fa5c Iustin Pop
    rcode = constants.EXIT_FAILURE
406 aafee533 Michael Hanselmann
407 f8c9fa5c Iustin Pop
  return rcode
408 a5bc662a Iustin Pop
409 a5bc662a Iustin Pop
410 c450e9b0 Iustin Pop
def FailoverNode(opts, args):
411 c450e9b0 Iustin Pop
  """Failover all primary instance on a node.
412 c450e9b0 Iustin Pop

413 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
414 ebf366ee Iustin Pop
  @type args: list
415 ebf366ee Iustin Pop
  @param args: should be an empty list
416 ebf366ee Iustin Pop
  @rtype: int
417 ebf366ee Iustin Pop
  @return: the desired exit code
418 ebf366ee Iustin Pop

419 c450e9b0 Iustin Pop
  """
420 479636a3 Iustin Pop
  cl = GetClient()
421 c450e9b0 Iustin Pop
  force = opts.force
422 c450e9b0 Iustin Pop
  selected_fields = ["name", "pinst_list"]
423 c450e9b0 Iustin Pop
424 2e7b8369 Iustin Pop
  # these fields are static data anyway, so it doesn't matter, but
425 2e7b8369 Iustin Pop
  # locking=True should be safer
426 9fbf0098 Iustin Pop
  qcl = GetClient(query=True)
427 2e7b8369 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields,
428 77921a95 Iustin Pop
                         use_locking=False)
429 9fbf0098 Iustin Pop
  qcl.Close()
430 c450e9b0 Iustin Pop
  node, pinst = result[0]
431 c450e9b0 Iustin Pop
432 c450e9b0 Iustin Pop
  if not pinst:
433 3a24c527 Iustin Pop
    ToStderr("No primary instances on node %s, exiting.", node)
434 c450e9b0 Iustin Pop
    return 0
435 c450e9b0 Iustin Pop
436 c450e9b0 Iustin Pop
  pinst = utils.NiceSort(pinst)
437 c450e9b0 Iustin Pop
438 c450e9b0 Iustin Pop
  retcode = 0
439 c450e9b0 Iustin Pop
440 c450e9b0 Iustin Pop
  if not force and not AskUser("Fail over instance(s) %s?" %
441 c450e9b0 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
442 c450e9b0 Iustin Pop
    return 2
443 c450e9b0 Iustin Pop
444 cb573a31 Iustin Pop
  jex = JobExecutor(cl=cl, opts=opts)
445 c450e9b0 Iustin Pop
  for iname in pinst:
446 019dbee1 Iustin Pop
    op = opcodes.OpInstanceFailover(instance_name=iname,
447 1b7761fd Apollon Oikonomopoulos
                                    ignore_consistency=opts.ignore_consistency,
448 1b7761fd Apollon Oikonomopoulos
                                    iallocator=opts.iallocator)
449 479636a3 Iustin Pop
    jex.QueueJob(iname, op)
450 479636a3 Iustin Pop
  results = jex.GetResults()
451 479636a3 Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
452 479636a3 Iustin Pop
  if bad_cnt == 0:
453 479636a3 Iustin Pop
    ToStdout("All %d instance(s) failed over successfully.", len(results))
454 c450e9b0 Iustin Pop
  else:
455 3a24c527 Iustin Pop
    ToStdout("There were errors during the failover:\n"
456 479636a3 Iustin Pop
             "%d error(s) out of %d instance(s).", bad_cnt, len(results))
457 c450e9b0 Iustin Pop
  return retcode
458 c450e9b0 Iustin Pop
459 c450e9b0 Iustin Pop
460 40ef0ed6 Iustin Pop
def MigrateNode(opts, args):
461 40ef0ed6 Iustin Pop
  """Migrate all primary instance on a node.
462 40ef0ed6 Iustin Pop

463 40ef0ed6 Iustin Pop
  """
464 40ef0ed6 Iustin Pop
  cl = GetClient()
465 40ef0ed6 Iustin Pop
  force = opts.force
466 40ef0ed6 Iustin Pop
  selected_fields = ["name", "pinst_list"]
467 40ef0ed6 Iustin Pop
468 9fbf0098 Iustin Pop
  qcl = GetClient(query=True)
469 77921a95 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields, use_locking=False)
470 9fbf0098 Iustin Pop
  qcl.Close()
471 b7a1c816 Michael Hanselmann
  ((node, pinst), ) = result
472 40ef0ed6 Iustin Pop
473 40ef0ed6 Iustin Pop
  if not pinst:
474 40ef0ed6 Iustin Pop
    ToStdout("No primary instances on node %s, exiting." % node)
475 40ef0ed6 Iustin Pop
    return 0
476 40ef0ed6 Iustin Pop
477 40ef0ed6 Iustin Pop
  pinst = utils.NiceSort(pinst)
478 40ef0ed6 Iustin Pop
479 b7a1c816 Michael Hanselmann
  if not (force or
480 b7a1c816 Michael Hanselmann
          AskUser("Migrate instance(s) %s?" %
481 b7a1c816 Michael Hanselmann
                  utils.CommaJoin(utils.NiceSort(pinst)))):
482 b7a1c816 Michael Hanselmann
    return constants.EXIT_CONFIRMATION
483 40ef0ed6 Iustin Pop
484 e71b9ef4 Iustin Pop
  # this should be removed once --non-live is deprecated
485 783a6c0b Iustin Pop
  if not opts.live and opts.migration_mode is not None:
486 e71b9ef4 Iustin Pop
    raise errors.OpPrereqError("Only one of the --non-live and "
487 783a6c0b Iustin Pop
                               "--migration-mode options can be passed",
488 e71b9ef4 Iustin Pop
                               errors.ECODE_INVAL)
489 e71b9ef4 Iustin Pop
  if not opts.live: # --non-live passed
490 8c35561f Iustin Pop
    mode = constants.HT_MIGRATION_NONLIVE
491 e71b9ef4 Iustin Pop
  else:
492 8c35561f Iustin Pop
    mode = opts.migration_mode
493 b7a1c816 Michael Hanselmann
494 1b7761fd Apollon Oikonomopoulos
  op = opcodes.OpNodeMigrate(node_name=args[0], mode=mode,
495 f8fa4175 Michael Hanselmann
                             iallocator=opts.iallocator,
496 9fa567b3 René Nussbaumer
                             target_node=opts.dst_node,
497 8c0b16f6 Guido Trotter
                             allow_runtime_changes=opts.allow_runtime_chgs,
498 9fa567b3 René Nussbaumer
                             ignore_ipolicy=opts.ignore_ipolicy)
499 b7a1c816 Michael Hanselmann
500 c5a66db3 Michael Hanselmann
  result = SubmitOrSend(op, opts, cl=cl)
501 b7a1c816 Michael Hanselmann
502 b7a1c816 Michael Hanselmann
  # Keep track of submitted jobs
503 b7a1c816 Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
504 b7a1c816 Michael Hanselmann
505 b7a1c816 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
506 b7a1c816 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
507 b7a1c816 Michael Hanselmann
508 b7a1c816 Michael Hanselmann
  results = jex.GetResults()
509 b7a1c816 Michael Hanselmann
  bad_cnt = len([row for row in results if not row[0]])
510 b7a1c816 Michael Hanselmann
  if bad_cnt == 0:
511 b7a1c816 Michael Hanselmann
    ToStdout("All instances migrated successfully.")
512 b7a1c816 Michael Hanselmann
    rcode = constants.EXIT_SUCCESS
513 b7a1c816 Michael Hanselmann
  else:
514 b7a1c816 Michael Hanselmann
    ToStdout("There were %s errors during the node migration.", bad_cnt)
515 b7a1c816 Michael Hanselmann
    rcode = constants.EXIT_FAILURE
516 b7a1c816 Michael Hanselmann
517 b7a1c816 Michael Hanselmann
  return rcode
518 40ef0ed6 Iustin Pop
519 40ef0ed6 Iustin Pop
520 a8083063 Iustin Pop
def ShowNodeConfig(opts, args):
521 a8083063 Iustin Pop
  """Show node information.
522 a8083063 Iustin Pop

523 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
524 ebf366ee Iustin Pop
  @type args: list
525 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
526 ebf366ee Iustin Pop
      we show information about all nodes, or should contain
527 ebf366ee Iustin Pop
      a list of nodes to be queried for information
528 ebf366ee Iustin Pop
  @rtype: int
529 ebf366ee Iustin Pop
  @return: the desired exit code
530 ebf366ee Iustin Pop

531 a8083063 Iustin Pop
  """
532 fb251c2c Iustin Pop
  # note: if this starts using RPC fields, and we haven't yet fixed
533 fb251c2c Iustin Pop
  # hconfd, then we should revert to query=False
534 9fbf0098 Iustin Pop
  cl = GetClient(query=True)
535 2e7b8369 Iustin Pop
  result = cl.QueryNodes(fields=["name", "pip", "sip",
536 0b2454b9 Iustin Pop
                                 "pinst_list", "sinst_list",
537 7b4978ad Iustin Pop
                                 "master_candidate", "drained", "offline",
538 8572f1fe René Nussbaumer
                                 "master_capable", "vm_capable", "powered",
539 8572f1fe René Nussbaumer
                                 "ndparams", "custom_ndparams"],
540 77921a95 Iustin Pop
                         names=args, use_locking=False)
541 a8083063 Iustin Pop
542 8572f1fe René Nussbaumer
  for (name, primary_ip, secondary_ip, pinst, sinst, is_mc, drained, offline,
543 8572f1fe René Nussbaumer
       master_capable, vm_capable, powered, ndparams,
544 8572f1fe René Nussbaumer
       ndparams_custom) in result:
545 3a24c527 Iustin Pop
    ToStdout("Node name: %s", name)
546 3a24c527 Iustin Pop
    ToStdout("  primary ip: %s", primary_ip)
547 3a24c527 Iustin Pop
    ToStdout("  secondary ip: %s", secondary_ip)
548 0b2454b9 Iustin Pop
    ToStdout("  master candidate: %s", is_mc)
549 0b2454b9 Iustin Pop
    ToStdout("  drained: %s", drained)
550 0b2454b9 Iustin Pop
    ToStdout("  offline: %s", offline)
551 016acd85 René Nussbaumer
    if powered is not None:
552 016acd85 René Nussbaumer
      ToStdout("  powered: %s", powered)
553 7b4978ad Iustin Pop
    ToStdout("  master_capable: %s", master_capable)
554 7b4978ad Iustin Pop
    ToStdout("  vm_capable: %s", vm_capable)
555 7b4978ad Iustin Pop
    if vm_capable:
556 7b4978ad Iustin Pop
      if pinst:
557 7b4978ad Iustin Pop
        ToStdout("  primary for instances:")
558 7b4978ad Iustin Pop
        for iname in utils.NiceSort(pinst):
559 7b4978ad Iustin Pop
          ToStdout("    - %s", iname)
560 7b4978ad Iustin Pop
      else:
561 7b4978ad Iustin Pop
        ToStdout("  primary for no instances")
562 7b4978ad Iustin Pop
      if sinst:
563 7b4978ad Iustin Pop
        ToStdout("  secondary for instances:")
564 7b4978ad Iustin Pop
        for iname in utils.NiceSort(sinst):
565 7b4978ad Iustin Pop
          ToStdout("    - %s", iname)
566 7b4978ad Iustin Pop
      else:
567 7b4978ad Iustin Pop
        ToStdout("  secondary for no instances")
568 8572f1fe René Nussbaumer
    ToStdout("  node parameters:")
569 8572f1fe René Nussbaumer
    buf = StringIO()
570 8572f1fe René Nussbaumer
    FormatParameterDict(buf, ndparams_custom, ndparams, level=2)
571 8572f1fe René Nussbaumer
    ToStdout(buf.getvalue().rstrip("\n"))
572 a8083063 Iustin Pop
573 a8083063 Iustin Pop
  return 0
574 a8083063 Iustin Pop
575 a8083063 Iustin Pop
576 a8083063 Iustin Pop
def RemoveNode(opts, args):
577 ebf366ee Iustin Pop
  """Remove a node from the cluster.
578 ebf366ee Iustin Pop

579 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
580 ebf366ee Iustin Pop
  @type args: list
581 ebf366ee Iustin Pop
  @param args: should contain only one element, the name of
582 ebf366ee Iustin Pop
      the node to be removed
583 ebf366ee Iustin Pop
  @rtype: int
584 ebf366ee Iustin Pop
  @return: the desired exit code
585 ebf366ee Iustin Pop

586 ebf366ee Iustin Pop
  """
587 73d565a3 Iustin Pop
  op = opcodes.OpNodeRemove(node_name=args[0])
588 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
589 ebf366ee Iustin Pop
  return 0
590 a8083063 Iustin Pop
591 a8083063 Iustin Pop
592 f5118ade Iustin Pop
def PowercycleNode(opts, args):
593 f5118ade Iustin Pop
  """Remove a node from the cluster.
594 f5118ade Iustin Pop

595 f5118ade Iustin Pop
  @param opts: the command line options selected by the user
596 f5118ade Iustin Pop
  @type args: list
597 f5118ade Iustin Pop
  @param args: should contain only one element, the name of
598 f5118ade Iustin Pop
      the node to be removed
599 f5118ade Iustin Pop
  @rtype: int
600 f5118ade Iustin Pop
  @return: the desired exit code
601 f5118ade Iustin Pop

602 f5118ade Iustin Pop
  """
603 f5118ade Iustin Pop
  node = args[0]
604 f5118ade Iustin Pop
  if (not opts.confirm and
605 f5118ade Iustin Pop
      not AskUser("Are you sure you want to hard powercycle node %s?" % node)):
606 f5118ade Iustin Pop
    return 2
607 f5118ade Iustin Pop
608 e0d4735f Iustin Pop
  op = opcodes.OpNodePowercycle(node_name=node, force=opts.force)
609 c5a66db3 Michael Hanselmann
  result = SubmitOrSend(op, opts)
610 48418fea Iustin Pop
  if result:
611 48418fea Iustin Pop
    ToStderr(result)
612 f5118ade Iustin Pop
  return 0
613 f5118ade Iustin Pop
614 f5118ade Iustin Pop
615 abefdcff René Nussbaumer
def PowerNode(opts, args):
616 abefdcff René Nussbaumer
  """Change/ask power state of a node.
617 abefdcff René Nussbaumer

618 abefdcff René Nussbaumer
  @param opts: the command line options selected by the user
619 abefdcff René Nussbaumer
  @type args: list
620 abefdcff René Nussbaumer
  @param args: should contain only one element, the name of
621 abefdcff René Nussbaumer
      the node to be removed
622 abefdcff René Nussbaumer
  @rtype: int
623 abefdcff René Nussbaumer
  @return: the desired exit code
624 abefdcff René Nussbaumer

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

704 a0724772 René Nussbaumer
  @param opts: the command line options selected by the user
705 a0724772 René Nussbaumer
  @type args: list
706 a0724772 René Nussbaumer
  @param args: should contain only one element, the name of
707 a0724772 René Nussbaumer
      the node to be removed
708 a0724772 René Nussbaumer
  @rtype: int
709 a0724772 René Nussbaumer
  @return: the desired exit code
710 a0724772 René Nussbaumer

711 a0724772 René Nussbaumer
  """
712 65a77fab René Nussbaumer
  op = opcodes.OpOobCommand(node_names=args, command=constants.OOB_HEALTH,
713 65a77fab René Nussbaumer
                            timeout=opts.oob_timeout)
714 a0724772 René Nussbaumer
  result = SubmitOpCode(op, opts=opts)
715 a0724772 René Nussbaumer
716 a0724772 René Nussbaumer
  if opts.no_headers:
717 a0724772 René Nussbaumer
    headers = None
718 a0724772 René Nussbaumer
  else:
719 a0724772 René Nussbaumer
    headers = {"node": "Node", "status": "Status"}
720 a0724772 René Nussbaumer
721 a0724772 René Nussbaumer
  errs = 0
722 a0724772 René Nussbaumer
  data = []
723 a0724772 René Nussbaumer
  for node_result in result:
724 a0724772 René Nussbaumer
    (node_tuple, data_tuple) = node_result
725 a0724772 René Nussbaumer
    (_, node_name) = node_tuple
726 a0724772 René Nussbaumer
    (data_status, data_node) = data_tuple
727 a0724772 René Nussbaumer
    if data_status == constants.RS_NORMAL:
728 a0724772 René Nussbaumer
      data.append([node_name, "%s=%s" % tuple(data_node[0])])
729 a0724772 René Nussbaumer
      for item, status in data_node[1:]:
730 a0724772 René Nussbaumer
        data.append(["", "%s=%s" % (item, status)])
731 a0724772 René Nussbaumer
    else:
732 a0724772 René Nussbaumer
      errs += 1
733 f2c6673d Michael Hanselmann
      data.append([node_name, cli.FormatResultError(data_status, True)])
734 a0724772 René Nussbaumer
735 a0724772 René Nussbaumer
  data = GenerateTable(separator=opts.separator, headers=headers,
736 a0724772 René Nussbaumer
                       fields=["node", "status"], data=data)
737 a0724772 René Nussbaumer
738 a0724772 René Nussbaumer
  for line in data:
739 a0724772 René Nussbaumer
    ToStdout(line)
740 a0724772 René Nussbaumer
741 a0724772 René Nussbaumer
  if errs:
742 a0724772 René Nussbaumer
    return constants.EXIT_FAILURE
743 a0724772 René Nussbaumer
  else:
744 a0724772 René Nussbaumer
    return constants.EXIT_SUCCESS
745 a0724772 René Nussbaumer
746 a0724772 René Nussbaumer
747 dcb93971 Michael Hanselmann
def ListVolumes(opts, args):
748 dcb93971 Michael Hanselmann
  """List logical volumes on node(s).
749 dcb93971 Michael Hanselmann

750 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
751 ebf366ee Iustin Pop
  @type args: list
752 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
753 ebf366ee Iustin Pop
      we list data for all nodes, or contain a list of nodes
754 ebf366ee Iustin Pop
      to display data only for those
755 ebf366ee Iustin Pop
  @rtype: int
756 ebf366ee Iustin Pop
  @return: the desired exit code
757 ebf366ee Iustin Pop

758 dcb93971 Michael Hanselmann
  """
759 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_VOL_DEF_FIELDS)
760 dcb93971 Michael Hanselmann
761 8ed55bfd Iustin Pop
  op = opcodes.OpNodeQueryvols(nodes=args, output_fields=selected_fields)
762 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
763 dcb93971 Michael Hanselmann
764 dcb93971 Michael Hanselmann
  if not opts.no_headers:
765 137161c9 Michael Hanselmann
    headers = {"node": "Node", "phys": "PhysDev",
766 137161c9 Michael Hanselmann
               "vg": "VG", "name": "Name",
767 137161c9 Michael Hanselmann
               "size": "Size", "instance": "Instance"}
768 137161c9 Michael Hanselmann
  else:
769 137161c9 Michael Hanselmann
    headers = None
770 137161c9 Michael Hanselmann
771 9fbfbb7b Iustin Pop
  unitfields = ["size"]
772 137161c9 Michael Hanselmann
773 137161c9 Michael Hanselmann
  numfields = ["size"]
774 137161c9 Michael Hanselmann
775 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
776 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
777 9fbfbb7b Iustin Pop
                       numfields=numfields, data=output, units=opts.units)
778 16be8703 Iustin Pop
779 16be8703 Iustin Pop
  for line in data:
780 3a24c527 Iustin Pop
    ToStdout(line)
781 dcb93971 Michael Hanselmann
782 dcb93971 Michael Hanselmann
  return 0
783 dcb93971 Michael Hanselmann
784 dcb93971 Michael Hanselmann
785 9b94905f Iustin Pop
def ListStorage(opts, args):
786 4007f57d Michael Hanselmann
  """List physical volumes on node(s).
787 4007f57d Michael Hanselmann

788 4007f57d Michael Hanselmann
  @param opts: the command line options selected by the user
789 4007f57d Michael Hanselmann
  @type args: list
790 4007f57d Michael Hanselmann
  @param args: should either be an empty list, in which case
791 4007f57d Michael Hanselmann
      we list data for all nodes, or contain a list of nodes
792 4007f57d Michael Hanselmann
      to display data only for those
793 4007f57d Michael Hanselmann
  @rtype: int
794 4007f57d Michael Hanselmann
  @return: the desired exit code
795 4007f57d Michael Hanselmann

796 4007f57d Michael Hanselmann
  """
797 53548798 Michael Hanselmann
  # TODO: Default to ST_FILE if LVM is disabled on the cluster
798 53548798 Michael Hanselmann
  if opts.user_storage_type is None:
799 53548798 Michael Hanselmann
    opts.user_storage_type = constants.ST_LVM_PV
800 53548798 Michael Hanselmann
801 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(opts.user_storage_type)
802 53548798 Michael Hanselmann
803 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_STOR_DEF_FIELDS)
804 4007f57d Michael Hanselmann
805 ad8d0595 Iustin Pop
  op = opcodes.OpNodeQueryStorage(nodes=args,
806 53548798 Michael Hanselmann
                                  storage_type=storage_type,
807 4007f57d Michael Hanselmann
                                  output_fields=selected_fields)
808 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
809 4007f57d Michael Hanselmann
810 4007f57d Michael Hanselmann
  if not opts.no_headers:
811 4007f57d Michael Hanselmann
    headers = {
812 620a85fd Iustin Pop
      constants.SF_NODE: "Node",
813 620a85fd Iustin Pop
      constants.SF_TYPE: "Type",
814 4007f57d Michael Hanselmann
      constants.SF_NAME: "Name",
815 4007f57d Michael Hanselmann
      constants.SF_SIZE: "Size",
816 4007f57d Michael Hanselmann
      constants.SF_USED: "Used",
817 4007f57d Michael Hanselmann
      constants.SF_FREE: "Free",
818 4007f57d Michael Hanselmann
      constants.SF_ALLOCATABLE: "Allocatable",
819 4007f57d Michael Hanselmann
      }
820 4007f57d Michael Hanselmann
  else:
821 4007f57d Michael Hanselmann
    headers = None
822 4007f57d Michael Hanselmann
823 4007f57d Michael Hanselmann
  unitfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
824 4007f57d Michael Hanselmann
  numfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
825 4007f57d Michael Hanselmann
826 dc09c3cf Iustin Pop
  # change raw values to nicer strings
827 dc09c3cf Iustin Pop
  for row in output:
828 dc09c3cf Iustin Pop
    for idx, field in enumerate(selected_fields):
829 dc09c3cf Iustin Pop
      val = row[idx]
830 dc09c3cf Iustin Pop
      if field == constants.SF_ALLOCATABLE:
831 dc09c3cf Iustin Pop
        if val:
832 dc09c3cf Iustin Pop
          val = "Y"
833 dc09c3cf Iustin Pop
        else:
834 dc09c3cf Iustin Pop
          val = "N"
835 dc09c3cf Iustin Pop
      row[idx] = str(val)
836 dc09c3cf Iustin Pop
837 4007f57d Michael Hanselmann
  data = GenerateTable(separator=opts.separator, headers=headers,
838 4007f57d Michael Hanselmann
                       fields=selected_fields, unitfields=unitfields,
839 4007f57d Michael Hanselmann
                       numfields=numfields, data=output, units=opts.units)
840 4007f57d Michael Hanselmann
841 4007f57d Michael Hanselmann
  for line in data:
842 4007f57d Michael Hanselmann
    ToStdout(line)
843 4007f57d Michael Hanselmann
844 4007f57d Michael Hanselmann
  return 0
845 4007f57d Michael Hanselmann
846 4007f57d Michael Hanselmann
847 9b94905f Iustin Pop
def ModifyStorage(opts, args):
848 0e89fc2d Michael Hanselmann
  """Modify storage volume on a node.
849 0e89fc2d Michael Hanselmann

850 0e89fc2d Michael Hanselmann
  @param opts: the command line options selected by the user
851 0e89fc2d Michael Hanselmann
  @type args: list
852 0e89fc2d Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
853 0e89fc2d Michael Hanselmann
  @rtype: int
854 0e89fc2d Michael Hanselmann
  @return: the desired exit code
855 0e89fc2d Michael Hanselmann

856 0e89fc2d Michael Hanselmann
  """
857 0e89fc2d Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
858 0e89fc2d Michael Hanselmann
859 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
860 0e89fc2d Michael Hanselmann
861 0e89fc2d Michael Hanselmann
  changes = {}
862 0e89fc2d Michael Hanselmann
863 0e89fc2d Michael Hanselmann
  if opts.allocatable is not None:
864 e7b61bb0 Iustin Pop
    changes[constants.SF_ALLOCATABLE] = opts.allocatable
865 0e89fc2d Michael Hanselmann
866 0e89fc2d Michael Hanselmann
  if changes:
867 2cee4077 Iustin Pop
    op = opcodes.OpNodeModifyStorage(node_name=node_name,
868 0e89fc2d Michael Hanselmann
                                     storage_type=storage_type,
869 0e89fc2d Michael Hanselmann
                                     name=volume_name,
870 0e89fc2d Michael Hanselmann
                                     changes=changes)
871 c5a66db3 Michael Hanselmann
    SubmitOrSend(op, opts)
872 620a85fd Iustin Pop
  else:
873 620a85fd Iustin Pop
    ToStderr("No changes to perform, exiting.")
874 0e89fc2d Michael Hanselmann
875 0e89fc2d Michael Hanselmann
876 9b94905f Iustin Pop
def RepairStorage(opts, args):
877 1e3463f1 Michael Hanselmann
  """Repairs a storage volume on a node.
878 1e3463f1 Michael Hanselmann

879 1e3463f1 Michael Hanselmann
  @param opts: the command line options selected by the user
880 1e3463f1 Michael Hanselmann
  @type args: list
881 1e3463f1 Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
882 1e3463f1 Michael Hanselmann
  @rtype: int
883 1e3463f1 Michael Hanselmann
  @return: the desired exit code
884 1e3463f1 Michael Hanselmann

885 1e3463f1 Michael Hanselmann
  """
886 1e3463f1 Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
887 1e3463f1 Michael Hanselmann
888 1e3463f1 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
889 1e3463f1 Michael Hanselmann
890 1e3463f1 Michael Hanselmann
  op = opcodes.OpRepairNodeStorage(node_name=node_name,
891 1e3463f1 Michael Hanselmann
                                   storage_type=storage_type,
892 7e9c6a78 Iustin Pop
                                   name=volume_name,
893 7e9c6a78 Iustin Pop
                                   ignore_consistency=opts.ignore_consistency)
894 c5a66db3 Michael Hanselmann
  SubmitOrSend(op, opts)
895 1e3463f1 Michael Hanselmann
896 1e3463f1 Michael Hanselmann
897 b31c8676 Iustin Pop
def SetNodeParams(opts, args):
898 b31c8676 Iustin Pop
  """Modifies a node.
899 b31c8676 Iustin Pop

900 b31c8676 Iustin Pop
  @param opts: the command line options selected by the user
901 b31c8676 Iustin Pop
  @type args: list
902 b31c8676 Iustin Pop
  @param args: should contain only one element, the node name
903 b31c8676 Iustin Pop
  @rtype: int
904 b31c8676 Iustin Pop
  @return: the desired exit code
905 b31c8676 Iustin Pop

906 b31c8676 Iustin Pop
  """
907 53919782 Iustin Pop
  all_changes = [opts.master_candidate, opts.drained, opts.offline,
908 4e37f591 René Nussbaumer
                 opts.master_capable, opts.vm_capable, opts.secondary_ip,
909 4e37f591 René Nussbaumer
                 opts.ndparams]
910 0ec2ce46 René Nussbaumer
  if (all_changes.count(None) == len(all_changes) and
911 0ec2ce46 René Nussbaumer
      not (opts.hv_state or opts.disk_state)):
912 b31c8676 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
913 b31c8676 Iustin Pop
    return 1
914 b31c8676 Iustin Pop
915 0ec2ce46 René Nussbaumer
  if opts.disk_state:
916 0ec2ce46 René Nussbaumer
    disk_state = utils.FlatToDict(opts.disk_state)
917 0ec2ce46 René Nussbaumer
  else:
918 0ec2ce46 René Nussbaumer
    disk_state = {}
919 0ec2ce46 René Nussbaumer
920 0ec2ce46 René Nussbaumer
  hv_state = dict(opts.hv_state)
921 0ec2ce46 René Nussbaumer
922 f13973c4 Iustin Pop
  op = opcodes.OpNodeSetParams(node_name=args[0],
923 e7b61bb0 Iustin Pop
                               master_candidate=opts.master_candidate,
924 e7b61bb0 Iustin Pop
                               offline=opts.offline,
925 e7b61bb0 Iustin Pop
                               drained=opts.drained,
926 f91e255a Iustin Pop
                               master_capable=opts.master_capable,
927 53919782 Iustin Pop
                               vm_capable=opts.vm_capable,
928 4d32c211 Guido Trotter
                               secondary_ip=opts.secondary_ip,
929 4c61d894 Iustin Pop
                               force=opts.force,
930 4e37f591 René Nussbaumer
                               ndparams=opts.ndparams,
931 dd94e9f6 René Nussbaumer
                               auto_promote=opts.auto_promote,
932 0ec2ce46 René Nussbaumer
                               powered=opts.node_powered,
933 0ec2ce46 René Nussbaumer
                               hv_state=hv_state,
934 0ec2ce46 René Nussbaumer
                               disk_state=disk_state)
935 b31c8676 Iustin Pop
936 b31c8676 Iustin Pop
  # even if here we process the result, we allow submit only
937 b31c8676 Iustin Pop
  result = SubmitOrSend(op, opts)
938 b31c8676 Iustin Pop
939 b31c8676 Iustin Pop
  if result:
940 b31c8676 Iustin Pop
    ToStdout("Modified node %s", args[0])
941 b31c8676 Iustin Pop
    for param, data in result:
942 b31c8676 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
943 b31c8676 Iustin Pop
  return 0
944 b31c8676 Iustin Pop
945 b31c8676 Iustin Pop
946 6d846d0e Michael Hanselmann
def RestrictedCommand(opts, args):
947 6d846d0e Michael Hanselmann
  """Runs a remote command on node(s).
948 6d846d0e Michael Hanselmann

949 6d846d0e Michael Hanselmann
  @param opts: Command line options selected by user
950 6d846d0e Michael Hanselmann
  @type args: list
951 6d846d0e Michael Hanselmann
  @param args: Command line arguments
952 6d846d0e Michael Hanselmann
  @rtype: int
953 6d846d0e Michael Hanselmann
  @return: Exit code
954 6d846d0e Michael Hanselmann

955 6d846d0e Michael Hanselmann
  """
956 6d846d0e Michael Hanselmann
  cl = GetClient()
957 6d846d0e Michael Hanselmann
958 6d846d0e Michael Hanselmann
  if len(args) > 1 or opts.nodegroup:
959 6d846d0e Michael Hanselmann
    # Expand node names
960 6d846d0e Michael Hanselmann
    nodes = GetOnlineNodes(nodes=args[1:], cl=cl, nodegroup=opts.nodegroup)
961 6d846d0e Michael Hanselmann
  else:
962 6d846d0e Michael Hanselmann
    raise errors.OpPrereqError("Node group or node names must be given",
963 6d846d0e Michael Hanselmann
                               errors.ECODE_INVAL)
964 6d846d0e Michael Hanselmann
965 6d846d0e Michael Hanselmann
  op = opcodes.OpRestrictedCommand(command=args[0], nodes=nodes,
966 6d846d0e Michael Hanselmann
                                   use_locking=opts.do_locking)
967 6d846d0e Michael Hanselmann
  result = SubmitOrSend(op, opts, cl=cl)
968 6d846d0e Michael Hanselmann
969 6d846d0e Michael Hanselmann
  exit_code = constants.EXIT_SUCCESS
970 6d846d0e Michael Hanselmann
971 6d846d0e Michael Hanselmann
  for (node, (status, text)) in zip(nodes, result):
972 6d846d0e Michael Hanselmann
    ToStdout("------------------------------------------------")
973 6d846d0e Michael Hanselmann
    if status:
974 6d846d0e Michael Hanselmann
      if opts.show_machine_names:
975 6d846d0e Michael Hanselmann
        for line in text.splitlines():
976 6d846d0e Michael Hanselmann
          ToStdout("%s: %s", node, line)
977 6d846d0e Michael Hanselmann
      else:
978 6d846d0e Michael Hanselmann
        ToStdout("Node: %s", node)
979 6d846d0e Michael Hanselmann
        ToStdout(text)
980 6d846d0e Michael Hanselmann
    else:
981 6d846d0e Michael Hanselmann
      exit_code = constants.EXIT_FAILURE
982 6d846d0e Michael Hanselmann
      ToStdout(text)
983 6d846d0e Michael Hanselmann
984 6d846d0e Michael Hanselmann
  return exit_code
985 6d846d0e Michael Hanselmann
986 6d846d0e Michael Hanselmann
987 7acbda7b Iustin Pop
class ReplyStatus(object):
988 7acbda7b Iustin Pop
  """Class holding a reply status for synchronous confd clients.
989 7acbda7b Iustin Pop

990 7acbda7b Iustin Pop
  """
991 7acbda7b Iustin Pop
  def __init__(self):
992 7acbda7b Iustin Pop
    self.failure = True
993 7acbda7b Iustin Pop
    self.answer = False
994 7acbda7b Iustin Pop
995 7acbda7b Iustin Pop
996 7acbda7b Iustin Pop
def ListDrbd(opts, args):
997 7acbda7b Iustin Pop
  """Modifies a node.
998 7acbda7b Iustin Pop

999 7acbda7b Iustin Pop
  @param opts: the command line options selected by the user
1000 7acbda7b Iustin Pop
  @type args: list
1001 7acbda7b Iustin Pop
  @param args: should contain only one element, the node name
1002 7acbda7b Iustin Pop
  @rtype: int
1003 7acbda7b Iustin Pop
  @return: the desired exit code
1004 7acbda7b Iustin Pop

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