Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-node @ c0e4a2c3

History | View | Annotate | Download (18.5 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 e7c6e02b Michael Hanselmann
# Copyright (C) 2006, 2007, 2008 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 a8083063 Iustin Pop
22 2f79bd34 Iustin Pop
# pylint: disable-msg=W0401,W0614
23 2f79bd34 Iustin Pop
# W0401: Wildcard import ganeti.cli
24 2f79bd34 Iustin Pop
# W0614: Unused import %s from wildcard import (since we need cli)
25 2f79bd34 Iustin Pop
26 a8083063 Iustin Pop
import sys
27 a8083063 Iustin Pop
from optparse import make_option
28 a8083063 Iustin Pop
29 a8083063 Iustin Pop
from ganeti.cli import *
30 c4ed32cb Iustin Pop
from ganeti import cli
31 a8083063 Iustin Pop
from ganeti import opcodes
32 a8083063 Iustin Pop
from ganeti import utils
33 846baef9 Iustin Pop
from ganeti import constants
34 c450e9b0 Iustin Pop
from ganeti import errors
35 827f753e Guido Trotter
from ganeti import bootstrap
36 a8083063 Iustin Pop
37 a8083063 Iustin Pop
38 ebf366ee Iustin Pop
#: default list of field for L{ListNodes}
39 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
40 48c4dfa8 Iustin Pop
  "name", "dtotal", "dfree",
41 48c4dfa8 Iustin Pop
  "mtotal", "mnode", "mfree",
42 48c4dfa8 Iustin Pop
  "pinst_cnt", "sinst_cnt",
43 48c4dfa8 Iustin Pop
  ]
44 48c4dfa8 Iustin Pop
45 cc3bcec8 Guido Trotter
#: headers (and full field list for L{ListNodes}
46 cc3bcec8 Guido Trotter
_LIST_HEADERS = {
47 cc3bcec8 Guido Trotter
  "name": "Node", "pinst_cnt": "Pinst", "sinst_cnt": "Sinst",
48 cc3bcec8 Guido Trotter
  "pinst_list": "PriInstances", "sinst_list": "SecInstances",
49 cc3bcec8 Guido Trotter
  "pip": "PrimaryIP", "sip": "SecondaryIP",
50 cc3bcec8 Guido Trotter
  "dtotal": "DTotal", "dfree": "DFree",
51 cc3bcec8 Guido Trotter
  "mtotal": "MTotal", "mnode": "MNode", "mfree": "MFree",
52 cc3bcec8 Guido Trotter
  "bootid": "BootID",
53 0105bad3 Iustin Pop
  "ctotal": "CTotal", "cnodes": "CNodes", "csockets": "CSockets",
54 cc3bcec8 Guido Trotter
  "tags": "Tags",
55 cc3bcec8 Guido Trotter
  "serial_no": "SerialNo",
56 cc3bcec8 Guido Trotter
  "master_candidate": "MasterC",
57 cc3bcec8 Guido Trotter
  "master": "IsMaster",
58 0b2454b9 Iustin Pop
  "offline": "Offline", "drained": "Drained",
59 cc3bcec8 Guido Trotter
  }
60 cc3bcec8 Guido Trotter
61 51144e33 Michael Hanselmann
62 4331f6cd Michael Hanselmann
@UsesRPC
63 a8083063 Iustin Pop
def AddNode(opts, args):
64 ebf366ee Iustin Pop
  """Add a node to the cluster.
65 ebf366ee Iustin Pop
66 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
67 ebf366ee Iustin Pop
  @type args: list
68 ebf366ee Iustin Pop
  @param args: should contain only one element, the new node name
69 ebf366ee Iustin Pop
  @rtype: int
70 ebf366ee Iustin Pop
  @return: the desired exit code
71 05ccd983 Guido Trotter
72 05ccd983 Guido Trotter
  """
73 87622829 Iustin Pop
  cl = GetClient()
74 05ccd983 Guido Trotter
  dns_data = utils.HostInfo(args[0])
75 05ccd983 Guido Trotter
  node = dns_data.name
76 82e12743 Iustin Pop
  readd = opts.readd
77 82e12743 Iustin Pop
78 82e12743 Iustin Pop
  try:
79 82e12743 Iustin Pop
    output = cl.QueryNodes(names=[node], fields=['name', 'sip'],
80 82e12743 Iustin Pop
                           use_locking=True)
81 82e12743 Iustin Pop
    node_exists, sip = output[0]
82 82e12743 Iustin Pop
  except (errors.OpPrereqError, errors.OpExecError):
83 82e12743 Iustin Pop
    node_exists = ""
84 82e12743 Iustin Pop
    sip = None
85 82e12743 Iustin Pop
86 82e12743 Iustin Pop
  if readd:
87 82e12743 Iustin Pop
    if not node_exists:
88 82e12743 Iustin Pop
      ToStderr("Node %s not in the cluster"
89 82e12743 Iustin Pop
               " - please retry without '--readd'", node)
90 82e12743 Iustin Pop
      return 1
91 82e12743 Iustin Pop
  else:
92 82e12743 Iustin Pop
    if node_exists:
93 3a24c527 Iustin Pop
      ToStderr("Node %s already in the cluster (as %s)"
94 82e12743 Iustin Pop
               " - please retry with '--readd'", node, node_exists)
95 05ccd983 Guido Trotter
      return 1
96 82e12743 Iustin Pop
    sip = opts.secondary_ip
97 05ccd983 Guido Trotter
98 87622829 Iustin Pop
  # read the cluster name from the master
99 87622829 Iustin Pop
  output = cl.QueryConfigValues(['cluster_name'])
100 87622829 Iustin Pop
  cluster_name = output[0]
101 87622829 Iustin Pop
102 82e12743 Iustin Pop
  if readd:
103 82e12743 Iustin Pop
    # clear the offline and drain flags on the node
104 82e12743 Iustin Pop
    ToStdout("Resetting the 'offline' and 'drained' flags due to re-add")
105 82e12743 Iustin Pop
    op = opcodes.OpSetNodeParams(node_name=node, force=True,
106 82e12743 Iustin Pop
                                 offline=False, drained=False)
107 82e12743 Iustin Pop
108 82e12743 Iustin Pop
    result = SubmitOpCode(op, cl=cl)
109 82e12743 Iustin Pop
    if result:
110 82e12743 Iustin Pop
      ToStdout("Modified:")
111 82e12743 Iustin Pop
      for param, data in result:
112 82e12743 Iustin Pop
        ToStdout(" - %-5s -> %s", param, data)
113 82e12743 Iustin Pop
  else:
114 82e12743 Iustin Pop
    ToStderr("-- WARNING -- \n"
115 82e12743 Iustin Pop
             "Performing this operation is going to replace the ssh daemon"
116 82e12743 Iustin Pop
             " keypair\n"
117 82e12743 Iustin Pop
             "on the target machine (%s) with the ones of the"
118 82e12743 Iustin Pop
             " current one\n"
119 82e12743 Iustin Pop
             "and grant full intra-cluster ssh root access to/from it\n", node)
120 05ccd983 Guido Trotter
121 87622829 Iustin Pop
  bootstrap.SetupNodeDaemon(cluster_name, node, opts.ssh_key_check)
122 827f753e Guido Trotter
123 82e12743 Iustin Pop
  op = opcodes.OpAddNode(node_name=args[0], secondary_ip=sip,
124 e7c6e02b Michael Hanselmann
                         readd=opts.readd)
125 a8083063 Iustin Pop
  SubmitOpCode(op)
126 a8083063 Iustin Pop
127 a8083063 Iustin Pop
128 a8083063 Iustin Pop
def ListNodes(opts, args):
129 a8083063 Iustin Pop
  """List nodes and their properties.
130 a8083063 Iustin Pop
131 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
132 ebf366ee Iustin Pop
  @type args: list
133 ebf366ee Iustin Pop
  @param args: should be an empty list
134 ebf366ee Iustin Pop
  @rtype: int
135 ebf366ee Iustin Pop
  @return: the desired exit code
136 ebf366ee Iustin Pop
137 a8083063 Iustin Pop
  """
138 a8083063 Iustin Pop
  if opts.output is None:
139 48c4dfa8 Iustin Pop
    selected_fields = _LIST_DEF_FIELDS
140 48c4dfa8 Iustin Pop
  elif opts.output.startswith("+"):
141 48c4dfa8 Iustin Pop
    selected_fields = _LIST_DEF_FIELDS + opts.output[1:].split(",")
142 a8083063 Iustin Pop
  else:
143 a8083063 Iustin Pop
    selected_fields = opts.output.split(",")
144 a8083063 Iustin Pop
145 f1de3563 Iustin Pop
  output = GetClient().QueryNodes(args, selected_fields, opts.do_locking)
146 a8083063 Iustin Pop
147 a8083063 Iustin Pop
  if not opts.no_headers:
148 cc3bcec8 Guido Trotter
    headers = _LIST_HEADERS
149 137161c9 Michael Hanselmann
  else:
150 137161c9 Michael Hanselmann
    headers = None
151 137161c9 Michael Hanselmann
152 9fbfbb7b Iustin Pop
  unitfields = ["dtotal", "dfree", "mtotal", "mnode", "mfree"]
153 137161c9 Michael Hanselmann
154 ec223efb Iustin Pop
  numfields = ["dtotal", "dfree",
155 ec223efb Iustin Pop
               "mtotal", "mnode", "mfree",
156 e8a4c138 Iustin Pop
               "pinst_cnt", "sinst_cnt",
157 38d7239a Iustin Pop
               "ctotal", "serial_no"]
158 ec223efb Iustin Pop
159 130a6a6f Iustin Pop
  list_type_fields = ("pinst_list", "sinst_list", "tags")
160 ec223efb Iustin Pop
  # change raw values to nicer strings
161 ec223efb Iustin Pop
  for row in output:
162 ec223efb Iustin Pop
    for idx, field in enumerate(selected_fields):
163 ec223efb Iustin Pop
      val = row[idx]
164 130a6a6f Iustin Pop
      if field in list_type_fields:
165 ec223efb Iustin Pop
        val = ",".join(val)
166 0b2454b9 Iustin Pop
      elif field in ('master', 'master_candidate', 'offline', 'drained'):
167 0e67cdbe Iustin Pop
        if val:
168 0e67cdbe Iustin Pop
          val = 'Y'
169 0e67cdbe Iustin Pop
        else:
170 0e67cdbe Iustin Pop
          val = 'N'
171 ec223efb Iustin Pop
      elif val is None:
172 ec223efb Iustin Pop
        val = "?"
173 ec223efb Iustin Pop
      row[idx] = str(val)
174 137161c9 Michael Hanselmann
175 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
176 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
177 9fbfbb7b Iustin Pop
                       numfields=numfields, data=output, units=opts.units)
178 16be8703 Iustin Pop
  for line in data:
179 3a24c527 Iustin Pop
    ToStdout(line)
180 a8083063 Iustin Pop
181 a8083063 Iustin Pop
  return 0
182 a8083063 Iustin Pop
183 a8083063 Iustin Pop
184 a5bc662a Iustin Pop
def EvacuateNode(opts, args):
185 a5bc662a Iustin Pop
  """Relocate all secondary instance from a node.
186 a5bc662a Iustin Pop
187 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
188 ebf366ee Iustin Pop
  @type args: list
189 ebf366ee Iustin Pop
  @param args: should be an empty list
190 ebf366ee Iustin Pop
  @rtype: int
191 ebf366ee Iustin Pop
  @return: the desired exit code
192 ebf366ee Iustin Pop
193 a5bc662a Iustin Pop
  """
194 479636a3 Iustin Pop
  cl = GetClient()
195 a5bc662a Iustin Pop
  force = opts.force
196 c4ed32cb Iustin Pop
197 c4ed32cb Iustin Pop
  dst_node = opts.dst_node
198 c4ed32cb Iustin Pop
  iallocator = opts.iallocator
199 c4ed32cb Iustin Pop
200 c4ed32cb Iustin Pop
  cnt = [dst_node, iallocator].count(None)
201 c4ed32cb Iustin Pop
  if cnt != 1:
202 c4ed32cb Iustin Pop
    raise errors.OpPrereqError("One and only one of the -n and -i"
203 c4ed32cb Iustin Pop
                               " options must be passed")
204 c4ed32cb Iustin Pop
205 a5bc662a Iustin Pop
  selected_fields = ["name", "sinst_list"]
206 c4ed32cb Iustin Pop
  src_node = args[0]
207 a5bc662a Iustin Pop
208 ec79568d Iustin Pop
  result = cl.QueryNodes(names=[src_node], fields=selected_fields,
209 ec79568d Iustin Pop
                         use_locking=True)
210 a5bc662a Iustin Pop
  src_node, sinst = result[0]
211 a5bc662a Iustin Pop
212 a5bc662a Iustin Pop
  if not sinst:
213 3a24c527 Iustin Pop
    ToStderr("No secondary instances on node %s, exiting.", src_node)
214 a5bc662a Iustin Pop
    return constants.EXIT_SUCCESS
215 a5bc662a Iustin Pop
216 c4ed32cb Iustin Pop
  if dst_node is not None:
217 ec79568d Iustin Pop
    result = cl.QueryNodes(names=[dst_node], fields=["name"], use_locking=True)
218 c4ed32cb Iustin Pop
    dst_node = result[0][0]
219 c4ed32cb Iustin Pop
220 c4ed32cb Iustin Pop
    if src_node == dst_node:
221 c4ed32cb Iustin Pop
      raise errors.OpPrereqError("Evacuate node needs different source and"
222 c4ed32cb Iustin Pop
                                 " target nodes (node %s given twice)" %
223 c4ed32cb Iustin Pop
                                 src_node)
224 c4ed32cb Iustin Pop
    txt_msg = "to node %s" % dst_node
225 c4ed32cb Iustin Pop
  else:
226 c4ed32cb Iustin Pop
    txt_msg = "using iallocator %s" % iallocator
227 c4ed32cb Iustin Pop
228 a5bc662a Iustin Pop
  sinst = utils.NiceSort(sinst)
229 a5bc662a Iustin Pop
230 a5bc662a Iustin Pop
  if not force and not AskUser("Relocate instance(s) %s from node\n"
231 c4ed32cb Iustin Pop
                               " %s %s?" %
232 a5bc662a Iustin Pop
                               (",".join("'%s'" % name for name in sinst),
233 c4ed32cb Iustin Pop
                               src_node, txt_msg)):
234 a5bc662a Iustin Pop
    return constants.EXIT_CONFIRMATION
235 a5bc662a Iustin Pop
236 c4ed32cb Iustin Pop
  ops = []
237 a5bc662a Iustin Pop
  for iname in sinst:
238 a5bc662a Iustin Pop
    op = opcodes.OpReplaceDisks(instance_name=iname,
239 22d31e49 Michael Hanselmann
                                remote_node=dst_node,
240 479636a3 Iustin Pop
                                mode=constants.REPLACE_DISK_CHG,
241 c4ed32cb Iustin Pop
                                iallocator=iallocator,
242 479636a3 Iustin Pop
                                disks=[])
243 c4ed32cb Iustin Pop
    ops.append(op)
244 479636a3 Iustin Pop
245 c4ed32cb Iustin Pop
  job_id = cli.SendJob(ops, cl=cl)
246 c4ed32cb Iustin Pop
  cli.PollJob(job_id, cl=cl)
247 a5bc662a Iustin Pop
248 a5bc662a Iustin Pop
249 c450e9b0 Iustin Pop
def FailoverNode(opts, args):
250 c450e9b0 Iustin Pop
  """Failover all primary instance on a node.
251 c450e9b0 Iustin Pop
252 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
253 ebf366ee Iustin Pop
  @type args: list
254 ebf366ee Iustin Pop
  @param args: should be an empty list
255 ebf366ee Iustin Pop
  @rtype: int
256 ebf366ee Iustin Pop
  @return: the desired exit code
257 ebf366ee Iustin Pop
258 c450e9b0 Iustin Pop
  """
259 479636a3 Iustin Pop
  cl = GetClient()
260 c450e9b0 Iustin Pop
  force = opts.force
261 c450e9b0 Iustin Pop
  selected_fields = ["name", "pinst_list"]
262 c450e9b0 Iustin Pop
263 2e7b8369 Iustin Pop
  # these fields are static data anyway, so it doesn't matter, but
264 2e7b8369 Iustin Pop
  # locking=True should be safer
265 2e7b8369 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields,
266 2e7b8369 Iustin Pop
                         use_locking=True)
267 c450e9b0 Iustin Pop
  node, pinst = result[0]
268 c450e9b0 Iustin Pop
269 c450e9b0 Iustin Pop
  if not pinst:
270 3a24c527 Iustin Pop
    ToStderr("No primary instances on node %s, exiting.", node)
271 c450e9b0 Iustin Pop
    return 0
272 c450e9b0 Iustin Pop
273 c450e9b0 Iustin Pop
  pinst = utils.NiceSort(pinst)
274 c450e9b0 Iustin Pop
275 c450e9b0 Iustin Pop
  retcode = 0
276 c450e9b0 Iustin Pop
277 c450e9b0 Iustin Pop
  if not force and not AskUser("Fail over instance(s) %s?" %
278 c450e9b0 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
279 c450e9b0 Iustin Pop
    return 2
280 c450e9b0 Iustin Pop
281 479636a3 Iustin Pop
  jex = JobExecutor(cl=cl)
282 c450e9b0 Iustin Pop
  for iname in pinst:
283 c450e9b0 Iustin Pop
    op = opcodes.OpFailoverInstance(instance_name=iname,
284 c450e9b0 Iustin Pop
                                    ignore_consistency=opts.ignore_consistency)
285 479636a3 Iustin Pop
    jex.QueueJob(iname, op)
286 479636a3 Iustin Pop
  results = jex.GetResults()
287 479636a3 Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
288 479636a3 Iustin Pop
  if bad_cnt == 0:
289 479636a3 Iustin Pop
    ToStdout("All %d instance(s) failed over successfully.", len(results))
290 c450e9b0 Iustin Pop
  else:
291 3a24c527 Iustin Pop
    ToStdout("There were errors during the failover:\n"
292 479636a3 Iustin Pop
             "%d error(s) out of %d instance(s).", bad_cnt, len(results))
293 c450e9b0 Iustin Pop
  return retcode
294 c450e9b0 Iustin Pop
295 c450e9b0 Iustin Pop
296 40ef0ed6 Iustin Pop
def MigrateNode(opts, args):
297 40ef0ed6 Iustin Pop
  """Migrate all primary instance on a node.
298 40ef0ed6 Iustin Pop
299 40ef0ed6 Iustin Pop
  """
300 40ef0ed6 Iustin Pop
  cl = GetClient()
301 40ef0ed6 Iustin Pop
  force = opts.force
302 40ef0ed6 Iustin Pop
  selected_fields = ["name", "pinst_list"]
303 40ef0ed6 Iustin Pop
304 ec79568d Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields, use_locking=True)
305 40ef0ed6 Iustin Pop
  node, pinst = result[0]
306 40ef0ed6 Iustin Pop
307 40ef0ed6 Iustin Pop
  if not pinst:
308 40ef0ed6 Iustin Pop
    ToStdout("No primary instances on node %s, exiting." % node)
309 40ef0ed6 Iustin Pop
    return 0
310 40ef0ed6 Iustin Pop
311 40ef0ed6 Iustin Pop
  pinst = utils.NiceSort(pinst)
312 40ef0ed6 Iustin Pop
313 40ef0ed6 Iustin Pop
  retcode = 0
314 40ef0ed6 Iustin Pop
315 40ef0ed6 Iustin Pop
  if not force and not AskUser("Migrate instance(s) %s?" %
316 40ef0ed6 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
317 40ef0ed6 Iustin Pop
    return 2
318 40ef0ed6 Iustin Pop
319 40ef0ed6 Iustin Pop
  jex = JobExecutor(cl=cl)
320 40ef0ed6 Iustin Pop
  for iname in pinst:
321 40ef0ed6 Iustin Pop
    op = opcodes.OpMigrateInstance(instance_name=iname, live=opts.live,
322 40ef0ed6 Iustin Pop
                                   cleanup=False)
323 40ef0ed6 Iustin Pop
    jex.QueueJob(iname, op)
324 40ef0ed6 Iustin Pop
325 40ef0ed6 Iustin Pop
  results = jex.GetResults()
326 40ef0ed6 Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
327 40ef0ed6 Iustin Pop
  if bad_cnt == 0:
328 40ef0ed6 Iustin Pop
    ToStdout("All %d instance(s) migrated successfully.", len(results))
329 40ef0ed6 Iustin Pop
  else:
330 40ef0ed6 Iustin Pop
    ToStdout("There were errors during the migration:\n"
331 40ef0ed6 Iustin Pop
             "%d error(s) out of %d instance(s).", bad_cnt, len(results))
332 40ef0ed6 Iustin Pop
  return retcode
333 40ef0ed6 Iustin Pop
334 40ef0ed6 Iustin Pop
335 a8083063 Iustin Pop
def ShowNodeConfig(opts, args):
336 a8083063 Iustin Pop
  """Show node information.
337 a8083063 Iustin Pop
338 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
339 ebf366ee Iustin Pop
  @type args: list
340 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
341 ebf366ee Iustin Pop
      we show information about all nodes, or should contain
342 ebf366ee Iustin Pop
      a list of nodes to be queried for information
343 ebf366ee Iustin Pop
  @rtype: int
344 ebf366ee Iustin Pop
  @return: the desired exit code
345 ebf366ee Iustin Pop
346 a8083063 Iustin Pop
  """
347 2e7b8369 Iustin Pop
  cl = GetClient()
348 2e7b8369 Iustin Pop
  result = cl.QueryNodes(fields=["name", "pip", "sip",
349 0b2454b9 Iustin Pop
                                 "pinst_list", "sinst_list",
350 0b2454b9 Iustin Pop
                                 "master_candidate", "drained", "offline"],
351 2e7b8369 Iustin Pop
                         names=args, use_locking=True)
352 a8083063 Iustin Pop
353 0b2454b9 Iustin Pop
  for (name, primary_ip, secondary_ip, pinst, sinst,
354 0b2454b9 Iustin Pop
       is_mc, drained, offline) in result:
355 3a24c527 Iustin Pop
    ToStdout("Node name: %s", name)
356 3a24c527 Iustin Pop
    ToStdout("  primary ip: %s", primary_ip)
357 3a24c527 Iustin Pop
    ToStdout("  secondary ip: %s", secondary_ip)
358 0b2454b9 Iustin Pop
    ToStdout("  master candidate: %s", is_mc)
359 0b2454b9 Iustin Pop
    ToStdout("  drained: %s", drained)
360 0b2454b9 Iustin Pop
    ToStdout("  offline: %s", offline)
361 a8083063 Iustin Pop
    if pinst:
362 3a24c527 Iustin Pop
      ToStdout("  primary for instances:")
363 ae07a1d3 Iustin Pop
      for iname in utils.NiceSort(pinst):
364 3a24c527 Iustin Pop
        ToStdout("    - %s", iname)
365 a8083063 Iustin Pop
    else:
366 3a24c527 Iustin Pop
      ToStdout("  primary for no instances")
367 a8083063 Iustin Pop
    if sinst:
368 3a24c527 Iustin Pop
      ToStdout("  secondary for instances:")
369 ae07a1d3 Iustin Pop
      for iname in utils.NiceSort(sinst):
370 3a24c527 Iustin Pop
        ToStdout("    - %s", iname)
371 a8083063 Iustin Pop
    else:
372 3a24c527 Iustin Pop
      ToStdout("  secondary for no instances")
373 a8083063 Iustin Pop
374 a8083063 Iustin Pop
  return 0
375 a8083063 Iustin Pop
376 a8083063 Iustin Pop
377 a8083063 Iustin Pop
def RemoveNode(opts, args):
378 ebf366ee Iustin Pop
  """Remove a node from the cluster.
379 ebf366ee Iustin Pop
380 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
381 ebf366ee Iustin Pop
  @type args: list
382 ebf366ee Iustin Pop
  @param args: should contain only one element, the name of
383 ebf366ee Iustin Pop
      the node to be removed
384 ebf366ee Iustin Pop
  @rtype: int
385 ebf366ee Iustin Pop
  @return: the desired exit code
386 ebf366ee Iustin Pop
387 ebf366ee Iustin Pop
  """
388 a8083063 Iustin Pop
  op = opcodes.OpRemoveNode(node_name=args[0])
389 a8083063 Iustin Pop
  SubmitOpCode(op)
390 ebf366ee Iustin Pop
  return 0
391 a8083063 Iustin Pop
392 a8083063 Iustin Pop
393 dcb93971 Michael Hanselmann
def ListVolumes(opts, args):
394 dcb93971 Michael Hanselmann
  """List logical volumes on node(s).
395 dcb93971 Michael Hanselmann
396 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
397 ebf366ee Iustin Pop
  @type args: list
398 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
399 ebf366ee Iustin Pop
      we list data for all nodes, or contain a list of nodes
400 ebf366ee Iustin Pop
      to display data only for those
401 ebf366ee Iustin Pop
  @rtype: int
402 ebf366ee Iustin Pop
  @return: the desired exit code
403 ebf366ee Iustin Pop
404 dcb93971 Michael Hanselmann
  """
405 dcb93971 Michael Hanselmann
  if opts.output is None:
406 dcb93971 Michael Hanselmann
    selected_fields = ["node", "phys", "vg",
407 dcb93971 Michael Hanselmann
                       "name", "size", "instance"]
408 dcb93971 Michael Hanselmann
  else:
409 dcb93971 Michael Hanselmann
    selected_fields = opts.output.split(",")
410 dcb93971 Michael Hanselmann
411 dcb93971 Michael Hanselmann
  op = opcodes.OpQueryNodeVolumes(nodes=args, output_fields=selected_fields)
412 dcb93971 Michael Hanselmann
  output = SubmitOpCode(op)
413 dcb93971 Michael Hanselmann
414 dcb93971 Michael Hanselmann
  if not opts.no_headers:
415 137161c9 Michael Hanselmann
    headers = {"node": "Node", "phys": "PhysDev",
416 137161c9 Michael Hanselmann
               "vg": "VG", "name": "Name",
417 137161c9 Michael Hanselmann
               "size": "Size", "instance": "Instance"}
418 137161c9 Michael Hanselmann
  else:
419 137161c9 Michael Hanselmann
    headers = None
420 137161c9 Michael Hanselmann
421 9fbfbb7b Iustin Pop
  unitfields = ["size"]
422 137161c9 Michael Hanselmann
423 137161c9 Michael Hanselmann
  numfields = ["size"]
424 137161c9 Michael Hanselmann
425 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
426 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
427 9fbfbb7b Iustin Pop
                       numfields=numfields, data=output, units=opts.units)
428 16be8703 Iustin Pop
429 16be8703 Iustin Pop
  for line in data:
430 3a24c527 Iustin Pop
    ToStdout(line)
431 dcb93971 Michael Hanselmann
432 dcb93971 Michael Hanselmann
  return 0
433 dcb93971 Michael Hanselmann
434 dcb93971 Michael Hanselmann
435 b31c8676 Iustin Pop
def SetNodeParams(opts, args):
436 b31c8676 Iustin Pop
  """Modifies a node.
437 b31c8676 Iustin Pop
438 b31c8676 Iustin Pop
  @param opts: the command line options selected by the user
439 b31c8676 Iustin Pop
  @type args: list
440 b31c8676 Iustin Pop
  @param args: should contain only one element, the node name
441 b31c8676 Iustin Pop
  @rtype: int
442 b31c8676 Iustin Pop
  @return: the desired exit code
443 b31c8676 Iustin Pop
444 b31c8676 Iustin Pop
  """
445 c9d443ea Iustin Pop
  if [opts.master_candidate, opts.drained, opts.offline].count(None) == 3:
446 b31c8676 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
447 b31c8676 Iustin Pop
    return 1
448 b31c8676 Iustin Pop
449 3a5ba66a Iustin Pop
  if opts.master_candidate is not None:
450 3a5ba66a Iustin Pop
    candidate = opts.master_candidate == 'yes'
451 3a5ba66a Iustin Pop
  else:
452 3a5ba66a Iustin Pop
    candidate = None
453 3a5ba66a Iustin Pop
  if opts.offline is not None:
454 3a5ba66a Iustin Pop
    offline = opts.offline == 'yes'
455 3a5ba66a Iustin Pop
  else:
456 3a5ba66a Iustin Pop
    offline = None
457 c9d443ea Iustin Pop
458 c9d443ea Iustin Pop
  if opts.drained is not None:
459 c9d443ea Iustin Pop
    drained = opts.drained == 'yes'
460 c9d443ea Iustin Pop
  else:
461 c9d443ea Iustin Pop
    drained = None
462 b31c8676 Iustin Pop
  op = opcodes.OpSetNodeParams(node_name=args[0],
463 3a5ba66a Iustin Pop
                               master_candidate=candidate,
464 3a5ba66a Iustin Pop
                               offline=offline,
465 c9d443ea Iustin Pop
                               drained=drained,
466 3a5ba66a Iustin Pop
                               force=opts.force)
467 b31c8676 Iustin Pop
468 b31c8676 Iustin Pop
  # even if here we process the result, we allow submit only
469 b31c8676 Iustin Pop
  result = SubmitOrSend(op, opts)
470 b31c8676 Iustin Pop
471 b31c8676 Iustin Pop
  if result:
472 b31c8676 Iustin Pop
    ToStdout("Modified node %s", args[0])
473 b31c8676 Iustin Pop
    for param, data in result:
474 b31c8676 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
475 b31c8676 Iustin Pop
  return 0
476 b31c8676 Iustin Pop
477 b31c8676 Iustin Pop
478 a8083063 Iustin Pop
commands = {
479 a8083063 Iustin Pop
  'add': (AddNode, ARGS_ONE,
480 a8083063 Iustin Pop
          [DEBUG_OPT,
481 a8083063 Iustin Pop
           make_option("-s", "--secondary-ip", dest="secondary_ip",
482 a8083063 Iustin Pop
                       help="Specify the secondary ip for the node",
483 e7c6e02b Michael Hanselmann
                       metavar="ADDRESS", default=None),
484 e7c6e02b Michael Hanselmann
           make_option("--readd", dest="readd",
485 e7c6e02b Michael Hanselmann
                       default=False, action="store_true",
486 e7c6e02b Michael Hanselmann
                       help="Readd old node after replacing it"),
487 c4b6c29c Michael Hanselmann
           make_option("--no-ssh-key-check", dest="ssh_key_check",
488 c4b6c29c Michael Hanselmann
                       default=True, action="store_false",
489 c4b6c29c Michael Hanselmann
                       help="Disable SSH key fingerprint checking"),
490 e7c6e02b Michael Hanselmann
           ],
491 c4b6c29c Michael Hanselmann
          "[-s ip] [--readd] [--no-ssh-key-check] <node_name>",
492 c4b6c29c Michael Hanselmann
          "Add a node to the cluster"),
493 c4ed32cb Iustin Pop
  'evacuate': (EvacuateNode, ARGS_ONE,
494 c4ed32cb Iustin Pop
               [DEBUG_OPT, FORCE_OPT,
495 c4ed32cb Iustin Pop
                make_option("-n", "--new-secondary", dest="dst_node",
496 c4ed32cb Iustin Pop
                            help="New secondary node", metavar="NODE",
497 c4ed32cb Iustin Pop
                            default=None),
498 633b36db Iustin Pop
                make_option("-I", "--iallocator", metavar="<NAME>",
499 c4ed32cb Iustin Pop
                            help="Select new secondary for the instance"
500 c4ed32cb Iustin Pop
                            " automatically using the"
501 c4ed32cb Iustin Pop
                            " <NAME> iallocator plugin",
502 c4ed32cb Iustin Pop
                            default=None, type="string"),
503 c4ed32cb Iustin Pop
                ],
504 633b36db Iustin Pop
               "[-f] {-I <iallocator> | -n <dst>} <node>",
505 c4ed32cb Iustin Pop
               "Relocate the secondary instances from a node"
506 c4ed32cb Iustin Pop
               " to other nodes (only for instances with drbd disk template)"),
507 c450e9b0 Iustin Pop
  'failover': (FailoverNode, ARGS_ONE,
508 c450e9b0 Iustin Pop
               [DEBUG_OPT, FORCE_OPT,
509 c450e9b0 Iustin Pop
                make_option("--ignore-consistency", dest="ignore_consistency",
510 c450e9b0 Iustin Pop
                            action="store_true", default=False,
511 c450e9b0 Iustin Pop
                            help="Ignore the consistency of the disks on"
512 c450e9b0 Iustin Pop
                            " the secondary"),
513 c450e9b0 Iustin Pop
                ],
514 9a033156 Iustin Pop
               "[-f] <node>",
515 c450e9b0 Iustin Pop
               "Stops the primary instances on a node and start them on their"
516 abdf0113 Iustin Pop
               " secondary node (only for instances with drbd disk template)"),
517 40ef0ed6 Iustin Pop
  'migrate': (MigrateNode, ARGS_ONE,
518 40ef0ed6 Iustin Pop
               [DEBUG_OPT, FORCE_OPT,
519 40ef0ed6 Iustin Pop
                make_option("--non-live", dest="live",
520 40ef0ed6 Iustin Pop
                            default=True, action="store_false",
521 40ef0ed6 Iustin Pop
                            help="Do a non-live migration (this usually means"
522 40ef0ed6 Iustin Pop
                            " freeze the instance, save the state,"
523 40ef0ed6 Iustin Pop
                            " transfer and only then resume running on the"
524 40ef0ed6 Iustin Pop
                            " secondary node)"),
525 40ef0ed6 Iustin Pop
                ],
526 40ef0ed6 Iustin Pop
               "[-f] <node>",
527 40ef0ed6 Iustin Pop
               "Migrate all the primary instance on a node away from it"
528 40ef0ed6 Iustin Pop
               " (only for instances of type drbd)"),
529 a8083063 Iustin Pop
  'info': (ShowNodeConfig, ARGS_ANY, [DEBUG_OPT],
530 9a033156 Iustin Pop
           "[<node_name>...]", "Show information about the node(s)"),
531 f1de3563 Iustin Pop
  'list': (ListNodes, ARGS_ANY,
532 f1de3563 Iustin Pop
           [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, SYNC_OPT],
533 f1de3563 Iustin Pop
           "[nodes...]",
534 f1de3563 Iustin Pop
           "Lists the nodes in the cluster. The available fields"
535 cc3bcec8 Guido Trotter
           " are (see the man page for details): %s"
536 cc3bcec8 Guido Trotter
           " The default field list is (in order): %s." %
537 cc3bcec8 Guido Trotter
           (", ".join(_LIST_HEADERS), ", ".join(_LIST_DEF_FIELDS))),
538 b31c8676 Iustin Pop
  'modify': (SetNodeParams, ARGS_ONE,
539 b31c8676 Iustin Pop
             [DEBUG_OPT, FORCE_OPT,
540 b31c8676 Iustin Pop
              SUBMIT_OPT,
541 b31c8676 Iustin Pop
              make_option("-C", "--master-candidate", dest="master_candidate",
542 b31c8676 Iustin Pop
                          choices=('yes', 'no'), default=None,
543 b31c8676 Iustin Pop
                          help="Set the master_candidate flag on the node"),
544 3a5ba66a Iustin Pop
              make_option("-O", "--offline", dest="offline",
545 3a5ba66a Iustin Pop
                          choices=('yes', 'no'), default=None,
546 3a5ba66a Iustin Pop
                          help="Set the offline flag on the node"),
547 c9d443ea Iustin Pop
              make_option("-D", "--drained", dest="drained",
548 c9d443ea Iustin Pop
                          choices=('yes', 'no'), default=None,
549 c9d443ea Iustin Pop
                          help="Set the drained flag on the node"),
550 b31c8676 Iustin Pop
              ],
551 b31c8676 Iustin Pop
             "<instance>", "Alters the parameters of an instance"),
552 a8083063 Iustin Pop
  'remove': (RemoveNode, ARGS_ONE, [DEBUG_OPT],
553 9a033156 Iustin Pop
             "<node_name>", "Removes a node from the cluster"),
554 dcb93971 Michael Hanselmann
  'volumes': (ListVolumes, ARGS_ANY,
555 dcb93971 Michael Hanselmann
              [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
556 9a033156 Iustin Pop
              "[<node_name>...]", "List logical volumes on node(s)"),
557 846baef9 Iustin Pop
  'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
558 9a033156 Iustin Pop
                "<node_name>", "List the tags of the given node"),
559 810c50b7 Iustin Pop
  'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
560 9a033156 Iustin Pop
               "<node_name> tag...", "Add tags to the given node"),
561 810c50b7 Iustin Pop
  'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
562 9a033156 Iustin Pop
                  "<node_name> tag...", "Remove tags from the given node"),
563 a8083063 Iustin Pop
  }
564 a8083063 Iustin Pop
565 a8083063 Iustin Pop
566 a8083063 Iustin Pop
if __name__ == '__main__':
567 846baef9 Iustin Pop
  sys.exit(GenericMain(commands, override={"tag_type": constants.TAG_NODE}))