Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ 653bc0f1

History | View | Annotate | Download (37.9 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 5a904197 Santi Raffa
  constants.ST_SHARED_FILE: "sharedfile",
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 a9f33339 Petr Pudlak
def _SetupSSH(options, cluster_name, node, ssh_port):
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 a9f33339 Petr Pudlak
  @type ssh_port: int
194 a9f33339 Petr Pudlak
  @param ssh_port: Destination node ssh port
195 f1bebf4c Iustin Pop

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

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

234 05ccd983 Guido Trotter
  """
235 87622829 Iustin Pop
  cl = GetClient()
236 bc57fa8d Helga Velroyen
  query_cl = GetClient(query=True)
237 b705c7a6 Manuel Franceschini
  node = netutils.GetHostname(name=args[0]).name
238 82e12743 Iustin Pop
  readd = opts.readd
239 82e12743 Iustin Pop
240 a9f33339 Petr Pudlak
  # Retrieve relevant parameters of the node group.
241 a9f33339 Petr Pudlak
  ssh_port = None
242 651ce6a3 Petr Pudlak
  try:
243 651ce6a3 Petr Pudlak
    # Passing [] to QueryGroups means query the default group:
244 651ce6a3 Petr Pudlak
    node_groups = [opts.nodegroup] if opts.nodegroup is not None else []
245 fbde16f0 Helga Velroyen
    output = query_cl.QueryGroups(names=node_groups, fields=["ndp/ssh_port"],
246 fbde16f0 Helga Velroyen
                                  use_locking=False)
247 651ce6a3 Petr Pudlak
    (ssh_port, ) = output[0]
248 651ce6a3 Petr Pudlak
  except (errors.OpPrereqError, errors.OpExecError):
249 651ce6a3 Petr Pudlak
    pass
250 a9f33339 Petr Pudlak
251 82e12743 Iustin Pop
  try:
252 bc57fa8d Helga Velroyen
    output = query_cl.QueryNodes(names=[node],
253 bc57fa8d Helga Velroyen
                                 fields=["name", "sip", "master",
254 bc57fa8d Helga Velroyen
                                         "ndp/ssh_port"],
255 bc57fa8d Helga Velroyen
                                 use_locking=False)
256 929efcc3 Klaus Aehlig
    if len(output) == 0:
257 929efcc3 Klaus Aehlig
      node_exists = ""
258 929efcc3 Klaus Aehlig
      sip = None
259 929efcc3 Klaus Aehlig
    else:
260 929efcc3 Klaus Aehlig
      node_exists, sip, is_master, ssh_port = output[0]
261 82e12743 Iustin Pop
  except (errors.OpPrereqError, errors.OpExecError):
262 82e12743 Iustin Pop
    node_exists = ""
263 82e12743 Iustin Pop
    sip = None
264 82e12743 Iustin Pop
265 82e12743 Iustin Pop
  if readd:
266 82e12743 Iustin Pop
    if not node_exists:
267 82e12743 Iustin Pop
      ToStderr("Node %s not in the cluster"
268 82e12743 Iustin Pop
               " - please retry without '--readd'", node)
269 82e12743 Iustin Pop
      return 1
270 d833acc6 Iustin Pop
    if is_master:
271 d833acc6 Iustin Pop
      ToStderr("Node %s is the master, cannot readd", node)
272 d833acc6 Iustin Pop
      return 1
273 82e12743 Iustin Pop
  else:
274 82e12743 Iustin Pop
    if node_exists:
275 3a24c527 Iustin Pop
      ToStderr("Node %s already in the cluster (as %s)"
276 82e12743 Iustin Pop
               " - please retry with '--readd'", node, node_exists)
277 05ccd983 Guido Trotter
      return 1
278 82e12743 Iustin Pop
    sip = opts.secondary_ip
279 05ccd983 Guido Trotter
280 87622829 Iustin Pop
  # read the cluster name from the master
281 224ff0f7 Michael Hanselmann
  (cluster_name, ) = cl.QueryConfigValues(["cluster_name"])
282 87622829 Iustin Pop
283 3ef51126 René Nussbaumer
  if not readd and opts.node_setup:
284 82e12743 Iustin Pop
    ToStderr("-- WARNING -- \n"
285 82e12743 Iustin Pop
             "Performing this operation is going to replace the ssh daemon"
286 82e12743 Iustin Pop
             " keypair\n"
287 82e12743 Iustin Pop
             "on the target machine (%s) with the ones of the"
288 82e12743 Iustin Pop
             " current one\n"
289 82e12743 Iustin Pop
             "and grant full intra-cluster ssh root access to/from it\n", node)
290 05ccd983 Guido Trotter
291 2e6469a1 René Nussbaumer
  if opts.node_setup:
292 a9f33339 Petr Pudlak
    _SetupSSH(opts, cluster_name, node, ssh_port)
293 827f753e Guido Trotter
294 a9f33339 Petr Pudlak
  bootstrap.SetupNodeDaemon(opts, cluster_name, node, ssh_port)
295 3ef51126 René Nussbaumer
296 085e0d9f René Nussbaumer
  if opts.disk_state:
297 085e0d9f René Nussbaumer
    disk_state = utils.FlatToDict(opts.disk_state)
298 085e0d9f René Nussbaumer
  else:
299 085e0d9f René Nussbaumer
    disk_state = {}
300 085e0d9f René Nussbaumer
301 085e0d9f René Nussbaumer
  hv_state = dict(opts.hv_state)
302 085e0d9f René Nussbaumer
303 d817d49f Iustin Pop
  op = opcodes.OpNodeAdd(node_name=args[0], secondary_ip=sip,
304 fd3d37b6 Iustin Pop
                         readd=opts.readd, group=opts.nodegroup,
305 818e28cf Thomas Thrainer
                         vm_capable=opts.vm_capable, ndparams=opts.ndparams,
306 085e0d9f René Nussbaumer
                         master_capable=opts.master_capable,
307 085e0d9f René Nussbaumer
                         disk_state=disk_state,
308 085e0d9f René Nussbaumer
                         hv_state=hv_state)
309 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
310 a8083063 Iustin Pop
311 a8083063 Iustin Pop
312 a8083063 Iustin Pop
def ListNodes(opts, args):
313 a8083063 Iustin Pop
  """List nodes and their properties.
314 a8083063 Iustin Pop

315 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
316 ebf366ee Iustin Pop
  @type args: list
317 982ed68e Adeodato Simo
  @param args: nodes to list, or empty for all
318 ebf366ee Iustin Pop
  @rtype: int
319 ebf366ee Iustin Pop
  @return: the desired exit code
320 ebf366ee Iustin Pop

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

338 7f5443a0 Michael Hanselmann
  @param opts: the command line options selected by the user
339 7f5443a0 Michael Hanselmann
  @type args: list
340 7f5443a0 Michael Hanselmann
  @param args: fields to list, or empty for all
341 7f5443a0 Michael Hanselmann
  @rtype: int
342 7f5443a0 Michael Hanselmann
  @return: the desired exit code
343 a8083063 Iustin Pop

344 7f5443a0 Michael Hanselmann
  """
345 9fbf0098 Iustin Pop
  cl = GetClient(query=True)
346 9fbf0098 Iustin Pop
347 7f5443a0 Michael Hanselmann
  return GenericListFields(constants.QR_NODE, args, opts.separator,
348 9fbf0098 Iustin Pop
                           not opts.no_headers, cl=cl)
349 a8083063 Iustin Pop
350 a8083063 Iustin Pop
351 a5bc662a Iustin Pop
def EvacuateNode(opts, args):
352 a5bc662a Iustin Pop
  """Relocate all secondary instance from a node.
353 a5bc662a Iustin Pop

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

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

434 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
435 ebf366ee Iustin Pop
  @type args: list
436 ebf366ee Iustin Pop
  @param args: should be an empty list
437 ebf366ee Iustin Pop
  @rtype: int
438 ebf366ee Iustin Pop
  @return: the desired exit code
439 ebf366ee Iustin Pop

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

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

544 5f6d1b42 Bernardo Dal Seno
  """
545 5f6d1b42 Bernardo Dal Seno
  (name, primary_ip, secondary_ip, pinst, sinst, is_mc, drained, offline,
546 5f6d1b42 Bernardo Dal Seno
   master_capable, vm_capable, powered, ndparams, ndparams_custom) = node_info
547 5f6d1b42 Bernardo Dal Seno
  info = [
548 5f6d1b42 Bernardo Dal Seno
    ("Node name", name),
549 5f6d1b42 Bernardo Dal Seno
    ("primary ip", primary_ip),
550 5f6d1b42 Bernardo Dal Seno
    ("secondary ip", secondary_ip),
551 5f6d1b42 Bernardo Dal Seno
    ("master candidate", is_mc),
552 5f6d1b42 Bernardo Dal Seno
    ("drained", drained),
553 5f6d1b42 Bernardo Dal Seno
    ("offline", offline),
554 5f6d1b42 Bernardo Dal Seno
    ]
555 5f6d1b42 Bernardo Dal Seno
  if powered is not None:
556 5f6d1b42 Bernardo Dal Seno
    info.append(("powered", powered))
557 5f6d1b42 Bernardo Dal Seno
  info.extend([
558 5f6d1b42 Bernardo Dal Seno
    ("master_capable", master_capable),
559 5f6d1b42 Bernardo Dal Seno
    ("vm_capable", vm_capable),
560 5f6d1b42 Bernardo Dal Seno
    ])
561 5f6d1b42 Bernardo Dal Seno
  if vm_capable:
562 5f6d1b42 Bernardo Dal Seno
    info.extend([
563 5f6d1b42 Bernardo Dal Seno
      ("primary for instances",
564 5f6d1b42 Bernardo Dal Seno
       [iname for iname in utils.NiceSort(pinst)]),
565 5f6d1b42 Bernardo Dal Seno
      ("secondary for instances",
566 5f6d1b42 Bernardo Dal Seno
       [iname for iname in utils.NiceSort(sinst)]),
567 5f6d1b42 Bernardo Dal Seno
      ])
568 5f6d1b42 Bernardo Dal Seno
  info.append(("node parameters",
569 5f6d1b42 Bernardo Dal Seno
               FormatParamsDictInfo(ndparams_custom, ndparams)))
570 5f6d1b42 Bernardo Dal Seno
  return info
571 5f6d1b42 Bernardo Dal Seno
572 5f6d1b42 Bernardo Dal Seno
573 a8083063 Iustin Pop
def ShowNodeConfig(opts, args):
574 a8083063 Iustin Pop
  """Show node information.
575 a8083063 Iustin Pop

576 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
577 ebf366ee Iustin Pop
  @type args: list
578 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
579 ebf366ee Iustin Pop
      we show information about all nodes, or should contain
580 ebf366ee Iustin Pop
      a list of nodes to be queried for information
581 ebf366ee Iustin Pop
  @rtype: int
582 ebf366ee Iustin Pop
  @return: the desired exit code
583 ebf366ee Iustin Pop

584 a8083063 Iustin Pop
  """
585 9fbf0098 Iustin Pop
  cl = GetClient(query=True)
586 2e7b8369 Iustin Pop
  result = cl.QueryNodes(fields=["name", "pip", "sip",
587 0b2454b9 Iustin Pop
                                 "pinst_list", "sinst_list",
588 7b4978ad Iustin Pop
                                 "master_candidate", "drained", "offline",
589 8572f1fe René Nussbaumer
                                 "master_capable", "vm_capable", "powered",
590 8572f1fe René Nussbaumer
                                 "ndparams", "custom_ndparams"],
591 77921a95 Iustin Pop
                         names=args, use_locking=False)
592 5f6d1b42 Bernardo Dal Seno
  PrintGenericInfo([
593 5f6d1b42 Bernardo Dal Seno
    _FormatNodeInfo(node_info)
594 5f6d1b42 Bernardo Dal Seno
    for node_info in result
595 5f6d1b42 Bernardo Dal Seno
    ])
596 a8083063 Iustin Pop
  return 0
597 a8083063 Iustin Pop
598 a8083063 Iustin Pop
599 a8083063 Iustin Pop
def RemoveNode(opts, args):
600 ebf366ee Iustin Pop
  """Remove a node from the cluster.
601 ebf366ee Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

867 0e89fc2d Michael Hanselmann
  @param opts: the command line options selected by the user
868 0e89fc2d Michael Hanselmann
  @type args: list
869 0e89fc2d Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
870 0e89fc2d Michael Hanselmann
  @rtype: int
871 0e89fc2d Michael Hanselmann
  @return: the desired exit code
872 0e89fc2d Michael Hanselmann

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

896 1e3463f1 Michael Hanselmann
  @param opts: the command line options selected by the user
897 1e3463f1 Michael Hanselmann
  @type args: list
898 1e3463f1 Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
899 1e3463f1 Michael Hanselmann
  @rtype: int
900 1e3463f1 Michael Hanselmann
  @return: the desired exit code
901 1e3463f1 Michael Hanselmann

902 1e3463f1 Michael Hanselmann
  """
903 1e3463f1 Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
904 1e3463f1 Michael Hanselmann
905 1e3463f1 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
906 1e3463f1 Michael Hanselmann
907 1e3463f1 Michael Hanselmann
  op = opcodes.OpRepairNodeStorage(node_name=node_name,
908 1e3463f1 Michael Hanselmann
                                   storage_type=storage_type,
909 7e9c6a78 Iustin Pop
                                   name=volume_name,
910 7e9c6a78 Iustin Pop
                                   ignore_consistency=opts.ignore_consistency)
911 c5a66db3 Michael Hanselmann
  SubmitOrSend(op, opts)
912 1e3463f1 Michael Hanselmann
913 1e3463f1 Michael Hanselmann
914 b31c8676 Iustin Pop
def SetNodeParams(opts, args):
915 b31c8676 Iustin Pop
  """Modifies a node.
916 b31c8676 Iustin Pop

917 b31c8676 Iustin Pop
  @param opts: the command line options selected by the user
918 b31c8676 Iustin Pop
  @type args: list
919 b31c8676 Iustin Pop
  @param args: should contain only one element, the node name
920 b31c8676 Iustin Pop
  @rtype: int
921 b31c8676 Iustin Pop
  @return: the desired exit code
922 b31c8676 Iustin Pop

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

966 6d846d0e Michael Hanselmann
  @param opts: Command line options selected by user
967 6d846d0e Michael Hanselmann
  @type args: list
968 6d846d0e Michael Hanselmann
  @param args: Command line arguments
969 6d846d0e Michael Hanselmann
  @rtype: int
970 6d846d0e Michael Hanselmann
  @return: Exit code
971 6d846d0e Michael Hanselmann

972 6d846d0e Michael Hanselmann
  """
973 6d846d0e Michael Hanselmann
  cl = GetClient()
974 6d846d0e Michael Hanselmann
975 6d846d0e Michael Hanselmann
  if len(args) > 1 or opts.nodegroup:
976 6d846d0e Michael Hanselmann
    # Expand node names
977 6d846d0e Michael Hanselmann
    nodes = GetOnlineNodes(nodes=args[1:], cl=cl, nodegroup=opts.nodegroup)
978 6d846d0e Michael Hanselmann
  else:
979 6d846d0e Michael Hanselmann
    raise errors.OpPrereqError("Node group or node names must be given",
980 6d846d0e Michael Hanselmann
                               errors.ECODE_INVAL)
981 6d846d0e Michael Hanselmann
982 6d846d0e Michael Hanselmann
  op = opcodes.OpRestrictedCommand(command=args[0], nodes=nodes,
983 6d846d0e Michael Hanselmann
                                   use_locking=opts.do_locking)
984 6d846d0e Michael Hanselmann
  result = SubmitOrSend(op, opts, cl=cl)
985 6d846d0e Michael Hanselmann
986 6d846d0e Michael Hanselmann
  exit_code = constants.EXIT_SUCCESS
987 6d846d0e Michael Hanselmann
988 6d846d0e Michael Hanselmann
  for (node, (status, text)) in zip(nodes, result):
989 6d846d0e Michael Hanselmann
    ToStdout("------------------------------------------------")
990 6d846d0e Michael Hanselmann
    if status:
991 6d846d0e Michael Hanselmann
      if opts.show_machine_names:
992 6d846d0e Michael Hanselmann
        for line in text.splitlines():
993 6d846d0e Michael Hanselmann
          ToStdout("%s: %s", node, line)
994 6d846d0e Michael Hanselmann
      else:
995 6d846d0e Michael Hanselmann
        ToStdout("Node: %s", node)
996 6d846d0e Michael Hanselmann
        ToStdout(text)
997 6d846d0e Michael Hanselmann
    else:
998 6d846d0e Michael Hanselmann
      exit_code = constants.EXIT_FAILURE
999 6d846d0e Michael Hanselmann
      ToStdout(text)
1000 6d846d0e Michael Hanselmann
1001 6d846d0e Michael Hanselmann
  return exit_code
1002 6d846d0e Michael Hanselmann
1003 6d846d0e Michael Hanselmann
1004 7acbda7b Iustin Pop
class ReplyStatus(object):
1005 7acbda7b Iustin Pop
  """Class holding a reply status for synchronous confd clients.
1006 7acbda7b Iustin Pop

1007 7acbda7b Iustin Pop
  """
1008 7acbda7b Iustin Pop
  def __init__(self):
1009 7acbda7b Iustin Pop
    self.failure = True
1010 7acbda7b Iustin Pop
    self.answer = False
1011 7acbda7b Iustin Pop
1012 7acbda7b Iustin Pop
1013 7acbda7b Iustin Pop
def ListDrbd(opts, args):
1014 7acbda7b Iustin Pop
  """Modifies a node.
1015 7acbda7b Iustin Pop

1016 7acbda7b Iustin Pop
  @param opts: the command line options selected by the user
1017 7acbda7b Iustin Pop
  @type args: list
1018 7acbda7b Iustin Pop
  @param args: should contain only one element, the node name
1019 7acbda7b Iustin Pop
  @rtype: int
1020 7acbda7b Iustin Pop
  @return: the desired exit code
1021 7acbda7b Iustin Pop

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