Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ fb62843c

History | View | Annotate | Download (37.2 kB)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

522 5f6d1b42 Bernardo Dal Seno
  """
523 5f6d1b42 Bernardo Dal Seno
  (name, primary_ip, secondary_ip, pinst, sinst, is_mc, drained, offline,
524 5f6d1b42 Bernardo Dal Seno
   master_capable, vm_capable, powered, ndparams, ndparams_custom) = node_info
525 5f6d1b42 Bernardo Dal Seno
  info = [
526 5f6d1b42 Bernardo Dal Seno
    ("Node name", name),
527 5f6d1b42 Bernardo Dal Seno
    ("primary ip", primary_ip),
528 5f6d1b42 Bernardo Dal Seno
    ("secondary ip", secondary_ip),
529 5f6d1b42 Bernardo Dal Seno
    ("master candidate", is_mc),
530 5f6d1b42 Bernardo Dal Seno
    ("drained", drained),
531 5f6d1b42 Bernardo Dal Seno
    ("offline", offline),
532 5f6d1b42 Bernardo Dal Seno
    ]
533 5f6d1b42 Bernardo Dal Seno
  if powered is not None:
534 5f6d1b42 Bernardo Dal Seno
    info.append(("powered", powered))
535 5f6d1b42 Bernardo Dal Seno
  info.extend([
536 5f6d1b42 Bernardo Dal Seno
    ("master_capable", master_capable),
537 5f6d1b42 Bernardo Dal Seno
    ("vm_capable", vm_capable),
538 5f6d1b42 Bernardo Dal Seno
    ])
539 5f6d1b42 Bernardo Dal Seno
  if vm_capable:
540 5f6d1b42 Bernardo Dal Seno
    info.extend([
541 5f6d1b42 Bernardo Dal Seno
      ("primary for instances",
542 5f6d1b42 Bernardo Dal Seno
       [iname for iname in utils.NiceSort(pinst)]),
543 5f6d1b42 Bernardo Dal Seno
      ("secondary for instances",
544 5f6d1b42 Bernardo Dal Seno
       [iname for iname in utils.NiceSort(sinst)]),
545 5f6d1b42 Bernardo Dal Seno
      ])
546 5f6d1b42 Bernardo Dal Seno
  info.append(("node parameters",
547 5f6d1b42 Bernardo Dal Seno
               FormatParamsDictInfo(ndparams_custom, ndparams)))
548 5f6d1b42 Bernardo Dal Seno
  return info
549 5f6d1b42 Bernardo Dal Seno
550 5f6d1b42 Bernardo Dal Seno
551 a8083063 Iustin Pop
def ShowNodeConfig(opts, args):
552 a8083063 Iustin Pop
  """Show node information.
553 a8083063 Iustin Pop

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

562 a8083063 Iustin Pop
  """
563 9fbf0098 Iustin Pop
  cl = GetClient(query=True)
564 2e7b8369 Iustin Pop
  result = cl.QueryNodes(fields=["name", "pip", "sip",
565 0b2454b9 Iustin Pop
                                 "pinst_list", "sinst_list",
566 7b4978ad Iustin Pop
                                 "master_candidate", "drained", "offline",
567 8572f1fe René Nussbaumer
                                 "master_capable", "vm_capable", "powered",
568 8572f1fe René Nussbaumer
                                 "ndparams", "custom_ndparams"],
569 77921a95 Iustin Pop
                         names=args, use_locking=False)
570 5f6d1b42 Bernardo Dal Seno
  PrintGenericInfo([
571 5f6d1b42 Bernardo Dal Seno
    _FormatNodeInfo(node_info)
572 5f6d1b42 Bernardo Dal Seno
    for node_info in result
573 5f6d1b42 Bernardo Dal Seno
    ])
574 a8083063 Iustin Pop
  return 0
575 a8083063 Iustin Pop
576 a8083063 Iustin Pop
577 a8083063 Iustin Pop
def RemoveNode(opts, args):
578 ebf366ee Iustin Pop
  """Remove a node from the cluster.
579 ebf366ee Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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