Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-node @ c9d443ea

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