Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-node @ f4bc1f2c

History | View | Annotate | Download (10.5 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 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 a8083063 Iustin Pop
import sys
23 a8083063 Iustin Pop
from optparse import make_option
24 a8083063 Iustin Pop
25 a8083063 Iustin Pop
from ganeti.cli import *
26 a8083063 Iustin Pop
from ganeti import opcodes
27 a8083063 Iustin Pop
from ganeti import logger
28 a8083063 Iustin Pop
from ganeti import utils
29 846baef9 Iustin Pop
from ganeti import constants
30 c450e9b0 Iustin Pop
from ganeti import errors
31 a8083063 Iustin Pop
32 a8083063 Iustin Pop
33 a8083063 Iustin Pop
def AddNode(opts, args):
34 a8083063 Iustin Pop
  """Add node cli-to-processor bridge."""
35 99e8bbde Guido Trotter
  logger.ToStderr("-- WARNING -- \n"
36 99e8bbde Guido Trotter
    "Performing this operation is going to replace the ssh daemon keypair\n"
37 99e8bbde Guido Trotter
    "on the target machine (%s) with the ones of the current one\n"
38 99e8bbde Guido Trotter
    "and grant full intra-cluster ssh root access to/from it\n" % args[0])
39 a8083063 Iustin Pop
  op = opcodes.OpAddNode(node_name=args[0], secondary_ip=opts.secondary_ip)
40 a8083063 Iustin Pop
  SubmitOpCode(op)
41 a8083063 Iustin Pop
42 a8083063 Iustin Pop
43 a8083063 Iustin Pop
def ListNodes(opts, args):
44 a8083063 Iustin Pop
  """List nodes and their properties.
45 a8083063 Iustin Pop
46 a8083063 Iustin Pop
  """
47 a8083063 Iustin Pop
  if opts.output is None:
48 a8083063 Iustin Pop
    selected_fields = ["name", "dtotal", "dfree",
49 a8083063 Iustin Pop
                       "mtotal", "mnode", "mfree",
50 ec223efb Iustin Pop
                       "pinst_cnt", "sinst_cnt"]
51 a8083063 Iustin Pop
  else:
52 a8083063 Iustin Pop
    selected_fields = opts.output.split(",")
53 a8083063 Iustin Pop
54 246e180a Iustin Pop
  op = opcodes.OpQueryNodes(output_fields=selected_fields, names=[])
55 a8083063 Iustin Pop
  output = SubmitOpCode(op)
56 a8083063 Iustin Pop
57 a8083063 Iustin Pop
  if not opts.no_headers:
58 ec223efb Iustin Pop
    headers = {"name": "Node", "pinst_cnt": "Pinst", "sinst_cnt": "Sinst",
59 ec223efb Iustin Pop
               "pinst_list": "PriInstances", "sinst_list": "SecInstances",
60 137161c9 Michael Hanselmann
               "pip": "PrimaryIP", "sip": "SecondaryIP",
61 137161c9 Michael Hanselmann
               "dtotal": "DTotal", "dfree": "DFree",
62 3ef10550 Michael Hanselmann
               "mtotal": "MTotal", "mnode": "MNode", "mfree": "MFree",
63 3ef10550 Michael Hanselmann
               "bootid": "BootID"}
64 137161c9 Michael Hanselmann
  else:
65 137161c9 Michael Hanselmann
    headers = None
66 137161c9 Michael Hanselmann
67 137161c9 Michael Hanselmann
  if opts.human_readable:
68 137161c9 Michael Hanselmann
    unitfields = ["dtotal", "dfree", "mtotal", "mnode", "mfree"]
69 137161c9 Michael Hanselmann
  else:
70 137161c9 Michael Hanselmann
    unitfields = None
71 137161c9 Michael Hanselmann
72 ec223efb Iustin Pop
  numfields = ["dtotal", "dfree",
73 ec223efb Iustin Pop
               "mtotal", "mnode", "mfree",
74 ec223efb Iustin Pop
               "pinst_cnt", "sinst_cnt"]
75 ec223efb Iustin Pop
76 ec223efb Iustin Pop
  # change raw values to nicer strings
77 ec223efb Iustin Pop
  for row in output:
78 ec223efb Iustin Pop
    for idx, field in enumerate(selected_fields):
79 ec223efb Iustin Pop
      val = row[idx]
80 ec223efb Iustin Pop
      if field == "pinst_list":
81 ec223efb Iustin Pop
        val = ",".join(val)
82 ec223efb Iustin Pop
      elif field == "sinst_list":
83 ec223efb Iustin Pop
        val = ",".join(val)
84 ec223efb Iustin Pop
      elif val is None:
85 ec223efb Iustin Pop
        val = "?"
86 ec223efb Iustin Pop
      row[idx] = str(val)
87 137161c9 Michael Hanselmann
88 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
89 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
90 16be8703 Iustin Pop
                       numfields=numfields, data=output)
91 16be8703 Iustin Pop
  for line in data:
92 16be8703 Iustin Pop
    logger.ToStdout(line)
93 a8083063 Iustin Pop
94 a8083063 Iustin Pop
  return 0
95 a8083063 Iustin Pop
96 a8083063 Iustin Pop
97 a5bc662a Iustin Pop
def EvacuateNode(opts, args):
98 a5bc662a Iustin Pop
  """Relocate all secondary instance from a node.
99 a5bc662a Iustin Pop
100 a5bc662a Iustin Pop
  """
101 a5bc662a Iustin Pop
  force = opts.force
102 a5bc662a Iustin Pop
  selected_fields = ["name", "sinst_list"]
103 a5bc662a Iustin Pop
  src_node, dst_node = args
104 a5bc662a Iustin Pop
105 a5bc662a Iustin Pop
  op = opcodes.OpQueryNodes(output_fields=selected_fields, names=[src_node])
106 a5bc662a Iustin Pop
  result = SubmitOpCode(op)
107 a5bc662a Iustin Pop
  src_node, sinst = result[0]
108 a5bc662a Iustin Pop
  op = opcodes.OpQueryNodes(output_fields=["name"], names=[dst_node])
109 a5bc662a Iustin Pop
  result = SubmitOpCode(op)
110 a5bc662a Iustin Pop
  dst_node = result[0][0]
111 a5bc662a Iustin Pop
112 a5bc662a Iustin Pop
  if src_node == dst_node:
113 a5bc662a Iustin Pop
    raise errors.OpPrereqError("Evacuate node needs different source and"
114 a5bc662a Iustin Pop
                               " target nodes (node %s given twice)" %
115 a5bc662a Iustin Pop
                               src_node)
116 a5bc662a Iustin Pop
117 a5bc662a Iustin Pop
  if not sinst:
118 a5bc662a Iustin Pop
    logger.ToStderr("No secondary instances on node %s, exiting." % src_node)
119 a5bc662a Iustin Pop
    return constants.EXIT_SUCCESS
120 a5bc662a Iustin Pop
121 a5bc662a Iustin Pop
  sinst = utils.NiceSort(sinst)
122 a5bc662a Iustin Pop
123 a5bc662a Iustin Pop
  retcode = constants.EXIT_SUCCESS
124 a5bc662a Iustin Pop
125 a5bc662a Iustin Pop
  if not force and not AskUser("Relocate instance(s) %s from node\n"
126 a5bc662a Iustin Pop
                               " %s to node\n %s?" %
127 a5bc662a Iustin Pop
                               (",".join("'%s'" % name for name in sinst),
128 a5bc662a Iustin Pop
                               src_node, dst_node)):
129 a5bc662a Iustin Pop
    return constants.EXIT_CONFIRMATION
130 a5bc662a Iustin Pop
131 a5bc662a Iustin Pop
  good_cnt = bad_cnt = 0
132 a5bc662a Iustin Pop
  for iname in sinst:
133 a5bc662a Iustin Pop
    op = opcodes.OpReplaceDisks(instance_name=iname,
134 22d31e49 Michael Hanselmann
                                remote_node=dst_node,
135 22d31e49 Michael Hanselmann
                                mode=constants.REPLACE_DISK_ALL,
136 22d31e49 Michael Hanselmann
                                disks=["sda", "sdb"])
137 a5bc662a Iustin Pop
    try:
138 a5bc662a Iustin Pop
      logger.ToStdout("Replacing disks for instance %s" % iname)
139 a5bc662a Iustin Pop
      SubmitOpCode(op)
140 a5bc662a Iustin Pop
      logger.ToStdout("Instance %s has been relocated" % iname)
141 a5bc662a Iustin Pop
      good_cnt += 1
142 a5bc662a Iustin Pop
    except errors.GenericError, err:
143 a5bc662a Iustin Pop
      nret, msg = FormatError(err)
144 a5bc662a Iustin Pop
      retcode |= nret
145 a5bc662a Iustin Pop
      logger.ToStderr("Error replacing disks for instance %s: %s" %
146 a5bc662a Iustin Pop
                      (iname, msg))
147 a5bc662a Iustin Pop
      bad_cnt += 1
148 a5bc662a Iustin Pop
149 a5bc662a Iustin Pop
  if retcode == constants.EXIT_SUCCESS:
150 a5bc662a Iustin Pop
    logger.ToStdout("All %d instance(s) relocated successfully." % good_cnt)
151 a5bc662a Iustin Pop
  else:
152 a5bc662a Iustin Pop
    logger.ToStdout("There were errors during the relocation:\n"
153 a5bc662a Iustin Pop
                    "%d error(s) out of %d instance(s)." %
154 a5bc662a Iustin Pop
                    (bad_cnt, good_cnt + bad_cnt))
155 a5bc662a Iustin Pop
  return retcode
156 a5bc662a Iustin Pop
157 a5bc662a Iustin Pop
158 c450e9b0 Iustin Pop
def FailoverNode(opts, args):
159 c450e9b0 Iustin Pop
  """Failover all primary instance on a node.
160 c450e9b0 Iustin Pop
161 c450e9b0 Iustin Pop
  """
162 c450e9b0 Iustin Pop
  force = opts.force
163 c450e9b0 Iustin Pop
  selected_fields = ["name", "pinst_list"]
164 c450e9b0 Iustin Pop
165 c450e9b0 Iustin Pop
  op = opcodes.OpQueryNodes(output_fields=selected_fields, names=args)
166 c450e9b0 Iustin Pop
  result = SubmitOpCode(op)
167 c450e9b0 Iustin Pop
  node, pinst = result[0]
168 c450e9b0 Iustin Pop
169 c450e9b0 Iustin Pop
  if not pinst:
170 c450e9b0 Iustin Pop
    logger.ToStderr("No primary instances on node %s, exiting." % node)
171 c450e9b0 Iustin Pop
    return 0
172 c450e9b0 Iustin Pop
173 c450e9b0 Iustin Pop
  pinst = utils.NiceSort(pinst)
174 c450e9b0 Iustin Pop
175 c450e9b0 Iustin Pop
  retcode = 0
176 c450e9b0 Iustin Pop
177 c450e9b0 Iustin Pop
  if not force and not AskUser("Fail over instance(s) %s?" %
178 c450e9b0 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
179 c450e9b0 Iustin Pop
    return 2
180 c450e9b0 Iustin Pop
181 c450e9b0 Iustin Pop
  good_cnt = bad_cnt = 0
182 c450e9b0 Iustin Pop
  for iname in pinst:
183 c450e9b0 Iustin Pop
    op = opcodes.OpFailoverInstance(instance_name=iname,
184 c450e9b0 Iustin Pop
                                    ignore_consistency=opts.ignore_consistency)
185 c450e9b0 Iustin Pop
    try:
186 c450e9b0 Iustin Pop
      logger.ToStdout("Failing over instance %s" % iname)
187 c450e9b0 Iustin Pop
      SubmitOpCode(op)
188 c450e9b0 Iustin Pop
      logger.ToStdout("Instance %s has been failed over" % iname)
189 c450e9b0 Iustin Pop
      good_cnt += 1
190 c450e9b0 Iustin Pop
    except errors.GenericError, err:
191 c450e9b0 Iustin Pop
      nret, msg = FormatError(err)
192 c450e9b0 Iustin Pop
      retcode |= nret
193 c450e9b0 Iustin Pop
      logger.ToStderr("Error failing over instance %s: %s" % (iname, msg))
194 c450e9b0 Iustin Pop
      bad_cnt += 1
195 c450e9b0 Iustin Pop
196 c450e9b0 Iustin Pop
  if retcode == 0:
197 c450e9b0 Iustin Pop
    logger.ToStdout("All %d instance(s) failed over successfully." % good_cnt)
198 c450e9b0 Iustin Pop
  else:
199 c450e9b0 Iustin Pop
    logger.ToStdout("There were errors during the failover:\n"
200 c450e9b0 Iustin Pop
                    "%d error(s) out of %d instance(s)." %
201 c450e9b0 Iustin Pop
                    (bad_cnt, good_cnt + bad_cnt))
202 c450e9b0 Iustin Pop
  return retcode
203 c450e9b0 Iustin Pop
204 c450e9b0 Iustin Pop
205 a8083063 Iustin Pop
def ShowNodeConfig(opts, args):
206 a8083063 Iustin Pop
  """Show node information.
207 a8083063 Iustin Pop
208 a8083063 Iustin Pop
  """
209 4a72cc75 Iustin Pop
  op = opcodes.OpQueryNodes(output_fields=["name", "pip", "sip",
210 4a72cc75 Iustin Pop
                                           "pinst_list", "sinst_list"],
211 246e180a Iustin Pop
                            names=args)
212 a8083063 Iustin Pop
  result = SubmitOpCode(op)
213 a8083063 Iustin Pop
214 a8083063 Iustin Pop
  for name, primary_ip, secondary_ip, pinst, sinst in result:
215 a8083063 Iustin Pop
    logger.ToStdout("Node name: %s" % name)
216 a8083063 Iustin Pop
    logger.ToStdout("  primary ip: %s" % primary_ip)
217 a8083063 Iustin Pop
    logger.ToStdout("  secondary ip: %s" % secondary_ip)
218 a8083063 Iustin Pop
    if pinst:
219 a8083063 Iustin Pop
      logger.ToStdout("  primary for instances:")
220 a8083063 Iustin Pop
      for iname in pinst:
221 a8083063 Iustin Pop
        logger.ToStdout("    - %s" % iname)
222 a8083063 Iustin Pop
    else:
223 a8083063 Iustin Pop
      logger.ToStdout("  primary for no instances")
224 a8083063 Iustin Pop
    if sinst:
225 a8083063 Iustin Pop
      logger.ToStdout("  secondary for instances:")
226 a8083063 Iustin Pop
      for iname in sinst:
227 a8083063 Iustin Pop
        logger.ToStdout("    - %s" % iname)
228 a8083063 Iustin Pop
    else:
229 a8083063 Iustin Pop
      logger.ToStdout("  secondary for no instances")
230 a8083063 Iustin Pop
231 a8083063 Iustin Pop
  return 0
232 a8083063 Iustin Pop
233 a8083063 Iustin Pop
234 a8083063 Iustin Pop
def RemoveNode(opts, args):
235 a8083063 Iustin Pop
  """Remove node cli-to-processor bridge."""
236 a8083063 Iustin Pop
  op = opcodes.OpRemoveNode(node_name=args[0])
237 a8083063 Iustin Pop
  SubmitOpCode(op)
238 a8083063 Iustin Pop
239 a8083063 Iustin Pop
240 dcb93971 Michael Hanselmann
def ListVolumes(opts, args):
241 dcb93971 Michael Hanselmann
  """List logical volumes on node(s).
242 dcb93971 Michael Hanselmann
243 dcb93971 Michael Hanselmann
  """
244 dcb93971 Michael Hanselmann
  if opts.output is None:
245 dcb93971 Michael Hanselmann
    selected_fields = ["node", "phys", "vg",
246 dcb93971 Michael Hanselmann
                       "name", "size", "instance"]
247 dcb93971 Michael Hanselmann
  else:
248 dcb93971 Michael Hanselmann
    selected_fields = opts.output.split(",")
249 dcb93971 Michael Hanselmann
250 dcb93971 Michael Hanselmann
  op = opcodes.OpQueryNodeVolumes(nodes=args, output_fields=selected_fields)
251 dcb93971 Michael Hanselmann
  output = SubmitOpCode(op)
252 dcb93971 Michael Hanselmann
253 dcb93971 Michael Hanselmann
  if not opts.no_headers:
254 137161c9 Michael Hanselmann
    headers = {"node": "Node", "phys": "PhysDev",
255 137161c9 Michael Hanselmann
               "vg": "VG", "name": "Name",
256 137161c9 Michael Hanselmann
               "size": "Size", "instance": "Instance"}
257 137161c9 Michael Hanselmann
  else:
258 137161c9 Michael Hanselmann
    headers = None
259 137161c9 Michael Hanselmann
260 137161c9 Michael Hanselmann
  if opts.human_readable:
261 137161c9 Michael Hanselmann
    unitfields = ["size"]
262 137161c9 Michael Hanselmann
  else:
263 137161c9 Michael Hanselmann
    unitfields = None
264 137161c9 Michael Hanselmann
265 137161c9 Michael Hanselmann
  numfields = ["size"]
266 137161c9 Michael Hanselmann
267 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
268 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
269 16be8703 Iustin Pop
                       numfields=numfields, data=output)
270 16be8703 Iustin Pop
271 16be8703 Iustin Pop
  for line in data:
272 16be8703 Iustin Pop
    logger.ToStdout(line)
273 dcb93971 Michael Hanselmann
274 dcb93971 Michael Hanselmann
  return 0
275 dcb93971 Michael Hanselmann
276 dcb93971 Michael Hanselmann
277 a8083063 Iustin Pop
commands = {
278 a8083063 Iustin Pop
  'add': (AddNode, ARGS_ONE,
279 a8083063 Iustin Pop
          [DEBUG_OPT,
280 a8083063 Iustin Pop
           make_option("-s", "--secondary-ip", dest="secondary_ip",
281 a8083063 Iustin Pop
                       help="Specify the secondary ip for the node",
282 a8083063 Iustin Pop
                       metavar="ADDRESS", default=None),],
283 520de3bb Iustin Pop
          "[-s ip] <node_name>", "Add a node to the cluster"),
284 a5bc662a Iustin Pop
  'evacuate': (EvacuateNode, ARGS_FIXED(2),
285 a5bc662a Iustin Pop
               [DEBUG_OPT, FORCE_OPT],
286 a5bc662a Iustin Pop
               "[-f] <src_node> <dst_node>",
287 a5bc662a Iustin Pop
               "Relocate the secondary instances from the first node"
288 a5bc662a Iustin Pop
               " to the second one (only for instances of type remote_raid1)"),
289 c450e9b0 Iustin Pop
  'failover': (FailoverNode, ARGS_ONE,
290 c450e9b0 Iustin Pop
               [DEBUG_OPT, FORCE_OPT,
291 c450e9b0 Iustin Pop
                make_option("--ignore-consistency", dest="ignore_consistency",
292 c450e9b0 Iustin Pop
                            action="store_true", default=False,
293 c450e9b0 Iustin Pop
                            help="Ignore the consistency of the disks on"
294 c450e9b0 Iustin Pop
                            " the secondary"),
295 c450e9b0 Iustin Pop
                ],
296 c450e9b0 Iustin Pop
               "[-f] <node>",
297 c450e9b0 Iustin Pop
               "Stops the primary instances on a node and start them on their"
298 c450e9b0 Iustin Pop
               " secondary node (only for instances of type remote_raid1)"),
299 a8083063 Iustin Pop
  'info': (ShowNodeConfig, ARGS_ANY, [DEBUG_OPT],
300 a8083063 Iustin Pop
           "[<node_name>...]", "Show information about the node(s)"),
301 a8083063 Iustin Pop
  'list': (ListNodes, ARGS_NONE,
302 dcb93971 Michael Hanselmann
           [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
303 a8083063 Iustin Pop
           "", "Lists the nodes in the cluster"),
304 a8083063 Iustin Pop
  'remove': (RemoveNode, ARGS_ONE, [DEBUG_OPT],
305 a8083063 Iustin Pop
             "<node_name>", "Removes a node from the cluster"),
306 dcb93971 Michael Hanselmann
  'volumes': (ListVolumes, ARGS_ANY,
307 dcb93971 Michael Hanselmann
              [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
308 dcb93971 Michael Hanselmann
              "[<node_name>...]", "List logical volumes on node(s)"),
309 846baef9 Iustin Pop
  'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
310 846baef9 Iustin Pop
                "<node_name>", "List the tags of the given node"),
311 810c50b7 Iustin Pop
  'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
312 846baef9 Iustin Pop
               "<node_name> tag...", "Add tags to the given node"),
313 810c50b7 Iustin Pop
  'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
314 846baef9 Iustin Pop
                  "<node_name> tag...", "Remove tags from the given node"),
315 a8083063 Iustin Pop
  }
316 a8083063 Iustin Pop
317 a8083063 Iustin Pop
318 a8083063 Iustin Pop
if __name__ == '__main__':
319 846baef9 Iustin Pop
  sys.exit(GenericMain(commands, override={"tag_type": constants.TAG_NODE}))