Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-node @ bc8e4a1a

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