Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-node @ 1094acda

History | View | Annotate | Download (19.3 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 77921a95 Iustin Pop
                           use_locking=False)
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 77921a95 Iustin Pop
                         use_locking=False)
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 77921a95 Iustin Pop
    result = cl.QueryNodes(names=[dst_node], fields=["name"],
218 77921a95 Iustin Pop
                           use_locking=False)
219 c4ed32cb Iustin Pop
    dst_node = result[0][0]
220 c4ed32cb Iustin Pop
221 c4ed32cb Iustin Pop
    if src_node == dst_node:
222 c4ed32cb Iustin Pop
      raise errors.OpPrereqError("Evacuate node needs different source and"
223 c4ed32cb Iustin Pop
                                 " target nodes (node %s given twice)" %
224 c4ed32cb Iustin Pop
                                 src_node)
225 c4ed32cb Iustin Pop
    txt_msg = "to node %s" % dst_node
226 c4ed32cb Iustin Pop
  else:
227 c4ed32cb Iustin Pop
    txt_msg = "using iallocator %s" % iallocator
228 c4ed32cb Iustin Pop
229 a5bc662a Iustin Pop
  sinst = utils.NiceSort(sinst)
230 a5bc662a Iustin Pop
231 a5bc662a Iustin Pop
  if not force and not AskUser("Relocate instance(s) %s from node\n"
232 c4ed32cb Iustin Pop
                               " %s %s?" %
233 a5bc662a Iustin Pop
                               (",".join("'%s'" % name for name in sinst),
234 c4ed32cb Iustin Pop
                               src_node, txt_msg)):
235 a5bc662a Iustin Pop
    return constants.EXIT_CONFIRMATION
236 a5bc662a Iustin Pop
237 c4ed32cb Iustin Pop
  ops = []
238 a5bc662a Iustin Pop
  for iname in sinst:
239 a5bc662a Iustin Pop
    op = opcodes.OpReplaceDisks(instance_name=iname,
240 22d31e49 Michael Hanselmann
                                remote_node=dst_node,
241 479636a3 Iustin Pop
                                mode=constants.REPLACE_DISK_CHG,
242 c4ed32cb Iustin Pop
                                iallocator=iallocator,
243 479636a3 Iustin Pop
                                disks=[])
244 c4ed32cb Iustin Pop
    ops.append(op)
245 479636a3 Iustin Pop
246 c4ed32cb Iustin Pop
  job_id = cli.SendJob(ops, cl=cl)
247 c4ed32cb Iustin Pop
  cli.PollJob(job_id, cl=cl)
248 a5bc662a Iustin Pop
249 a5bc662a Iustin Pop
250 c450e9b0 Iustin Pop
def FailoverNode(opts, args):
251 c450e9b0 Iustin Pop
  """Failover all primary instance on a node.
252 c450e9b0 Iustin Pop
253 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
254 ebf366ee Iustin Pop
  @type args: list
255 ebf366ee Iustin Pop
  @param args: should be an empty list
256 ebf366ee Iustin Pop
  @rtype: int
257 ebf366ee Iustin Pop
  @return: the desired exit code
258 ebf366ee Iustin Pop
259 c450e9b0 Iustin Pop
  """
260 479636a3 Iustin Pop
  cl = GetClient()
261 c450e9b0 Iustin Pop
  force = opts.force
262 c450e9b0 Iustin Pop
  selected_fields = ["name", "pinst_list"]
263 c450e9b0 Iustin Pop
264 2e7b8369 Iustin Pop
  # these fields are static data anyway, so it doesn't matter, but
265 2e7b8369 Iustin Pop
  # locking=True should be safer
266 2e7b8369 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields,
267 77921a95 Iustin Pop
                         use_locking=False)
268 c450e9b0 Iustin Pop
  node, pinst = result[0]
269 c450e9b0 Iustin Pop
270 c450e9b0 Iustin Pop
  if not pinst:
271 3a24c527 Iustin Pop
    ToStderr("No primary instances on node %s, exiting.", node)
272 c450e9b0 Iustin Pop
    return 0
273 c450e9b0 Iustin Pop
274 c450e9b0 Iustin Pop
  pinst = utils.NiceSort(pinst)
275 c450e9b0 Iustin Pop
276 c450e9b0 Iustin Pop
  retcode = 0
277 c450e9b0 Iustin Pop
278 c450e9b0 Iustin Pop
  if not force and not AskUser("Fail over instance(s) %s?" %
279 c450e9b0 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
280 c450e9b0 Iustin Pop
    return 2
281 c450e9b0 Iustin Pop
282 479636a3 Iustin Pop
  jex = JobExecutor(cl=cl)
283 c450e9b0 Iustin Pop
  for iname in pinst:
284 c450e9b0 Iustin Pop
    op = opcodes.OpFailoverInstance(instance_name=iname,
285 c450e9b0 Iustin Pop
                                    ignore_consistency=opts.ignore_consistency)
286 479636a3 Iustin Pop
    jex.QueueJob(iname, op)
287 479636a3 Iustin Pop
  results = jex.GetResults()
288 479636a3 Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
289 479636a3 Iustin Pop
  if bad_cnt == 0:
290 479636a3 Iustin Pop
    ToStdout("All %d instance(s) failed over successfully.", len(results))
291 c450e9b0 Iustin Pop
  else:
292 3a24c527 Iustin Pop
    ToStdout("There were errors during the failover:\n"
293 479636a3 Iustin Pop
             "%d error(s) out of %d instance(s).", bad_cnt, len(results))
294 c450e9b0 Iustin Pop
  return retcode
295 c450e9b0 Iustin Pop
296 c450e9b0 Iustin Pop
297 40ef0ed6 Iustin Pop
def MigrateNode(opts, args):
298 40ef0ed6 Iustin Pop
  """Migrate all primary instance on a node.
299 40ef0ed6 Iustin Pop
300 40ef0ed6 Iustin Pop
  """
301 40ef0ed6 Iustin Pop
  cl = GetClient()
302 40ef0ed6 Iustin Pop
  force = opts.force
303 40ef0ed6 Iustin Pop
  selected_fields = ["name", "pinst_list"]
304 40ef0ed6 Iustin Pop
305 77921a95 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields, use_locking=False)
306 40ef0ed6 Iustin Pop
  node, pinst = result[0]
307 40ef0ed6 Iustin Pop
308 40ef0ed6 Iustin Pop
  if not pinst:
309 40ef0ed6 Iustin Pop
    ToStdout("No primary instances on node %s, exiting." % node)
310 40ef0ed6 Iustin Pop
    return 0
311 40ef0ed6 Iustin Pop
312 40ef0ed6 Iustin Pop
  pinst = utils.NiceSort(pinst)
313 40ef0ed6 Iustin Pop
314 40ef0ed6 Iustin Pop
  retcode = 0
315 40ef0ed6 Iustin Pop
316 40ef0ed6 Iustin Pop
  if not force and not AskUser("Migrate instance(s) %s?" %
317 40ef0ed6 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
318 40ef0ed6 Iustin Pop
    return 2
319 40ef0ed6 Iustin Pop
320 40ef0ed6 Iustin Pop
  jex = JobExecutor(cl=cl)
321 40ef0ed6 Iustin Pop
  for iname in pinst:
322 40ef0ed6 Iustin Pop
    op = opcodes.OpMigrateInstance(instance_name=iname, live=opts.live,
323 40ef0ed6 Iustin Pop
                                   cleanup=False)
324 40ef0ed6 Iustin Pop
    jex.QueueJob(iname, op)
325 40ef0ed6 Iustin Pop
326 40ef0ed6 Iustin Pop
  results = jex.GetResults()
327 40ef0ed6 Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
328 40ef0ed6 Iustin Pop
  if bad_cnt == 0:
329 40ef0ed6 Iustin Pop
    ToStdout("All %d instance(s) migrated successfully.", len(results))
330 40ef0ed6 Iustin Pop
  else:
331 40ef0ed6 Iustin Pop
    ToStdout("There were errors during the migration:\n"
332 40ef0ed6 Iustin Pop
             "%d error(s) out of %d instance(s).", bad_cnt, len(results))
333 40ef0ed6 Iustin Pop
  return retcode
334 40ef0ed6 Iustin Pop
335 40ef0ed6 Iustin Pop
336 a8083063 Iustin Pop
def ShowNodeConfig(opts, args):
337 a8083063 Iustin Pop
  """Show node information.
338 a8083063 Iustin Pop
339 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
340 ebf366ee Iustin Pop
  @type args: list
341 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
342 ebf366ee Iustin Pop
      we show information about all nodes, or should contain
343 ebf366ee Iustin Pop
      a list of nodes to be queried for information
344 ebf366ee Iustin Pop
  @rtype: int
345 ebf366ee Iustin Pop
  @return: the desired exit code
346 ebf366ee Iustin Pop
347 a8083063 Iustin Pop
  """
348 2e7b8369 Iustin Pop
  cl = GetClient()
349 2e7b8369 Iustin Pop
  result = cl.QueryNodes(fields=["name", "pip", "sip",
350 0b2454b9 Iustin Pop
                                 "pinst_list", "sinst_list",
351 0b2454b9 Iustin Pop
                                 "master_candidate", "drained", "offline"],
352 77921a95 Iustin Pop
                         names=args, use_locking=False)
353 a8083063 Iustin Pop
354 0b2454b9 Iustin Pop
  for (name, primary_ip, secondary_ip, pinst, sinst,
355 0b2454b9 Iustin Pop
       is_mc, drained, offline) in result:
356 3a24c527 Iustin Pop
    ToStdout("Node name: %s", name)
357 3a24c527 Iustin Pop
    ToStdout("  primary ip: %s", primary_ip)
358 3a24c527 Iustin Pop
    ToStdout("  secondary ip: %s", secondary_ip)
359 0b2454b9 Iustin Pop
    ToStdout("  master candidate: %s", is_mc)
360 0b2454b9 Iustin Pop
    ToStdout("  drained: %s", drained)
361 0b2454b9 Iustin Pop
    ToStdout("  offline: %s", offline)
362 a8083063 Iustin Pop
    if pinst:
363 3a24c527 Iustin Pop
      ToStdout("  primary for instances:")
364 ae07a1d3 Iustin Pop
      for iname in utils.NiceSort(pinst):
365 3a24c527 Iustin Pop
        ToStdout("    - %s", iname)
366 a8083063 Iustin Pop
    else:
367 3a24c527 Iustin Pop
      ToStdout("  primary for no instances")
368 a8083063 Iustin Pop
    if sinst:
369 3a24c527 Iustin Pop
      ToStdout("  secondary for instances:")
370 ae07a1d3 Iustin Pop
      for iname in utils.NiceSort(sinst):
371 3a24c527 Iustin Pop
        ToStdout("    - %s", iname)
372 a8083063 Iustin Pop
    else:
373 3a24c527 Iustin Pop
      ToStdout("  secondary for no instances")
374 a8083063 Iustin Pop
375 a8083063 Iustin Pop
  return 0
376 a8083063 Iustin Pop
377 a8083063 Iustin Pop
378 a8083063 Iustin Pop
def RemoveNode(opts, args):
379 ebf366ee Iustin Pop
  """Remove a node from the cluster.
380 ebf366ee Iustin Pop
381 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
382 ebf366ee Iustin Pop
  @type args: list
383 ebf366ee Iustin Pop
  @param args: should contain only one element, the name of
384 ebf366ee Iustin Pop
      the node to be removed
385 ebf366ee Iustin Pop
  @rtype: int
386 ebf366ee Iustin Pop
  @return: the desired exit code
387 ebf366ee Iustin Pop
388 ebf366ee Iustin Pop
  """
389 a8083063 Iustin Pop
  op = opcodes.OpRemoveNode(node_name=args[0])
390 a8083063 Iustin Pop
  SubmitOpCode(op)
391 ebf366ee Iustin Pop
  return 0
392 a8083063 Iustin Pop
393 a8083063 Iustin Pop
394 f5118ade Iustin Pop
def PowercycleNode(opts, args):
395 f5118ade Iustin Pop
  """Remove a node from the cluster.
396 f5118ade Iustin Pop
397 f5118ade Iustin Pop
  @param opts: the command line options selected by the user
398 f5118ade Iustin Pop
  @type args: list
399 f5118ade Iustin Pop
  @param args: should contain only one element, the name of
400 f5118ade Iustin Pop
      the node to be removed
401 f5118ade Iustin Pop
  @rtype: int
402 f5118ade Iustin Pop
  @return: the desired exit code
403 f5118ade Iustin Pop
404 f5118ade Iustin Pop
  """
405 f5118ade Iustin Pop
  node = args[0]
406 f5118ade Iustin Pop
  if (not opts.confirm and
407 f5118ade Iustin Pop
      not AskUser("Are you sure you want to hard powercycle node %s?" % node)):
408 f5118ade Iustin Pop
    return 2
409 f5118ade Iustin Pop
410 f5118ade Iustin Pop
  op = opcodes.OpPowercycleNode(node_name=node, force=opts.force)
411 f5118ade Iustin Pop
  result = SubmitOpCode(op)
412 f5118ade Iustin Pop
  ToStderr(result)
413 f5118ade Iustin Pop
  return 0
414 f5118ade Iustin Pop
415 f5118ade Iustin Pop
416 dcb93971 Michael Hanselmann
def ListVolumes(opts, args):
417 dcb93971 Michael Hanselmann
  """List logical volumes on node(s).
418 dcb93971 Michael Hanselmann
419 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
420 ebf366ee Iustin Pop
  @type args: list
421 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
422 ebf366ee Iustin Pop
      we list data for all nodes, or contain a list of nodes
423 ebf366ee Iustin Pop
      to display data only for those
424 ebf366ee Iustin Pop
  @rtype: int
425 ebf366ee Iustin Pop
  @return: the desired exit code
426 ebf366ee Iustin Pop
427 dcb93971 Michael Hanselmann
  """
428 dcb93971 Michael Hanselmann
  if opts.output is None:
429 dcb93971 Michael Hanselmann
    selected_fields = ["node", "phys", "vg",
430 dcb93971 Michael Hanselmann
                       "name", "size", "instance"]
431 dcb93971 Michael Hanselmann
  else:
432 dcb93971 Michael Hanselmann
    selected_fields = opts.output.split(",")
433 dcb93971 Michael Hanselmann
434 dcb93971 Michael Hanselmann
  op = opcodes.OpQueryNodeVolumes(nodes=args, output_fields=selected_fields)
435 dcb93971 Michael Hanselmann
  output = SubmitOpCode(op)
436 dcb93971 Michael Hanselmann
437 dcb93971 Michael Hanselmann
  if not opts.no_headers:
438 137161c9 Michael Hanselmann
    headers = {"node": "Node", "phys": "PhysDev",
439 137161c9 Michael Hanselmann
               "vg": "VG", "name": "Name",
440 137161c9 Michael Hanselmann
               "size": "Size", "instance": "Instance"}
441 137161c9 Michael Hanselmann
  else:
442 137161c9 Michael Hanselmann
    headers = None
443 137161c9 Michael Hanselmann
444 9fbfbb7b Iustin Pop
  unitfields = ["size"]
445 137161c9 Michael Hanselmann
446 137161c9 Michael Hanselmann
  numfields = ["size"]
447 137161c9 Michael Hanselmann
448 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
449 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
450 9fbfbb7b Iustin Pop
                       numfields=numfields, data=output, units=opts.units)
451 16be8703 Iustin Pop
452 16be8703 Iustin Pop
  for line in data:
453 3a24c527 Iustin Pop
    ToStdout(line)
454 dcb93971 Michael Hanselmann
455 dcb93971 Michael Hanselmann
  return 0
456 dcb93971 Michael Hanselmann
457 dcb93971 Michael Hanselmann
458 b31c8676 Iustin Pop
def SetNodeParams(opts, args):
459 b31c8676 Iustin Pop
  """Modifies a node.
460 b31c8676 Iustin Pop
461 b31c8676 Iustin Pop
  @param opts: the command line options selected by the user
462 b31c8676 Iustin Pop
  @type args: list
463 b31c8676 Iustin Pop
  @param args: should contain only one element, the node name
464 b31c8676 Iustin Pop
  @rtype: int
465 b31c8676 Iustin Pop
  @return: the desired exit code
466 b31c8676 Iustin Pop
467 b31c8676 Iustin Pop
  """
468 c9d443ea Iustin Pop
  if [opts.master_candidate, opts.drained, opts.offline].count(None) == 3:
469 b31c8676 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
470 b31c8676 Iustin Pop
    return 1
471 b31c8676 Iustin Pop
472 3a5ba66a Iustin Pop
  if opts.master_candidate is not None:
473 3a5ba66a Iustin Pop
    candidate = opts.master_candidate == 'yes'
474 3a5ba66a Iustin Pop
  else:
475 3a5ba66a Iustin Pop
    candidate = None
476 3a5ba66a Iustin Pop
  if opts.offline is not None:
477 3a5ba66a Iustin Pop
    offline = opts.offline == 'yes'
478 3a5ba66a Iustin Pop
  else:
479 3a5ba66a Iustin Pop
    offline = None
480 c9d443ea Iustin Pop
481 c9d443ea Iustin Pop
  if opts.drained is not None:
482 c9d443ea Iustin Pop
    drained = opts.drained == 'yes'
483 c9d443ea Iustin Pop
  else:
484 c9d443ea Iustin Pop
    drained = None
485 b31c8676 Iustin Pop
  op = opcodes.OpSetNodeParams(node_name=args[0],
486 3a5ba66a Iustin Pop
                               master_candidate=candidate,
487 3a5ba66a Iustin Pop
                               offline=offline,
488 c9d443ea Iustin Pop
                               drained=drained,
489 3a5ba66a Iustin Pop
                               force=opts.force)
490 b31c8676 Iustin Pop
491 b31c8676 Iustin Pop
  # even if here we process the result, we allow submit only
492 b31c8676 Iustin Pop
  result = SubmitOrSend(op, opts)
493 b31c8676 Iustin Pop
494 b31c8676 Iustin Pop
  if result:
495 b31c8676 Iustin Pop
    ToStdout("Modified node %s", args[0])
496 b31c8676 Iustin Pop
    for param, data in result:
497 b31c8676 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
498 b31c8676 Iustin Pop
  return 0
499 b31c8676 Iustin Pop
500 b31c8676 Iustin Pop
501 a8083063 Iustin Pop
commands = {
502 a8083063 Iustin Pop
  'add': (AddNode, ARGS_ONE,
503 a8083063 Iustin Pop
          [DEBUG_OPT,
504 a8083063 Iustin Pop
           make_option("-s", "--secondary-ip", dest="secondary_ip",
505 a8083063 Iustin Pop
                       help="Specify the secondary ip for the node",
506 e7c6e02b Michael Hanselmann
                       metavar="ADDRESS", default=None),
507 e7c6e02b Michael Hanselmann
           make_option("--readd", dest="readd",
508 e7c6e02b Michael Hanselmann
                       default=False, action="store_true",
509 e7c6e02b Michael Hanselmann
                       help="Readd old node after replacing it"),
510 c4b6c29c Michael Hanselmann
           make_option("--no-ssh-key-check", dest="ssh_key_check",
511 c4b6c29c Michael Hanselmann
                       default=True, action="store_false",
512 c4b6c29c Michael Hanselmann
                       help="Disable SSH key fingerprint checking"),
513 e7c6e02b Michael Hanselmann
           ],
514 c4b6c29c Michael Hanselmann
          "[-s ip] [--readd] [--no-ssh-key-check] <node_name>",
515 c4b6c29c Michael Hanselmann
          "Add a node to the cluster"),
516 c4ed32cb Iustin Pop
  'evacuate': (EvacuateNode, ARGS_ONE,
517 c4ed32cb Iustin Pop
               [DEBUG_OPT, FORCE_OPT,
518 c4ed32cb Iustin Pop
                make_option("-n", "--new-secondary", dest="dst_node",
519 c4ed32cb Iustin Pop
                            help="New secondary node", metavar="NODE",
520 c4ed32cb Iustin Pop
                            default=None),
521 633b36db Iustin Pop
                make_option("-I", "--iallocator", metavar="<NAME>",
522 c4ed32cb Iustin Pop
                            help="Select new secondary for the instance"
523 c4ed32cb Iustin Pop
                            " automatically using the"
524 c4ed32cb Iustin Pop
                            " <NAME> iallocator plugin",
525 c4ed32cb Iustin Pop
                            default=None, type="string"),
526 c4ed32cb Iustin Pop
                ],
527 633b36db Iustin Pop
               "[-f] {-I <iallocator> | -n <dst>} <node>",
528 c4ed32cb Iustin Pop
               "Relocate the secondary instances from a node"
529 c4ed32cb Iustin Pop
               " to other nodes (only for instances with drbd disk template)"),
530 c450e9b0 Iustin Pop
  'failover': (FailoverNode, ARGS_ONE,
531 c450e9b0 Iustin Pop
               [DEBUG_OPT, FORCE_OPT,
532 c450e9b0 Iustin Pop
                make_option("--ignore-consistency", dest="ignore_consistency",
533 c450e9b0 Iustin Pop
                            action="store_true", default=False,
534 c450e9b0 Iustin Pop
                            help="Ignore the consistency of the disks on"
535 c450e9b0 Iustin Pop
                            " the secondary"),
536 c450e9b0 Iustin Pop
                ],
537 9a033156 Iustin Pop
               "[-f] <node>",
538 c450e9b0 Iustin Pop
               "Stops the primary instances on a node and start them on their"
539 abdf0113 Iustin Pop
               " secondary node (only for instances with drbd disk template)"),
540 40ef0ed6 Iustin Pop
  'migrate': (MigrateNode, ARGS_ONE,
541 40ef0ed6 Iustin Pop
               [DEBUG_OPT, FORCE_OPT,
542 40ef0ed6 Iustin Pop
                make_option("--non-live", dest="live",
543 40ef0ed6 Iustin Pop
                            default=True, action="store_false",
544 40ef0ed6 Iustin Pop
                            help="Do a non-live migration (this usually means"
545 40ef0ed6 Iustin Pop
                            " freeze the instance, save the state,"
546 40ef0ed6 Iustin Pop
                            " transfer and only then resume running on the"
547 40ef0ed6 Iustin Pop
                            " secondary node)"),
548 40ef0ed6 Iustin Pop
                ],
549 40ef0ed6 Iustin Pop
               "[-f] <node>",
550 40ef0ed6 Iustin Pop
               "Migrate all the primary instance on a node away from it"
551 40ef0ed6 Iustin Pop
               " (only for instances of type drbd)"),
552 a8083063 Iustin Pop
  'info': (ShowNodeConfig, ARGS_ANY, [DEBUG_OPT],
553 9a033156 Iustin Pop
           "[<node_name>...]", "Show information about the node(s)"),
554 f1de3563 Iustin Pop
  'list': (ListNodes, ARGS_ANY,
555 f1de3563 Iustin Pop
           [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, SYNC_OPT],
556 f1de3563 Iustin Pop
           "[nodes...]",
557 f1de3563 Iustin Pop
           "Lists the nodes in the cluster. The available fields"
558 cc3bcec8 Guido Trotter
           " are (see the man page for details): %s"
559 cc3bcec8 Guido Trotter
           " The default field list is (in order): %s." %
560 cc3bcec8 Guido Trotter
           (", ".join(_LIST_HEADERS), ", ".join(_LIST_DEF_FIELDS))),
561 b31c8676 Iustin Pop
  'modify': (SetNodeParams, ARGS_ONE,
562 b31c8676 Iustin Pop
             [DEBUG_OPT, FORCE_OPT,
563 b31c8676 Iustin Pop
              SUBMIT_OPT,
564 b31c8676 Iustin Pop
              make_option("-C", "--master-candidate", dest="master_candidate",
565 b31c8676 Iustin Pop
                          choices=('yes', 'no'), default=None,
566 949bdabe Iustin Pop
                          metavar="yes|no",
567 b31c8676 Iustin Pop
                          help="Set the master_candidate flag on the node"),
568 949bdabe Iustin Pop
569 949bdabe Iustin Pop
              make_option("-O", "--offline", dest="offline", metavar="yes|no",
570 3a5ba66a Iustin Pop
                          choices=('yes', 'no'), default=None,
571 3a5ba66a Iustin Pop
                          help="Set the offline flag on the node"),
572 949bdabe Iustin Pop
              make_option("-D", "--drained", dest="drained", metavar="yes|no",
573 c9d443ea Iustin Pop
                          choices=('yes', 'no'), default=None,
574 c9d443ea Iustin Pop
                          help="Set the drained flag on the node"),
575 b31c8676 Iustin Pop
              ],
576 b31c8676 Iustin Pop
             "<instance>", "Alters the parameters of an instance"),
577 f5118ade Iustin Pop
  'powercycle': (PowercycleNode, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, CONFIRM_OPT],
578 f5118ade Iustin Pop
                 "<node_name>", "Tries to forcefully powercycle a node"),
579 a8083063 Iustin Pop
  'remove': (RemoveNode, ARGS_ONE, [DEBUG_OPT],
580 9a033156 Iustin Pop
             "<node_name>", "Removes a node from the cluster"),
581 dcb93971 Michael Hanselmann
  'volumes': (ListVolumes, ARGS_ANY,
582 dcb93971 Michael Hanselmann
              [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
583 9a033156 Iustin Pop
              "[<node_name>...]", "List logical volumes on node(s)"),
584 846baef9 Iustin Pop
  'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
585 9a033156 Iustin Pop
                "<node_name>", "List the tags of the given node"),
586 810c50b7 Iustin Pop
  'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
587 9a033156 Iustin Pop
               "<node_name> tag...", "Add tags to the given node"),
588 810c50b7 Iustin Pop
  'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
589 9a033156 Iustin Pop
                  "<node_name> tag...", "Remove tags from the given node"),
590 a8083063 Iustin Pop
  }
591 a8083063 Iustin Pop
592 a8083063 Iustin Pop
593 a8083063 Iustin Pop
if __name__ == '__main__':
594 846baef9 Iustin Pop
  sys.exit(GenericMain(commands, override={"tag_type": constants.TAG_NODE}))