Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ bc57fa8d

History | View | Annotate | Download (37.7 kB)

1 37494fa4 Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 5f6d1b42 Bernardo Dal Seno
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 7260cfbe Iustin Pop
"""Node related commands"""
22 a8083063 Iustin Pop
23 b459a848 Andrea Spadaccini
# pylint: disable=W0401,W0613,W0614,C0103
24 2f79bd34 Iustin Pop
# W0401: Wildcard import ganeti.cli
25 2d54e29c Iustin Pop
# W0613: Unused argument, since all functions follow the same API
26 2f79bd34 Iustin Pop
# W0614: Unused import %s from wildcard import (since we need cli)
27 7260cfbe Iustin Pop
# C0103: Invalid name gnt-node
28 2f79bd34 Iustin Pop
29 aafee533 Michael Hanselmann
import itertools
30 224ff0f7 Michael Hanselmann
import errno
31 aafee533 Michael Hanselmann
32 a8083063 Iustin Pop
from ganeti.cli import *
33 d363797e René Nussbaumer
from ganeti import cli
34 3ef51126 René Nussbaumer
from ganeti import bootstrap
35 a8083063 Iustin Pop
from ganeti import opcodes
36 a8083063 Iustin Pop
from ganeti import utils
37 846baef9 Iustin Pop
from ganeti import constants
38 c450e9b0 Iustin Pop
from ganeti import errors
39 a744b676 Manuel Franceschini
from ganeti import netutils
40 78e706bb Michael Hanselmann
from ganeti import pathutils
41 224ff0f7 Michael Hanselmann
from ganeti import ssh
42 b8028dcf Michael Hanselmann
from ganeti import compat
43 a8083063 Iustin Pop
44 7acbda7b Iustin Pop
from ganeti import confd
45 7acbda7b Iustin Pop
from ganeti.confd import client as confd_client
46 a8083063 Iustin Pop
47 ebf366ee Iustin Pop
#: default list of field for L{ListNodes}
48 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
49 48c4dfa8 Iustin Pop
  "name", "dtotal", "dfree",
50 48c4dfa8 Iustin Pop
  "mtotal", "mnode", "mfree",
51 48c4dfa8 Iustin Pop
  "pinst_cnt", "sinst_cnt",
52 48c4dfa8 Iustin Pop
  ]
53 48c4dfa8 Iustin Pop
54 620a85fd Iustin Pop
55 a4ebd726 Michael Hanselmann
#: Default field list for L{ListVolumes}
56 a4ebd726 Michael Hanselmann
_LIST_VOL_DEF_FIELDS = ["node", "phys", "vg", "name", "size", "instance"]
57 a4ebd726 Michael Hanselmann
58 a4ebd726 Michael Hanselmann
59 620a85fd Iustin Pop
#: default list of field for L{ListStorage}
60 620a85fd Iustin Pop
_LIST_STOR_DEF_FIELDS = [
61 620a85fd Iustin Pop
  constants.SF_NODE,
62 620a85fd Iustin Pop
  constants.SF_TYPE,
63 620a85fd Iustin Pop
  constants.SF_NAME,
64 620a85fd Iustin Pop
  constants.SF_SIZE,
65 620a85fd Iustin Pop
  constants.SF_USED,
66 620a85fd Iustin Pop
  constants.SF_FREE,
67 620a85fd Iustin Pop
  constants.SF_ALLOCATABLE,
68 620a85fd Iustin Pop
  ]
69 620a85fd Iustin Pop
70 620a85fd Iustin Pop
71 abefdcff René Nussbaumer
#: default list of power commands
72 abefdcff René Nussbaumer
_LIST_POWER_COMMANDS = ["on", "off", "cycle", "status"]
73 abefdcff René Nussbaumer
74 abefdcff René Nussbaumer
75 982ed68e Adeodato Simo
#: headers (and full field list) for L{ListStorage}
76 620a85fd Iustin Pop
_LIST_STOR_HEADERS = {
77 620a85fd Iustin Pop
  constants.SF_NODE: "Node",
78 620a85fd Iustin Pop
  constants.SF_TYPE: "Type",
79 620a85fd Iustin Pop
  constants.SF_NAME: "Name",
80 620a85fd Iustin Pop
  constants.SF_SIZE: "Size",
81 620a85fd Iustin Pop
  constants.SF_USED: "Used",
82 620a85fd Iustin Pop
  constants.SF_FREE: "Free",
83 620a85fd Iustin Pop
  constants.SF_ALLOCATABLE: "Allocatable",
84 620a85fd Iustin Pop
  }
85 620a85fd Iustin Pop
86 620a85fd Iustin Pop
87 0e89fc2d Michael Hanselmann
#: User-facing storage unit types
88 0e89fc2d Michael Hanselmann
_USER_STORAGE_TYPE = {
89 0e89fc2d Michael Hanselmann
  constants.ST_FILE: "file",
90 0e89fc2d Michael Hanselmann
  constants.ST_LVM_PV: "lvm-pv",
91 0e89fc2d Michael Hanselmann
  constants.ST_LVM_VG: "lvm-vg",
92 0e89fc2d Michael Hanselmann
  }
93 0e89fc2d Michael Hanselmann
94 a8005e17 Michael Hanselmann
_STORAGE_TYPE_OPT = \
95 aeaefce8 Iustin Pop
  cli_option("-t", "--storage-type",
96 a8005e17 Michael Hanselmann
             dest="user_storage_type",
97 a8005e17 Michael Hanselmann
             choices=_USER_STORAGE_TYPE.keys(),
98 a8005e17 Michael Hanselmann
             default=None,
99 a8005e17 Michael Hanselmann
             metavar="STORAGE_TYPE",
100 ab3e6da8 Iustin Pop
             help=("Storage type (%s)" %
101 ab3e6da8 Iustin Pop
                   utils.CommaJoin(_USER_STORAGE_TYPE.keys())))
102 a8005e17 Michael Hanselmann
103 a8005e17 Michael Hanselmann
_REPAIRABLE_STORAGE_TYPES = \
104 a8005e17 Michael Hanselmann
  [st for st, so in constants.VALID_STORAGE_OPERATIONS.iteritems()
105 a8005e17 Michael Hanselmann
   if constants.SO_FIX_CONSISTENCY in so]
106 a8005e17 Michael Hanselmann
107 a8005e17 Michael Hanselmann
_MODIFIABLE_STORAGE_TYPES = constants.MODIFIABLE_STORAGE_FIELDS.keys()
108 a8005e17 Michael Hanselmann
109 b8028dcf Michael Hanselmann
_OOB_COMMAND_ASK = compat.UniqueFrozenset([
110 b8028dcf Michael Hanselmann
  constants.OOB_POWER_OFF,
111 b8028dcf Michael Hanselmann
  constants.OOB_POWER_CYCLE,
112 b8028dcf Michael Hanselmann
  ])
113 51144e33 Michael Hanselmann
114 b8028dcf Michael Hanselmann
_ENV_OVERRIDE = compat.UniqueFrozenset(["list"])
115 ef9fa5b9 René Nussbaumer
116 2e6469a1 René Nussbaumer
NONODE_SETUP_OPT = cli_option("--no-node-setup", default=True,
117 2e6469a1 René Nussbaumer
                              action="store_false", dest="node_setup",
118 2e6469a1 René Nussbaumer
                              help=("Do not make initial SSH setup on remote"
119 2e6469a1 René Nussbaumer
                                    " node (needs to be done manually)"))
120 2e6469a1 René Nussbaumer
121 efae0fdd René Nussbaumer
IGNORE_STATUS_OPT = cli_option("--ignore-status", default=False,
122 efae0fdd René Nussbaumer
                               action="store_true", dest="ignore_status",
123 efae0fdd René Nussbaumer
                               help=("Ignore the Node(s) offline status"
124 efae0fdd René Nussbaumer
                                     " (potentially DANGEROUS)"))
125 efae0fdd René Nussbaumer
126 65a77fab René Nussbaumer
127 86f5eae3 Michael Hanselmann
def ConvertStorageType(user_storage_type):
128 86f5eae3 Michael Hanselmann
  """Converts a user storage type to its internal name.
129 86f5eae3 Michael Hanselmann

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

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

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

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

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

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

187 224ff0f7 Michael Hanselmann
  @param options: Command line options
188 224ff0f7 Michael Hanselmann
  @type cluster_name
189 224ff0f7 Michael Hanselmann
  @param cluster_name: Cluster name
190 224ff0f7 Michael Hanselmann
  @type node: string
191 224ff0f7 Michael Hanselmann
  @param node: Destination node name
192 a9f33339 Petr Pudlak
  @type ssh_port: int
193 a9f33339 Petr Pudlak
  @param ssh_port: Destination node ssh port
194 f1bebf4c Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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