Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ 93f1e606

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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