Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ 178ad717

History | View | Annotate | Download (37.8 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 a9f33339 Petr Pudlak
    node_exists, sip, is_master, ssh_port = output[0]
257 82e12743 Iustin Pop
  except (errors.OpPrereqError, errors.OpExecError):
258 82e12743 Iustin Pop
    node_exists = ""
259 82e12743 Iustin Pop
    sip = None
260 82e12743 Iustin Pop
261 82e12743 Iustin Pop
  if readd:
262 82e12743 Iustin Pop
    if not node_exists:
263 82e12743 Iustin Pop
      ToStderr("Node %s not in the cluster"
264 82e12743 Iustin Pop
               " - please retry without '--readd'", node)
265 82e12743 Iustin Pop
      return 1
266 d833acc6 Iustin Pop
    if is_master:
267 d833acc6 Iustin Pop
      ToStderr("Node %s is the master, cannot readd", node)
268 d833acc6 Iustin Pop
      return 1
269 82e12743 Iustin Pop
  else:
270 82e12743 Iustin Pop
    if node_exists:
271 3a24c527 Iustin Pop
      ToStderr("Node %s already in the cluster (as %s)"
272 82e12743 Iustin Pop
               " - please retry with '--readd'", node, node_exists)
273 05ccd983 Guido Trotter
      return 1
274 82e12743 Iustin Pop
    sip = opts.secondary_ip
275 05ccd983 Guido Trotter
276 87622829 Iustin Pop
  # read the cluster name from the master
277 224ff0f7 Michael Hanselmann
  (cluster_name, ) = cl.QueryConfigValues(["cluster_name"])
278 87622829 Iustin Pop
279 3ef51126 René Nussbaumer
  if not readd and opts.node_setup:
280 82e12743 Iustin Pop
    ToStderr("-- WARNING -- \n"
281 82e12743 Iustin Pop
             "Performing this operation is going to replace the ssh daemon"
282 82e12743 Iustin Pop
             " keypair\n"
283 82e12743 Iustin Pop
             "on the target machine (%s) with the ones of the"
284 82e12743 Iustin Pop
             " current one\n"
285 82e12743 Iustin Pop
             "and grant full intra-cluster ssh root access to/from it\n", node)
286 05ccd983 Guido Trotter
287 2e6469a1 René Nussbaumer
  if opts.node_setup:
288 a9f33339 Petr Pudlak
    _SetupSSH(opts, cluster_name, node, ssh_port)
289 827f753e Guido Trotter
290 a9f33339 Petr Pudlak
  bootstrap.SetupNodeDaemon(opts, cluster_name, node, ssh_port)
291 3ef51126 René Nussbaumer
292 085e0d9f René Nussbaumer
  if opts.disk_state:
293 085e0d9f René Nussbaumer
    disk_state = utils.FlatToDict(opts.disk_state)
294 085e0d9f René Nussbaumer
  else:
295 085e0d9f René Nussbaumer
    disk_state = {}
296 085e0d9f René Nussbaumer
297 085e0d9f René Nussbaumer
  hv_state = dict(opts.hv_state)
298 085e0d9f René Nussbaumer
299 d817d49f Iustin Pop
  op = opcodes.OpNodeAdd(node_name=args[0], secondary_ip=sip,
300 fd3d37b6 Iustin Pop
                         readd=opts.readd, group=opts.nodegroup,
301 818e28cf Thomas Thrainer
                         vm_capable=opts.vm_capable, ndparams=opts.ndparams,
302 085e0d9f René Nussbaumer
                         master_capable=opts.master_capable,
303 085e0d9f René Nussbaumer
                         disk_state=disk_state,
304 085e0d9f René Nussbaumer
                         hv_state=hv_state)
305 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
306 a8083063 Iustin Pop
307 a8083063 Iustin Pop
308 a8083063 Iustin Pop
def ListNodes(opts, args):
309 a8083063 Iustin Pop
  """List nodes and their properties.
310 a8083063 Iustin Pop

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

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

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

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

350 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
351 ebf366ee Iustin Pop
  @type args: list
352 ebf366ee Iustin Pop
  @param args: should be an empty list
353 ebf366ee Iustin Pop
  @rtype: int
354 ebf366ee Iustin Pop
  @return: the desired exit code
355 ebf366ee Iustin Pop

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

430 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
431 ebf366ee Iustin Pop
  @type args: list
432 ebf366ee Iustin Pop
  @param args: should be an empty list
433 ebf366ee Iustin Pop
  @rtype: int
434 ebf366ee Iustin Pop
  @return: the desired exit code
435 ebf366ee Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

962 6d846d0e Michael Hanselmann
  @param opts: Command line options selected by user
963 6d846d0e Michael Hanselmann
  @type args: list
964 6d846d0e Michael Hanselmann
  @param args: Command line arguments
965 6d846d0e Michael Hanselmann
  @rtype: int
966 6d846d0e Michael Hanselmann
  @return: Exit code
967 6d846d0e Michael Hanselmann

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

1003 7acbda7b Iustin Pop
  """
1004 7acbda7b Iustin Pop
  def __init__(self):
1005 7acbda7b Iustin Pop
    self.failure = True
1006 7acbda7b Iustin Pop
    self.answer = False
1007 7acbda7b Iustin Pop
1008 7acbda7b Iustin Pop
1009 7acbda7b Iustin Pop
def ListDrbd(opts, args):
1010 7acbda7b Iustin Pop
  """Modifies a node.
1011 7acbda7b Iustin Pop

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

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