Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-instance @ 1f864b60

History | View | Annotate | Download (46.7 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 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
import os
28 312ac745 Iustin Pop
import itertools
29 0d0e9090 René Nussbaumer
import simplejson
30 90f72445 Iustin Pop
import time
31 a8083063 Iustin Pop
from cStringIO import StringIO
32 a8083063 Iustin Pop
33 a8083063 Iustin Pop
from ganeti.cli import *
34 a8083063 Iustin Pop
from ganeti import opcodes
35 a8083063 Iustin Pop
from ganeti import constants
36 a8083063 Iustin Pop
from ganeti import utils
37 312ac745 Iustin Pop
from ganeti import errors
38 312ac745 Iustin Pop
39 312ac745 Iustin Pop
40 312ac745 Iustin Pop
_SHUTDOWN_CLUSTER = "cluster"
41 312ac745 Iustin Pop
_SHUTDOWN_NODES_BOTH = "nodes"
42 312ac745 Iustin Pop
_SHUTDOWN_NODES_PRI = "nodes-pri"
43 312ac745 Iustin Pop
_SHUTDOWN_NODES_SEC = "nodes-sec"
44 312ac745 Iustin Pop
_SHUTDOWN_INSTANCES = "instances"
45 312ac745 Iustin Pop
46 7c0d6283 Michael Hanselmann
47 31a853d2 Iustin Pop
_VALUE_TRUE = "true"
48 31a853d2 Iustin Pop
49 7232c04c Iustin Pop
#: default list of options for L{ListInstances}
50 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
51 e69d05fd Iustin Pop
  "name", "hypervisor", "os", "pnode", "status", "oper_ram",
52 48c4dfa8 Iustin Pop
  ]
53 48c4dfa8 Iustin Pop
54 bdb7d4e8 Michael Hanselmann
55 479636a3 Iustin Pop
def _ExpandMultiNames(mode, names, client=None):
56 312ac745 Iustin Pop
  """Expand the given names using the passed mode.
57 312ac745 Iustin Pop
58 312ac745 Iustin Pop
  For _SHUTDOWN_CLUSTER, all instances will be returned. For
59 312ac745 Iustin Pop
  _SHUTDOWN_NODES_PRI/SEC, all instances having those nodes as
60 7232c04c Iustin Pop
  primary/secondary will be returned. For _SHUTDOWN_NODES_BOTH, all
61 312ac745 Iustin Pop
  instances having those nodes as either primary or secondary will be
62 312ac745 Iustin Pop
  returned. For _SHUTDOWN_INSTANCES, the given instances will be
63 312ac745 Iustin Pop
  returned.
64 312ac745 Iustin Pop
65 7232c04c Iustin Pop
  @param mode: one of L{_SHUTDOWN_CLUSTER}, L{_SHUTDOWN_NODES_BOTH},
66 7232c04c Iustin Pop
      L{_SHUTDOWN_NODES_PRI}, L{_SHUTDOWN_NODES_SEC} or
67 7232c04c Iustin Pop
      L{_SHUTDOWN_INSTANCES}
68 7232c04c Iustin Pop
  @param names: a list of names; for cluster, it must be empty,
69 7232c04c Iustin Pop
      and for node and instance it must be a list of valid item
70 7232c04c Iustin Pop
      names (short names are valid as usual, e.g. node1 instead of
71 7232c04c Iustin Pop
      node1.example.com)
72 7232c04c Iustin Pop
  @rtype: list
73 7232c04c Iustin Pop
  @return: the list of names after the expansion
74 7232c04c Iustin Pop
  @raise errors.ProgrammerError: for unknown selection type
75 7232c04c Iustin Pop
  @raise errors.OpPrereqError: for invalid input parameters
76 7232c04c Iustin Pop
77 312ac745 Iustin Pop
  """
78 479636a3 Iustin Pop
  if client is None:
79 479636a3 Iustin Pop
    client = GetClient()
80 312ac745 Iustin Pop
  if mode == _SHUTDOWN_CLUSTER:
81 312ac745 Iustin Pop
    if names:
82 debac808 Iustin Pop
      raise errors.OpPrereqError("Cluster filter mode takes no arguments",
83 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
84 ec79568d Iustin Pop
    idata = client.QueryInstances([], ["name"], False)
85 312ac745 Iustin Pop
    inames = [row[0] for row in idata]
86 312ac745 Iustin Pop
87 312ac745 Iustin Pop
  elif mode in (_SHUTDOWN_NODES_BOTH,
88 312ac745 Iustin Pop
                _SHUTDOWN_NODES_PRI,
89 312ac745 Iustin Pop
                _SHUTDOWN_NODES_SEC):
90 312ac745 Iustin Pop
    if not names:
91 debac808 Iustin Pop
      raise errors.OpPrereqError("No node names passed", errors.ECODE_INVAL)
92 ec79568d Iustin Pop
    ndata = client.QueryNodes(names, ["name", "pinst_list", "sinst_list"],
93 77921a95 Iustin Pop
                              False)
94 312ac745 Iustin Pop
    ipri = [row[1] for row in ndata]
95 312ac745 Iustin Pop
    pri_names = list(itertools.chain(*ipri))
96 312ac745 Iustin Pop
    isec = [row[2] for row in ndata]
97 312ac745 Iustin Pop
    sec_names = list(itertools.chain(*isec))
98 312ac745 Iustin Pop
    if mode == _SHUTDOWN_NODES_BOTH:
99 312ac745 Iustin Pop
      inames = pri_names + sec_names
100 312ac745 Iustin Pop
    elif mode == _SHUTDOWN_NODES_PRI:
101 312ac745 Iustin Pop
      inames = pri_names
102 312ac745 Iustin Pop
    elif mode == _SHUTDOWN_NODES_SEC:
103 312ac745 Iustin Pop
      inames = sec_names
104 312ac745 Iustin Pop
    else:
105 312ac745 Iustin Pop
      raise errors.ProgrammerError("Unhandled shutdown type")
106 312ac745 Iustin Pop
107 312ac745 Iustin Pop
  elif mode == _SHUTDOWN_INSTANCES:
108 312ac745 Iustin Pop
    if not names:
109 debac808 Iustin Pop
      raise errors.OpPrereqError("No instance names passed",
110 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
111 ec79568d Iustin Pop
    idata = client.QueryInstances(names, ["name"], False)
112 312ac745 Iustin Pop
    inames = [row[0] for row in idata]
113 312ac745 Iustin Pop
114 312ac745 Iustin Pop
  else:
115 debac808 Iustin Pop
    raise errors.OpPrereqError("Unknown mode '%s'" % mode, errors.ECODE_INVAL)
116 312ac745 Iustin Pop
117 312ac745 Iustin Pop
  return inames
118 a8083063 Iustin Pop
119 a8083063 Iustin Pop
120 55efe6da Iustin Pop
def _ConfirmOperation(inames, text, extra=""):
121 804a1e8e Iustin Pop
  """Ask the user to confirm an operation on a list of instances.
122 804a1e8e Iustin Pop
123 804a1e8e Iustin Pop
  This function is used to request confirmation for doing an operation
124 804a1e8e Iustin Pop
  on a given list of instances.
125 804a1e8e Iustin Pop
126 7232c04c Iustin Pop
  @type inames: list
127 7232c04c Iustin Pop
  @param inames: the list of names that we display when
128 7232c04c Iustin Pop
      we ask for confirmation
129 7232c04c Iustin Pop
  @type text: str
130 7232c04c Iustin Pop
  @param text: the operation that the user should confirm
131 7232c04c Iustin Pop
      (e.g. I{shutdown} or I{startup})
132 7232c04c Iustin Pop
  @rtype: boolean
133 7232c04c Iustin Pop
  @return: True or False depending on user's confirmation.
134 804a1e8e Iustin Pop
135 804a1e8e Iustin Pop
  """
136 804a1e8e Iustin Pop
  count = len(inames)
137 55efe6da Iustin Pop
  msg = ("The %s will operate on %d instances.\n%s"
138 55efe6da Iustin Pop
         "Do you want to continue?" % (text, count, extra))
139 804a1e8e Iustin Pop
  affected = ("\nAffected instances:\n" +
140 804a1e8e Iustin Pop
              "\n".join(["  %s" % name for name in inames]))
141 804a1e8e Iustin Pop
142 804a1e8e Iustin Pop
  choices = [('y', True, 'Yes, execute the %s' % text),
143 804a1e8e Iustin Pop
             ('n', False, 'No, abort the %s' % text)]
144 804a1e8e Iustin Pop
145 804a1e8e Iustin Pop
  if count > 20:
146 804a1e8e Iustin Pop
    choices.insert(1, ('v', 'v', 'View the list of affected instances'))
147 804a1e8e Iustin Pop
    ask = msg
148 804a1e8e Iustin Pop
  else:
149 804a1e8e Iustin Pop
    ask = msg + affected
150 804a1e8e Iustin Pop
151 804a1e8e Iustin Pop
  choice = AskUser(ask, choices)
152 804a1e8e Iustin Pop
  if choice == 'v':
153 804a1e8e Iustin Pop
    choices.pop(1)
154 5e66b7e6 Iustin Pop
    choice = AskUser(msg + affected, choices)
155 804a1e8e Iustin Pop
  return choice
156 804a1e8e Iustin Pop
157 804a1e8e Iustin Pop
158 a76f0c4a Iustin Pop
def _EnsureInstancesExist(client, names):
159 a76f0c4a Iustin Pop
  """Check for and ensure the given instance names exist.
160 a76f0c4a Iustin Pop
161 a76f0c4a Iustin Pop
  This function will raise an OpPrereqError in case they don't
162 a76f0c4a Iustin Pop
  exist. Otherwise it will exit cleanly.
163 a76f0c4a Iustin Pop
164 f2fd87d7 Iustin Pop
  @type client: L{ganeti.luxi.Client}
165 a76f0c4a Iustin Pop
  @param client: the client to use for the query
166 a76f0c4a Iustin Pop
  @type names: list
167 a76f0c4a Iustin Pop
  @param names: the list of instance names to query
168 a76f0c4a Iustin Pop
  @raise errors.OpPrereqError: in case any instance is missing
169 a76f0c4a Iustin Pop
170 a76f0c4a Iustin Pop
  """
171 a76f0c4a Iustin Pop
  # TODO: change LUQueryInstances to that it actually returns None
172 a76f0c4a Iustin Pop
  # instead of raising an exception, or devise a better mechanism
173 ec79568d Iustin Pop
  result = client.QueryInstances(names, ["name"], False)
174 a76f0c4a Iustin Pop
  for orig_name, row in zip(names, result):
175 a76f0c4a Iustin Pop
    if row[0] is None:
176 debac808 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' does not exist" % orig_name,
177 debac808 Iustin Pop
                                 errors.ECODE_NOENT)
178 a76f0c4a Iustin Pop
179 a76f0c4a Iustin Pop
180 1c5945b6 Iustin Pop
def GenericManyOps(operation, fn):
181 1c5945b6 Iustin Pop
  """Generic multi-instance operations.
182 1c5945b6 Iustin Pop
183 1c5945b6 Iustin Pop
  The will return a wrapper that processes the options and arguments
184 1c5945b6 Iustin Pop
  given, and uses the passed function to build the opcode needed for
185 1c5945b6 Iustin Pop
  the specific operation. Thus all the generic loop/confirmation code
186 1c5945b6 Iustin Pop
  is abstracted into this function.
187 1c5945b6 Iustin Pop
188 1c5945b6 Iustin Pop
  """
189 1c5945b6 Iustin Pop
  def realfn(opts, args):
190 1c5945b6 Iustin Pop
    if opts.multi_mode is None:
191 1c5945b6 Iustin Pop
      opts.multi_mode = _SHUTDOWN_INSTANCES
192 1c5945b6 Iustin Pop
    cl = GetClient()
193 1c5945b6 Iustin Pop
    inames = _ExpandMultiNames(opts.multi_mode, args, client=cl)
194 1c5945b6 Iustin Pop
    if not inames:
195 1c5945b6 Iustin Pop
      raise errors.OpPrereqError("Selection filter does not match"
196 debac808 Iustin Pop
                                 " any instances", errors.ECODE_INVAL)
197 1c5945b6 Iustin Pop
    multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
198 1c5945b6 Iustin Pop
    if not (opts.force_multi or not multi_on
199 1c5945b6 Iustin Pop
            or _ConfirmOperation(inames, operation)):
200 1c5945b6 Iustin Pop
      return 1
201 1c5945b6 Iustin Pop
    jex = JobExecutor(verbose=multi_on, cl=cl)
202 1c5945b6 Iustin Pop
    for name in inames:
203 1c5945b6 Iustin Pop
      op = fn(name, opts)
204 1c5945b6 Iustin Pop
      jex.QueueJob(name, op)
205 1c5945b6 Iustin Pop
    jex.WaitOrShow(not opts.submit_only)
206 1c5945b6 Iustin Pop
    return 0
207 1c5945b6 Iustin Pop
  return realfn
208 1c5945b6 Iustin Pop
209 1c5945b6 Iustin Pop
210 a8083063 Iustin Pop
def ListInstances(opts, args):
211 f5abe9bd Oleksiy Mishchenko
  """List instances and their properties.
212 a8083063 Iustin Pop
213 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
214 7232c04c Iustin Pop
  @type args: list
215 7232c04c Iustin Pop
  @param args: should be an empty list
216 7232c04c Iustin Pop
  @rtype: int
217 7232c04c Iustin Pop
  @return: the desired exit code
218 7232c04c Iustin Pop
219 a8083063 Iustin Pop
  """
220 a8083063 Iustin Pop
  if opts.output is None:
221 48c4dfa8 Iustin Pop
    selected_fields = _LIST_DEF_FIELDS
222 48c4dfa8 Iustin Pop
  elif opts.output.startswith("+"):
223 48c4dfa8 Iustin Pop
    selected_fields = _LIST_DEF_FIELDS + opts.output[1:].split(",")
224 a8083063 Iustin Pop
  else:
225 a8083063 Iustin Pop
    selected_fields = opts.output.split(",")
226 a8083063 Iustin Pop
227 ec79568d Iustin Pop
  output = GetClient().QueryInstances(args, selected_fields, opts.do_locking)
228 a8083063 Iustin Pop
229 a8083063 Iustin Pop
  if not opts.no_headers:
230 d8052456 Iustin Pop
    headers = {
231 d8052456 Iustin Pop
      "name": "Instance", "os": "OS", "pnode": "Primary_node",
232 d8052456 Iustin Pop
      "snodes": "Secondary_Nodes", "admin_state": "Autostart",
233 338e51e8 Iustin Pop
      "oper_state": "Running",
234 d8052456 Iustin Pop
      "oper_ram": "Memory", "disk_template": "Disk_template",
235 3fb1e1c5 Alexander Schreiber
      "ip": "IP_address", "mac": "MAC_address",
236 638c6349 Guido Trotter
      "nic_mode": "NIC_Mode", "nic_link": "NIC_Link",
237 338e51e8 Iustin Pop
      "bridge": "Bridge",
238 d8052456 Iustin Pop
      "sda_size": "Disk/0", "sdb_size": "Disk/1",
239 024e157f Iustin Pop
      "disk_usage": "DiskUsage",
240 130a6a6f Iustin Pop
      "status": "Status", "tags": "Tags",
241 3fb1e1c5 Alexander Schreiber
      "network_port": "Network_port",
242 5018a335 Iustin Pop
      "hv/kernel_path": "Kernel_path",
243 5018a335 Iustin Pop
      "hv/initrd_path": "Initrd_path",
244 20b1bd80 Iustin Pop
      "hv/boot_order": "Boot_order",
245 20b1bd80 Iustin Pop
      "hv/acpi": "ACPI",
246 20b1bd80 Iustin Pop
      "hv/pae": "PAE",
247 20b1bd80 Iustin Pop
      "hv/cdrom_image_path": "CDROM_image_path",
248 20b1bd80 Iustin Pop
      "hv/nic_type": "NIC_type",
249 20b1bd80 Iustin Pop
      "hv/disk_type": "Disk_type",
250 7ac1fc45 Guido Trotter
      "hv/vnc_bind_address": "VNC_bind_address",
251 e69d05fd Iustin Pop
      "serial_no": "SerialNo", "hypervisor": "Hypervisor",
252 5018a335 Iustin Pop
      "hvparams": "Hypervisor_parameters",
253 338e51e8 Iustin Pop
      "be/memory": "Configured_memory",
254 338e51e8 Iustin Pop
      "be/vcpus": "VCPUs",
255 c1ce76bb Iustin Pop
      "vcpus": "VCPUs",
256 c0f2b229 Iustin Pop
      "be/auto_balance": "Auto_balance",
257 23b8c8d6 Iustin Pop
      "disk.count": "Disks", "disk.sizes": "Disk_sizes",
258 23b8c8d6 Iustin Pop
      "nic.count": "NICs", "nic.ips": "NIC_IPs",
259 638c6349 Guido Trotter
      "nic.modes": "NIC_modes", "nic.links": "NIC_links",
260 23b8c8d6 Iustin Pop
      "nic.bridges": "NIC_bridges", "nic.macs": "NIC_MACs",
261 033d58b0 Iustin Pop
      "ctime": "CTime", "mtime": "MTime", "uuid": "UUID",
262 d8052456 Iustin Pop
      }
263 137161c9 Michael Hanselmann
  else:
264 137161c9 Michael Hanselmann
    headers = None
265 137161c9 Michael Hanselmann
266 9fbfbb7b Iustin Pop
  unitfields = ["be/memory", "oper_ram", "sd(a|b)_size", "disk\.size/.*"]
267 00430f8e Iustin Pop
  numfields = ["be/memory", "oper_ram", "sd(a|b)_size", "be/vcpus",
268 23b8c8d6 Iustin Pop
               "serial_no", "(disk|nic)\.count", "disk\.size/.*"]
269 137161c9 Michael Hanselmann
270 638c6349 Guido Trotter
  list_type_fields = ("tags", "disk.sizes", "nic.macs", "nic.ips",
271 638c6349 Guido Trotter
                      "nic.modes", "nic.links", "nic.bridges")
272 8a23d2d3 Iustin Pop
  # change raw values to nicer strings
273 8a23d2d3 Iustin Pop
  for row in output:
274 8a23d2d3 Iustin Pop
    for idx, field in enumerate(selected_fields):
275 8a23d2d3 Iustin Pop
      val = row[idx]
276 8a23d2d3 Iustin Pop
      if field == "snodes":
277 8a23d2d3 Iustin Pop
        val = ",".join(val) or "-"
278 8a23d2d3 Iustin Pop
      elif field == "admin_state":
279 8a23d2d3 Iustin Pop
        if val:
280 8a23d2d3 Iustin Pop
          val = "yes"
281 8a23d2d3 Iustin Pop
        else:
282 8a23d2d3 Iustin Pop
          val = "no"
283 8a23d2d3 Iustin Pop
      elif field == "oper_state":
284 8a23d2d3 Iustin Pop
        if val is None:
285 8a23d2d3 Iustin Pop
          val = "(node down)"
286 8a23d2d3 Iustin Pop
        elif val: # True
287 8a23d2d3 Iustin Pop
          val = "running"
288 8a23d2d3 Iustin Pop
        else:
289 8a23d2d3 Iustin Pop
          val = "stopped"
290 8a23d2d3 Iustin Pop
      elif field == "oper_ram":
291 8a23d2d3 Iustin Pop
        if val is None:
292 8a23d2d3 Iustin Pop
          val = "(node down)"
293 8a23d2d3 Iustin Pop
      elif field == "sda_size" or field == "sdb_size":
294 8a23d2d3 Iustin Pop
        if val is None:
295 8a23d2d3 Iustin Pop
          val = "N/A"
296 90f72445 Iustin Pop
      elif field == "ctime" or field == "mtime":
297 90f72445 Iustin Pop
        val = utils.FormatTime(val)
298 130a6a6f Iustin Pop
      elif field in list_type_fields:
299 23b8c8d6 Iustin Pop
        val = ",".join(str(item) for item in val)
300 5018a335 Iustin Pop
      elif val is None:
301 5018a335 Iustin Pop
        val = "-"
302 8a23d2d3 Iustin Pop
      row[idx] = str(val)
303 8a23d2d3 Iustin Pop
304 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
305 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
306 9fbfbb7b Iustin Pop
                       numfields=numfields, data=output, units=opts.units)
307 16be8703 Iustin Pop
308 16be8703 Iustin Pop
  for line in data:
309 3a24c527 Iustin Pop
    ToStdout(line)
310 a8083063 Iustin Pop
311 a8083063 Iustin Pop
  return 0
312 a8083063 Iustin Pop
313 a8083063 Iustin Pop
314 a8083063 Iustin Pop
def AddInstance(opts, args):
315 a8083063 Iustin Pop
  """Add an instance to the cluster.
316 a8083063 Iustin Pop
317 d77490c5 Iustin Pop
  This is just a wrapper over GenericInstanceCreate.
318 a8083063 Iustin Pop
319 a8083063 Iustin Pop
  """
320 d77490c5 Iustin Pop
  return GenericInstanceCreate(constants.INSTANCE_CREATE, opts, args)
321 a8083063 Iustin Pop
  return 0
322 a8083063 Iustin Pop
323 a8083063 Iustin Pop
324 0d0e9090 René Nussbaumer
def BatchCreate(opts, args):
325 7232c04c Iustin Pop
  """Create instances using a definition file.
326 7232c04c Iustin Pop
327 7232c04c Iustin Pop
  This function reads a json file with instances defined
328 7232c04c Iustin Pop
  in the form::
329 7232c04c Iustin Pop
330 7232c04c Iustin Pop
    {"instance-name":{
331 9939547b Iustin Pop
      "disk_size": [20480],
332 7232c04c Iustin Pop
      "template": "drbd",
333 7232c04c Iustin Pop
      "backend": {
334 7232c04c Iustin Pop
        "memory": 512,
335 7232c04c Iustin Pop
        "vcpus": 1 },
336 9939547b Iustin Pop
      "os": "debootstrap",
337 7232c04c Iustin Pop
      "primary_node": "firstnode",
338 7232c04c Iustin Pop
      "secondary_node": "secondnode",
339 7232c04c Iustin Pop
      "iallocator": "dumb"}
340 7232c04c Iustin Pop
    }
341 7232c04c Iustin Pop
342 7232c04c Iustin Pop
  Note that I{primary_node} and I{secondary_node} have precedence over
343 7232c04c Iustin Pop
  I{iallocator}.
344 7232c04c Iustin Pop
345 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
346 7232c04c Iustin Pop
  @type args: list
347 7232c04c Iustin Pop
  @param args: should contain one element, the json filename
348 7232c04c Iustin Pop
  @rtype: int
349 7232c04c Iustin Pop
  @return: the desired exit code
350 0d0e9090 René Nussbaumer
351 0d0e9090 René Nussbaumer
  """
352 9939547b Iustin Pop
  _DEFAULT_SPECS = {"disk_size": [20 * 1024],
353 0d0e9090 René Nussbaumer
                    "backend": {},
354 0d0e9090 René Nussbaumer
                    "iallocator": None,
355 0d0e9090 René Nussbaumer
                    "primary_node": None,
356 0d0e9090 René Nussbaumer
                    "secondary_node": None,
357 a379d9bd Guido Trotter
                    "nics": None,
358 0d0e9090 René Nussbaumer
                    "start": True,
359 0d0e9090 René Nussbaumer
                    "ip_check": True,
360 0d0e9090 René Nussbaumer
                    "hypervisor": None,
361 4082e6f9 Iustin Pop
                    "hvparams": {},
362 0d0e9090 René Nussbaumer
                    "file_storage_dir": None,
363 0d0e9090 René Nussbaumer
                    "file_driver": 'loop'}
364 0d0e9090 René Nussbaumer
365 0d0e9090 René Nussbaumer
  def _PopulateWithDefaults(spec):
366 0d0e9090 René Nussbaumer
    """Returns a new hash combined with default values."""
367 2f79bd34 Iustin Pop
    mydict = _DEFAULT_SPECS.copy()
368 2f79bd34 Iustin Pop
    mydict.update(spec)
369 2f79bd34 Iustin Pop
    return mydict
370 0d0e9090 René Nussbaumer
371 0d0e9090 René Nussbaumer
  def _Validate(spec):
372 0d0e9090 René Nussbaumer
    """Validate the instance specs."""
373 0d0e9090 René Nussbaumer
    # Validate fields required under any circumstances
374 0d0e9090 René Nussbaumer
    for required_field in ('os', 'template'):
375 0d0e9090 René Nussbaumer
      if required_field not in spec:
376 0d0e9090 René Nussbaumer
        raise errors.OpPrereqError('Required field "%s" is missing.' %
377 debac808 Iustin Pop
                                   required_field, errors.ECODE_INVAL)
378 0d0e9090 René Nussbaumer
    # Validate special fields
379 0d0e9090 René Nussbaumer
    if spec['primary_node'] is not None:
380 0d0e9090 René Nussbaumer
      if (spec['template'] in constants.DTS_NET_MIRROR and
381 0d0e9090 René Nussbaumer
          spec['secondary_node'] is None):
382 0d0e9090 René Nussbaumer
        raise errors.OpPrereqError('Template requires secondary node, but'
383 debac808 Iustin Pop
                                   ' there was no secondary provided.',
384 debac808 Iustin Pop
                                   errors.ECODE_INVAL)
385 0d0e9090 René Nussbaumer
    elif spec['iallocator'] is None:
386 0d0e9090 René Nussbaumer
      raise errors.OpPrereqError('You have to provide at least a primary_node'
387 debac808 Iustin Pop
                                 ' or an iallocator.',
388 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
389 0d0e9090 René Nussbaumer
390 4082e6f9 Iustin Pop
    if (spec['hvparams'] and
391 4082e6f9 Iustin Pop
        not isinstance(spec['hvparams'], dict)):
392 debac808 Iustin Pop
      raise errors.OpPrereqError('Hypervisor parameters must be a dict.',
393 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
394 0d0e9090 René Nussbaumer
395 0d0e9090 René Nussbaumer
  json_filename = args[0]
396 0d0e9090 René Nussbaumer
  try:
397 13998ef2 Michael Hanselmann
    instance_data = simplejson.loads(utils.ReadFile(json_filename))
398 4082e6f9 Iustin Pop
  except Exception, err:
399 4082e6f9 Iustin Pop
    ToStderr("Can't parse the instance definition file: %s" % str(err))
400 4082e6f9 Iustin Pop
    return 1
401 0d0e9090 René Nussbaumer
402 d4dd4b74 Iustin Pop
  jex = JobExecutor()
403 d4dd4b74 Iustin Pop
404 0d0e9090 René Nussbaumer
  # Iterate over the instances and do:
405 0d0e9090 René Nussbaumer
  #  * Populate the specs with default value
406 0d0e9090 René Nussbaumer
  #  * Validate the instance specs
407 7312b33d Iustin Pop
  i_names = utils.NiceSort(instance_data.keys())
408 7312b33d Iustin Pop
  for name in i_names:
409 7312b33d Iustin Pop
    specs = instance_data[name]
410 0d0e9090 René Nussbaumer
    specs = _PopulateWithDefaults(specs)
411 0d0e9090 René Nussbaumer
    _Validate(specs)
412 0d0e9090 René Nussbaumer
413 4082e6f9 Iustin Pop
    hypervisor = specs['hypervisor']
414 4082e6f9 Iustin Pop
    hvparams = specs['hvparams']
415 0d0e9090 René Nussbaumer
416 9939547b Iustin Pop
    disks = []
417 9939547b Iustin Pop
    for elem in specs['disk_size']:
418 9939547b Iustin Pop
      try:
419 9939547b Iustin Pop
        size = utils.ParseUnit(elem)
420 9939547b Iustin Pop
      except ValueError, err:
421 9939547b Iustin Pop
        raise errors.OpPrereqError("Invalid disk size '%s' for"
422 9939547b Iustin Pop
                                   " instance %s: %s" %
423 debac808 Iustin Pop
                                   (elem, name, err), errors.ECODE_INVAL)
424 9939547b Iustin Pop
      disks.append({"size": size})
425 9939547b Iustin Pop
426 a5728081 Guido Trotter
    utils.ForceDictType(specs['backend'], constants.BES_PARAMETER_TYPES)
427 a5728081 Guido Trotter
    utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
428 a5728081 Guido Trotter
429 a379d9bd Guido Trotter
    tmp_nics = []
430 a379d9bd Guido Trotter
    for field in ('ip', 'mac', 'mode', 'link', 'bridge'):
431 a379d9bd Guido Trotter
      if field in specs:
432 a379d9bd Guido Trotter
        if not tmp_nics:
433 a379d9bd Guido Trotter
          tmp_nics.append({})
434 a379d9bd Guido Trotter
        tmp_nics[0][field] = specs[field]
435 a379d9bd Guido Trotter
436 a379d9bd Guido Trotter
    if specs['nics'] is not None and tmp_nics:
437 a379d9bd Guido Trotter
      raise errors.OpPrereqError("'nics' list incompatible with using"
438 debac808 Iustin Pop
                                 " individual nic fields as well",
439 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
440 a379d9bd Guido Trotter
    elif specs['nics'] is not None:
441 a379d9bd Guido Trotter
      tmp_nics = specs['nics']
442 a379d9bd Guido Trotter
    elif not tmp_nics:
443 a379d9bd Guido Trotter
      tmp_nics = [{}]
444 a379d9bd Guido Trotter
445 0d0e9090 René Nussbaumer
    op = opcodes.OpCreateInstance(instance_name=name,
446 9939547b Iustin Pop
                                  disks=disks,
447 0d0e9090 René Nussbaumer
                                  disk_template=specs['template'],
448 0d0e9090 René Nussbaumer
                                  mode=constants.INSTANCE_CREATE,
449 0d0e9090 René Nussbaumer
                                  os_type=specs['os'],
450 06073e85 Guido Trotter
                                  force_variant=opts.force_variant,
451 0d0e9090 René Nussbaumer
                                  pnode=specs['primary_node'],
452 0d0e9090 René Nussbaumer
                                  snode=specs['secondary_node'],
453 a379d9bd Guido Trotter
                                  nics=tmp_nics,
454 0d0e9090 René Nussbaumer
                                  start=specs['start'],
455 0d0e9090 René Nussbaumer
                                  ip_check=specs['ip_check'],
456 0d0e9090 René Nussbaumer
                                  wait_for_sync=True,
457 0d0e9090 René Nussbaumer
                                  iallocator=specs['iallocator'],
458 0d0e9090 René Nussbaumer
                                  hypervisor=hypervisor,
459 0d0e9090 René Nussbaumer
                                  hvparams=hvparams,
460 0d0e9090 René Nussbaumer
                                  beparams=specs['backend'],
461 0d0e9090 René Nussbaumer
                                  file_storage_dir=specs['file_storage_dir'],
462 0d0e9090 René Nussbaumer
                                  file_driver=specs['file_driver'])
463 0d0e9090 René Nussbaumer
464 d4dd4b74 Iustin Pop
    jex.QueueJob(name, op)
465 d4dd4b74 Iustin Pop
  # we never want to wait, just show the submitted job IDs
466 d4dd4b74 Iustin Pop
  jex.WaitOrShow(False)
467 0d0e9090 René Nussbaumer
468 0d0e9090 René Nussbaumer
  return 0
469 0d0e9090 René Nussbaumer
470 0d0e9090 René Nussbaumer
471 fe7b0351 Michael Hanselmann
def ReinstallInstance(opts, args):
472 fe7b0351 Michael Hanselmann
  """Reinstall an instance.
473 fe7b0351 Michael Hanselmann
474 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
475 7232c04c Iustin Pop
  @type args: list
476 7232c04c Iustin Pop
  @param args: should contain only one element, the name of the
477 7232c04c Iustin Pop
      instance to be reinstalled
478 7232c04c Iustin Pop
  @rtype: int
479 7232c04c Iustin Pop
  @return: the desired exit code
480 fe7b0351 Michael Hanselmann
481 fe7b0351 Michael Hanselmann
  """
482 55efe6da Iustin Pop
  # first, compute the desired name list
483 55efe6da Iustin Pop
  if opts.multi_mode is None:
484 55efe6da Iustin Pop
    opts.multi_mode = _SHUTDOWN_INSTANCES
485 55efe6da Iustin Pop
486 55efe6da Iustin Pop
  inames = _ExpandMultiNames(opts.multi_mode, args)
487 55efe6da Iustin Pop
  if not inames:
488 debac808 Iustin Pop
    raise errors.OpPrereqError("Selection filter does not match any instances",
489 debac808 Iustin Pop
                               errors.ECODE_INVAL)
490 fe7b0351 Michael Hanselmann
491 55efe6da Iustin Pop
  # second, if requested, ask for an OS
492 20e23543 Alexander Schreiber
  if opts.select_os is True:
493 e3ac208c Guido Trotter
    op = opcodes.OpDiagnoseOS(output_fields=["name", "valid", "variants"],
494 e3ac208c Guido Trotter
                              names=[])
495 20e23543 Alexander Schreiber
    result = SubmitOpCode(op)
496 20e23543 Alexander Schreiber
497 20e23543 Alexander Schreiber
    if not result:
498 3a24c527 Iustin Pop
      ToStdout("Can't get the OS list")
499 20e23543 Alexander Schreiber
      return 1
500 20e23543 Alexander Schreiber
501 3a24c527 Iustin Pop
    ToStdout("Available OS templates:")
502 20e23543 Alexander Schreiber
    number = 0
503 20e23543 Alexander Schreiber
    choices = []
504 e3ac208c Guido Trotter
    for (name, valid, variants) in result:
505 e3ac208c Guido Trotter
      if valid:
506 e3ac208c Guido Trotter
        for entry in CalculateOSNames(name, variants):
507 e3ac208c Guido Trotter
          ToStdout("%3s: %s", number, entry)
508 e3ac208c Guido Trotter
          choices.append(("%s" % number, entry, entry))
509 e3ac208c Guido Trotter
          number += 1
510 20e23543 Alexander Schreiber
511 20e23543 Alexander Schreiber
    choices.append(('x', 'exit', 'Exit gnt-instance reinstall'))
512 949bdabe Iustin Pop
    selected = AskUser("Enter OS template number (or x to abort):",
513 20e23543 Alexander Schreiber
                       choices)
514 20e23543 Alexander Schreiber
515 20e23543 Alexander Schreiber
    if selected == 'exit':
516 55efe6da Iustin Pop
      ToStderr("User aborted reinstall, exiting")
517 20e23543 Alexander Schreiber
      return 1
518 20e23543 Alexander Schreiber
519 2f79bd34 Iustin Pop
    os_name = selected
520 20e23543 Alexander Schreiber
  else:
521 2f79bd34 Iustin Pop
    os_name = opts.os
522 20e23543 Alexander Schreiber
523 55efe6da Iustin Pop
  # third, get confirmation: multi-reinstall requires --force-multi
524 55efe6da Iustin Pop
  # *and* --force, single-reinstall just --force
525 55efe6da Iustin Pop
  multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
526 55efe6da Iustin Pop
  if multi_on:
527 55efe6da Iustin Pop
    warn_msg = "Note: this will remove *all* data for the below instances!\n"
528 55efe6da Iustin Pop
    if not ((opts.force_multi and opts.force) or
529 55efe6da Iustin Pop
            _ConfirmOperation(inames, "reinstall", extra=warn_msg)):
530 fe7b0351 Michael Hanselmann
      return 1
531 55efe6da Iustin Pop
  else:
532 55efe6da Iustin Pop
    if not opts.force:
533 55efe6da Iustin Pop
      usertext = ("This will reinstall the instance %s and remove"
534 b6e243ab Iustin Pop
                  " all data. Continue?") % inames[0]
535 55efe6da Iustin Pop
      if not AskUser(usertext):
536 55efe6da Iustin Pop
        return 1
537 55efe6da Iustin Pop
538 55efe6da Iustin Pop
  jex = JobExecutor(verbose=multi_on)
539 55efe6da Iustin Pop
  for instance_name in inames:
540 55efe6da Iustin Pop
    op = opcodes.OpReinstallInstance(instance_name=instance_name,
541 06073e85 Guido Trotter
                                     os_type=os_name,
542 06073e85 Guido Trotter
                                     force_variant=opts.force_variant)
543 55efe6da Iustin Pop
    jex.QueueJob(instance_name, op)
544 fe7b0351 Michael Hanselmann
545 55efe6da Iustin Pop
  jex.WaitOrShow(not opts.submit_only)
546 fe7b0351 Michael Hanselmann
  return 0
547 fe7b0351 Michael Hanselmann
548 fe7b0351 Michael Hanselmann
549 a8083063 Iustin Pop
def RemoveInstance(opts, args):
550 a8083063 Iustin Pop
  """Remove an instance.
551 a8083063 Iustin Pop
552 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
553 7232c04c Iustin Pop
  @type args: list
554 7232c04c Iustin Pop
  @param args: should contain only one element, the name of
555 7232c04c Iustin Pop
      the instance to be removed
556 7232c04c Iustin Pop
  @rtype: int
557 7232c04c Iustin Pop
  @return: the desired exit code
558 a8083063 Iustin Pop
559 a8083063 Iustin Pop
  """
560 a8083063 Iustin Pop
  instance_name = args[0]
561 a8083063 Iustin Pop
  force = opts.force
562 a76f0c4a Iustin Pop
  cl = GetClient()
563 a8083063 Iustin Pop
564 a8083063 Iustin Pop
  if not force:
565 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
566 a76f0c4a Iustin Pop
567 a8083063 Iustin Pop
    usertext = ("This will remove the volumes of the instance %s"
568 a8083063 Iustin Pop
                " (including mirrors), thus removing all the data"
569 a8083063 Iustin Pop
                " of the instance. Continue?") % instance_name
570 47988778 Iustin Pop
    if not AskUser(usertext):
571 a8083063 Iustin Pop
      return 1
572 a8083063 Iustin Pop
573 1d67656e Iustin Pop
  op = opcodes.OpRemoveInstance(instance_name=instance_name,
574 17c3f802 Guido Trotter
                                ignore_failures=opts.ignore_failures,
575 4d98c565 Guido Trotter
                                shutdown_timeout=opts.shutdown_timeout)
576 a76f0c4a Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
577 a8083063 Iustin Pop
  return 0
578 a8083063 Iustin Pop
579 a8083063 Iustin Pop
580 decd5f45 Iustin Pop
def RenameInstance(opts, args):
581 4ab0b9e3 Guido Trotter
  """Rename an instance.
582 decd5f45 Iustin Pop
583 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
584 7232c04c Iustin Pop
  @type args: list
585 7232c04c Iustin Pop
  @param args: should contain two elements, the old and the
586 7232c04c Iustin Pop
      new instance names
587 7232c04c Iustin Pop
  @rtype: int
588 7232c04c Iustin Pop
  @return: the desired exit code
589 decd5f45 Iustin Pop
590 decd5f45 Iustin Pop
  """
591 decd5f45 Iustin Pop
  op = opcodes.OpRenameInstance(instance_name=args[0],
592 decd5f45 Iustin Pop
                                new_name=args[1],
593 decd5f45 Iustin Pop
                                ignore_ip=opts.ignore_ip)
594 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
595 decd5f45 Iustin Pop
  return 0
596 decd5f45 Iustin Pop
597 decd5f45 Iustin Pop
598 a8083063 Iustin Pop
def ActivateDisks(opts, args):
599 a8083063 Iustin Pop
  """Activate an instance's disks.
600 a8083063 Iustin Pop
601 a8083063 Iustin Pop
  This serves two purposes:
602 7232c04c Iustin Pop
    - it allows (as long as the instance is not running)
603 7232c04c Iustin Pop
      mounting the disks and modifying them from the node
604 a8083063 Iustin Pop
    - it repairs inactive secondary drbds
605 a8083063 Iustin Pop
606 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
607 7232c04c Iustin Pop
  @type args: list
608 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
609 7232c04c Iustin Pop
  @rtype: int
610 7232c04c Iustin Pop
  @return: the desired exit code
611 7232c04c Iustin Pop
612 a8083063 Iustin Pop
  """
613 a8083063 Iustin Pop
  instance_name = args[0]
614 b4ec07f8 Iustin Pop
  op = opcodes.OpActivateInstanceDisks(instance_name=instance_name,
615 b4ec07f8 Iustin Pop
                                       ignore_size=opts.ignore_size)
616 6340bb0a Iustin Pop
  disks_info = SubmitOrSend(op, opts)
617 a8083063 Iustin Pop
  for host, iname, nname in disks_info:
618 3a24c527 Iustin Pop
    ToStdout("%s:%s:%s", host, iname, nname)
619 a8083063 Iustin Pop
  return 0
620 a8083063 Iustin Pop
621 a8083063 Iustin Pop
622 a8083063 Iustin Pop
def DeactivateDisks(opts, args):
623 bd315bfa Iustin Pop
  """Deactivate an instance's disks.
624 a8083063 Iustin Pop
625 a8083063 Iustin Pop
  This function takes the instance name, looks for its primary node
626 a8083063 Iustin Pop
  and the tries to shutdown its block devices on that node.
627 a8083063 Iustin Pop
628 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
629 7232c04c Iustin Pop
  @type args: list
630 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
631 7232c04c Iustin Pop
  @rtype: int
632 7232c04c Iustin Pop
  @return: the desired exit code
633 7232c04c Iustin Pop
634 a8083063 Iustin Pop
  """
635 a8083063 Iustin Pop
  instance_name = args[0]
636 a8083063 Iustin Pop
  op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
637 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
638 a8083063 Iustin Pop
  return 0
639 a8083063 Iustin Pop
640 a8083063 Iustin Pop
641 bd315bfa Iustin Pop
def RecreateDisks(opts, args):
642 bd315bfa Iustin Pop
  """Recreate an instance's disks.
643 bd315bfa Iustin Pop
644 bd315bfa Iustin Pop
  @param opts: the command line options selected by the user
645 bd315bfa Iustin Pop
  @type args: list
646 bd315bfa Iustin Pop
  @param args: should contain only one element, the instance name
647 bd315bfa Iustin Pop
  @rtype: int
648 bd315bfa Iustin Pop
  @return: the desired exit code
649 bd315bfa Iustin Pop
650 bd315bfa Iustin Pop
  """
651 bd315bfa Iustin Pop
  instance_name = args[0]
652 bd315bfa Iustin Pop
  if opts.disks:
653 bd315bfa Iustin Pop
    try:
654 bd315bfa Iustin Pop
      opts.disks = [int(v) for v in opts.disks.split(",")]
655 bd315bfa Iustin Pop
    except (ValueError, TypeError), err:
656 bd315bfa Iustin Pop
      ToStderr("Invalid disks value: %s" % str(err))
657 bd315bfa Iustin Pop
      return 1
658 bd315bfa Iustin Pop
  else:
659 bd315bfa Iustin Pop
    opts.disks = []
660 bd315bfa Iustin Pop
661 bd315bfa Iustin Pop
  op = opcodes.OpRecreateInstanceDisks(instance_name=instance_name,
662 bd315bfa Iustin Pop
                                       disks=opts.disks)
663 bd315bfa Iustin Pop
  SubmitOrSend(op, opts)
664 bd315bfa Iustin Pop
  return 0
665 bd315bfa Iustin Pop
666 bd315bfa Iustin Pop
667 c6e911bc Iustin Pop
def GrowDisk(opts, args):
668 7232c04c Iustin Pop
  """Grow an instance's disks.
669 c6e911bc Iustin Pop
670 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
671 7232c04c Iustin Pop
  @type args: list
672 7232c04c Iustin Pop
  @param args: should contain two elements, the instance name
673 7232c04c Iustin Pop
      whose disks we grow and the disk name, e.g. I{sda}
674 7232c04c Iustin Pop
  @rtype: int
675 7232c04c Iustin Pop
  @return: the desired exit code
676 c6e911bc Iustin Pop
677 c6e911bc Iustin Pop
  """
678 c6e911bc Iustin Pop
  instance = args[0]
679 c6e911bc Iustin Pop
  disk = args[1]
680 ad24e046 Iustin Pop
  try:
681 ad24e046 Iustin Pop
    disk = int(disk)
682 ad24e046 Iustin Pop
  except ValueError, err:
683 debac808 Iustin Pop
    raise errors.OpPrereqError("Invalid disk index: %s" % str(err),
684 debac808 Iustin Pop
                               errors.ECODE_INVAL)
685 c6e911bc Iustin Pop
  amount = utils.ParseUnit(args[2])
686 6605411d Iustin Pop
  op = opcodes.OpGrowDisk(instance_name=instance, disk=disk, amount=amount,
687 6605411d Iustin Pop
                          wait_for_sync=opts.wait_for_sync)
688 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
689 c6e911bc Iustin Pop
  return 0
690 c6e911bc Iustin Pop
691 c6e911bc Iustin Pop
692 1c5945b6 Iustin Pop
def _StartupInstance(name, opts):
693 7232c04c Iustin Pop
  """Startup instances.
694 a8083063 Iustin Pop
695 1c5945b6 Iustin Pop
  This returns the opcode to start an instance, and its decorator will
696 1c5945b6 Iustin Pop
  wrap this into a loop starting all desired instances.
697 7232c04c Iustin Pop
698 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
699 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
700 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
701 a8083063 Iustin Pop
702 a8083063 Iustin Pop
  """
703 1c5945b6 Iustin Pop
  op = opcodes.OpStartupInstance(instance_name=name,
704 1c5945b6 Iustin Pop
                                 force=opts.force)
705 1c5945b6 Iustin Pop
  # do not add these parameters to the opcode unless they're defined
706 1c5945b6 Iustin Pop
  if opts.hvparams:
707 1c5945b6 Iustin Pop
    op.hvparams = opts.hvparams
708 1c5945b6 Iustin Pop
  if opts.beparams:
709 1c5945b6 Iustin Pop
    op.beparams = opts.beparams
710 1c5945b6 Iustin Pop
  return op
711 a8083063 Iustin Pop
712 7c0d6283 Michael Hanselmann
713 1c5945b6 Iustin Pop
def _RebootInstance(name, opts):
714 7232c04c Iustin Pop
  """Reboot instance(s).
715 7232c04c Iustin Pop
716 1c5945b6 Iustin Pop
  This returns the opcode to reboot an instance, and its decorator
717 1c5945b6 Iustin Pop
  will wrap this into a loop rebooting all desired instances.
718 579d4337 Alexander Schreiber
719 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
720 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
721 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
722 579d4337 Alexander Schreiber
723 579d4337 Alexander Schreiber
  """
724 1c5945b6 Iustin Pop
  return opcodes.OpRebootInstance(instance_name=name,
725 579d4337 Alexander Schreiber
                                  reboot_type=opts.reboot_type,
726 17c3f802 Guido Trotter
                                  ignore_secondaries=opts.ignore_secondaries,
727 4d98c565 Guido Trotter
                                  shutdown_timeout=opts.shutdown_timeout)
728 a8083063 Iustin Pop
729 7c0d6283 Michael Hanselmann
730 1c5945b6 Iustin Pop
def _ShutdownInstance(name, opts):
731 a8083063 Iustin Pop
  """Shutdown an instance.
732 a8083063 Iustin Pop
733 1c5945b6 Iustin Pop
  This returns the opcode to shutdown an instance, and its decorator
734 1c5945b6 Iustin Pop
  will wrap this into a loop shutting down all desired instances.
735 1c5945b6 Iustin Pop
736 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
737 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
738 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
739 a8083063 Iustin Pop
740 a8083063 Iustin Pop
  """
741 6263189c Guido Trotter
  return opcodes.OpShutdownInstance(instance_name=name,
742 6263189c Guido Trotter
                                    timeout=opts.timeout)
743 a8083063 Iustin Pop
744 a8083063 Iustin Pop
745 a8083063 Iustin Pop
def ReplaceDisks(opts, args):
746 a8083063 Iustin Pop
  """Replace the disks of an instance
747 a8083063 Iustin Pop
748 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
749 7232c04c Iustin Pop
  @type args: list
750 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
751 7232c04c Iustin Pop
  @rtype: int
752 7232c04c Iustin Pop
  @return: the desired exit code
753 a8083063 Iustin Pop
754 a8083063 Iustin Pop
  """
755 a8083063 Iustin Pop
  instance_name = args[0]
756 a14db5ff Iustin Pop
  new_2ndary = opts.dst_node
757 b6e82a65 Iustin Pop
  iallocator = opts.iallocator
758 a9e0c397 Iustin Pop
  if opts.disks is None:
759 54155f52 Iustin Pop
    disks = []
760 a9e0c397 Iustin Pop
  else:
761 54155f52 Iustin Pop
    try:
762 54155f52 Iustin Pop
      disks = [int(i) for i in opts.disks.split(",")]
763 54155f52 Iustin Pop
    except ValueError, err:
764 debac808 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err),
765 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
766 05d47e33 Michael Hanselmann
  cnt = [opts.on_primary, opts.on_secondary, opts.auto,
767 7e9366f7 Iustin Pop
         new_2ndary is not None, iallocator is not None].count(True)
768 7e9366f7 Iustin Pop
  if cnt != 1:
769 05d47e33 Michael Hanselmann
    raise errors.OpPrereqError("One and only one of the -p, -s, -a, -n and -i"
770 debac808 Iustin Pop
                               " options must be passed", errors.ECODE_INVAL)
771 7e9366f7 Iustin Pop
  elif opts.on_primary:
772 a9e0c397 Iustin Pop
    mode = constants.REPLACE_DISK_PRI
773 7e9366f7 Iustin Pop
  elif opts.on_secondary:
774 a9e0c397 Iustin Pop
    mode = constants.REPLACE_DISK_SEC
775 05d47e33 Michael Hanselmann
  elif opts.auto:
776 05d47e33 Michael Hanselmann
    mode = constants.REPLACE_DISK_AUTO
777 05d47e33 Michael Hanselmann
    if disks:
778 05d47e33 Michael Hanselmann
      raise errors.OpPrereqError("Cannot specify disks when using automatic"
779 debac808 Iustin Pop
                                 " mode", errors.ECODE_INVAL)
780 7e9366f7 Iustin Pop
  elif new_2ndary is not None or iallocator is not None:
781 7e9366f7 Iustin Pop
    # replace secondary
782 7e9366f7 Iustin Pop
    mode = constants.REPLACE_DISK_CHG
783 a9e0c397 Iustin Pop
784 a9e0c397 Iustin Pop
  op = opcodes.OpReplaceDisks(instance_name=args[0], disks=disks,
785 b6e82a65 Iustin Pop
                              remote_node=new_2ndary, mode=mode,
786 b6e82a65 Iustin Pop
                              iallocator=iallocator)
787 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
788 a8083063 Iustin Pop
  return 0
789 a8083063 Iustin Pop
790 a8083063 Iustin Pop
791 a8083063 Iustin Pop
def FailoverInstance(opts, args):
792 a8083063 Iustin Pop
  """Failover an instance.
793 a8083063 Iustin Pop
794 a8083063 Iustin Pop
  The failover is done by shutting it down on its present node and
795 a8083063 Iustin Pop
  starting it on the secondary.
796 a8083063 Iustin Pop
797 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
798 7232c04c Iustin Pop
  @type args: list
799 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
800 7232c04c Iustin Pop
  @rtype: int
801 7232c04c Iustin Pop
  @return: the desired exit code
802 a8083063 Iustin Pop
803 a8083063 Iustin Pop
  """
804 a76f0c4a Iustin Pop
  cl = GetClient()
805 80de0e3f Iustin Pop
  instance_name = args[0]
806 80de0e3f Iustin Pop
  force = opts.force
807 a8083063 Iustin Pop
808 80de0e3f Iustin Pop
  if not force:
809 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
810 a76f0c4a Iustin Pop
811 80de0e3f Iustin Pop
    usertext = ("Failover will happen to image %s."
812 80de0e3f Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
813 80de0e3f Iustin Pop
                (instance_name,))
814 80de0e3f Iustin Pop
    if not AskUser(usertext):
815 80de0e3f Iustin Pop
      return 1
816 a8083063 Iustin Pop
817 80de0e3f Iustin Pop
  op = opcodes.OpFailoverInstance(instance_name=instance_name,
818 17c3f802 Guido Trotter
                                  ignore_consistency=opts.ignore_consistency,
819 4d98c565 Guido Trotter
                                  shutdown_timeout=opts.shutdown_timeout)
820 a76f0c4a Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
821 80de0e3f Iustin Pop
  return 0
822 a8083063 Iustin Pop
823 a8083063 Iustin Pop
824 53c776b5 Iustin Pop
def MigrateInstance(opts, args):
825 53c776b5 Iustin Pop
  """Migrate an instance.
826 53c776b5 Iustin Pop
827 53c776b5 Iustin Pop
  The migrate is done without shutdown.
828 53c776b5 Iustin Pop
829 2f907a8c Iustin Pop
  @param opts: the command line options selected by the user
830 2f907a8c Iustin Pop
  @type args: list
831 2f907a8c Iustin Pop
  @param args: should contain only one element, the instance name
832 2f907a8c Iustin Pop
  @rtype: int
833 2f907a8c Iustin Pop
  @return: the desired exit code
834 53c776b5 Iustin Pop
835 53c776b5 Iustin Pop
  """
836 a76f0c4a Iustin Pop
  cl = GetClient()
837 53c776b5 Iustin Pop
  instance_name = args[0]
838 53c776b5 Iustin Pop
  force = opts.force
839 53c776b5 Iustin Pop
840 53c776b5 Iustin Pop
  if not force:
841 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
842 a76f0c4a Iustin Pop
843 53c776b5 Iustin Pop
    if opts.cleanup:
844 53c776b5 Iustin Pop
      usertext = ("Instance %s will be recovered from a failed migration."
845 53c776b5 Iustin Pop
                  " Note that the migration procedure (including cleanup)" %
846 53c776b5 Iustin Pop
                  (instance_name,))
847 53c776b5 Iustin Pop
    else:
848 53c776b5 Iustin Pop
      usertext = ("Instance %s will be migrated. Note that migration" %
849 53c776b5 Iustin Pop
                  (instance_name,))
850 53c776b5 Iustin Pop
    usertext += (" is **experimental** in this version."
851 53c776b5 Iustin Pop
                " This might impact the instance if anything goes wrong."
852 53c776b5 Iustin Pop
                " Continue?")
853 53c776b5 Iustin Pop
    if not AskUser(usertext):
854 53c776b5 Iustin Pop
      return 1
855 53c776b5 Iustin Pop
856 53c776b5 Iustin Pop
  op = opcodes.OpMigrateInstance(instance_name=instance_name, live=opts.live,
857 53c776b5 Iustin Pop
                                 cleanup=opts.cleanup)
858 a76f0c4a Iustin Pop
  SubmitOpCode(op, cl=cl)
859 53c776b5 Iustin Pop
  return 0
860 53c776b5 Iustin Pop
861 53c776b5 Iustin Pop
862 fbf5a861 Iustin Pop
def MoveInstance(opts, args):
863 fbf5a861 Iustin Pop
  """Move an instance.
864 fbf5a861 Iustin Pop
865 fbf5a861 Iustin Pop
  @param opts: the command line options selected by the user
866 fbf5a861 Iustin Pop
  @type args: list
867 fbf5a861 Iustin Pop
  @param args: should contain only one element, the instance name
868 fbf5a861 Iustin Pop
  @rtype: int
869 fbf5a861 Iustin Pop
  @return: the desired exit code
870 fbf5a861 Iustin Pop
871 fbf5a861 Iustin Pop
  """
872 fbf5a861 Iustin Pop
  cl = GetClient()
873 fbf5a861 Iustin Pop
  instance_name = args[0]
874 fbf5a861 Iustin Pop
  force = opts.force
875 fbf5a861 Iustin Pop
876 fbf5a861 Iustin Pop
  if not force:
877 fbf5a861 Iustin Pop
    usertext = ("Instance %s will be moved."
878 fbf5a861 Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
879 fbf5a861 Iustin Pop
                (instance_name,))
880 fbf5a861 Iustin Pop
    if not AskUser(usertext):
881 fbf5a861 Iustin Pop
      return 1
882 fbf5a861 Iustin Pop
883 fbf5a861 Iustin Pop
  op = opcodes.OpMoveInstance(instance_name=instance_name,
884 17c3f802 Guido Trotter
                              target_node=opts.node,
885 4d98c565 Guido Trotter
                              shutdown_timeout=opts.shutdown_timeout)
886 fbf5a861 Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
887 fbf5a861 Iustin Pop
  return 0
888 fbf5a861 Iustin Pop
889 fbf5a861 Iustin Pop
890 a8083063 Iustin Pop
def ConnectToInstanceConsole(opts, args):
891 a8083063 Iustin Pop
  """Connect to the console of an instance.
892 a8083063 Iustin Pop
893 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
894 7232c04c Iustin Pop
  @type args: list
895 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
896 7232c04c Iustin Pop
  @rtype: int
897 7232c04c Iustin Pop
  @return: the desired exit code
898 a8083063 Iustin Pop
899 a8083063 Iustin Pop
  """
900 a8083063 Iustin Pop
  instance_name = args[0]
901 a8083063 Iustin Pop
902 a8083063 Iustin Pop
  op = opcodes.OpConnectConsole(instance_name=instance_name)
903 0a80a26f Michael Hanselmann
  cmd = SubmitOpCode(op)
904 51c6e7b5 Michael Hanselmann
905 51c6e7b5 Michael Hanselmann
  if opts.show_command:
906 3a24c527 Iustin Pop
    ToStdout("%s", utils.ShellQuoteArgs(cmd))
907 51c6e7b5 Michael Hanselmann
  else:
908 51c6e7b5 Michael Hanselmann
    try:
909 51c6e7b5 Michael Hanselmann
      os.execvp(cmd[0], cmd)
910 51c6e7b5 Michael Hanselmann
    finally:
911 3a24c527 Iustin Pop
      ToStderr("Can't run console command %s with arguments:\n'%s'",
912 2f79bd34 Iustin Pop
               cmd[0], " ".join(cmd))
913 51c6e7b5 Michael Hanselmann
      os._exit(1)
914 a8083063 Iustin Pop
915 a8083063 Iustin Pop
916 19708787 Iustin Pop
def _FormatLogicalID(dev_type, logical_id):
917 19708787 Iustin Pop
  """Formats the logical_id of a disk.
918 19708787 Iustin Pop
919 19708787 Iustin Pop
  """
920 19708787 Iustin Pop
  if dev_type == constants.LD_DRBD8:
921 19708787 Iustin Pop
    node_a, node_b, port, minor_a, minor_b, key = logical_id
922 19708787 Iustin Pop
    data = [
923 19708787 Iustin Pop
      ("nodeA", "%s, minor=%s" % (node_a, minor_a)),
924 19708787 Iustin Pop
      ("nodeB", "%s, minor=%s" % (node_b, minor_b)),
925 19708787 Iustin Pop
      ("port", port),
926 19708787 Iustin Pop
      ("auth key", key),
927 19708787 Iustin Pop
      ]
928 19708787 Iustin Pop
  elif dev_type == constants.LD_LV:
929 19708787 Iustin Pop
    vg_name, lv_name = logical_id
930 19708787 Iustin Pop
    data = ["%s/%s" % (vg_name, lv_name)]
931 19708787 Iustin Pop
  else:
932 19708787 Iustin Pop
    data = [str(logical_id)]
933 19708787 Iustin Pop
934 19708787 Iustin Pop
  return data
935 19708787 Iustin Pop
936 19708787 Iustin Pop
937 19708787 Iustin Pop
def _FormatBlockDevInfo(idx, top_level, dev, static):
938 a8083063 Iustin Pop
  """Show block device information.
939 a8083063 Iustin Pop
940 7232c04c Iustin Pop
  This is only used by L{ShowInstanceConfig}, but it's too big to be
941 a8083063 Iustin Pop
  left for an inline definition.
942 a8083063 Iustin Pop
943 19708787 Iustin Pop
  @type idx: int
944 19708787 Iustin Pop
  @param idx: the index of the current disk
945 19708787 Iustin Pop
  @type top_level: boolean
946 19708787 Iustin Pop
  @param top_level: if this a top-level disk?
947 7232c04c Iustin Pop
  @type dev: dict
948 7232c04c Iustin Pop
  @param dev: dictionary with disk information
949 7232c04c Iustin Pop
  @type static: boolean
950 7232c04c Iustin Pop
  @param static: wheter the device information doesn't contain
951 7232c04c Iustin Pop
      runtime information but only static data
952 19708787 Iustin Pop
  @return: a list of either strings, tuples or lists
953 19708787 Iustin Pop
      (which should be formatted at a higher indent level)
954 7232c04c Iustin Pop
955 a8083063 Iustin Pop
  """
956 19708787 Iustin Pop
  def helper(dtype, status):
957 7232c04c Iustin Pop
    """Format one line for physical device status.
958 7232c04c Iustin Pop
959 7232c04c Iustin Pop
    @type dtype: str
960 7232c04c Iustin Pop
    @param dtype: a constant from the L{constants.LDS_BLOCK} set
961 7232c04c Iustin Pop
    @type status: tuple
962 7232c04c Iustin Pop
    @param status: a tuple as returned from L{backend.FindBlockDevice}
963 19708787 Iustin Pop
    @return: the string representing the status
964 7232c04c Iustin Pop
965 7232c04c Iustin Pop
    """
966 a8083063 Iustin Pop
    if not status:
967 19708787 Iustin Pop
      return "not active"
968 19708787 Iustin Pop
    txt = ""
969 f208978a Michael Hanselmann
    (path, major, minor, syncp, estt, degr, ldisk_status) = status
970 19708787 Iustin Pop
    if major is None:
971 19708787 Iustin Pop
      major_string = "N/A"
972 a8083063 Iustin Pop
    else:
973 19708787 Iustin Pop
      major_string = str(major)
974 fd38ef95 Manuel Franceschini
975 19708787 Iustin Pop
    if minor is None:
976 19708787 Iustin Pop
      minor_string = "N/A"
977 19708787 Iustin Pop
    else:
978 19708787 Iustin Pop
      minor_string = str(minor)
979 19708787 Iustin Pop
980 19708787 Iustin Pop
    txt += ("%s (%s:%s)" % (path, major_string, minor_string))
981 19708787 Iustin Pop
    if dtype in (constants.LD_DRBD8, ):
982 19708787 Iustin Pop
      if syncp is not None:
983 19708787 Iustin Pop
        sync_text = "*RECOVERING* %5.2f%%," % syncp
984 19708787 Iustin Pop
        if estt:
985 19708787 Iustin Pop
          sync_text += " ETA %ds" % estt
986 9db6dbce Iustin Pop
        else:
987 19708787 Iustin Pop
          sync_text += " ETA unknown"
988 19708787 Iustin Pop
      else:
989 19708787 Iustin Pop
        sync_text = "in sync"
990 19708787 Iustin Pop
      if degr:
991 19708787 Iustin Pop
        degr_text = "*DEGRADED*"
992 19708787 Iustin Pop
      else:
993 19708787 Iustin Pop
        degr_text = "ok"
994 f208978a Michael Hanselmann
      if ldisk_status == constants.LDS_FAULTY:
995 19708787 Iustin Pop
        ldisk_text = " *MISSING DISK*"
996 f208978a Michael Hanselmann
      elif ldisk_status == constants.LDS_UNKNOWN:
997 f208978a Michael Hanselmann
        ldisk_text = " *UNCERTAIN STATE*"
998 19708787 Iustin Pop
      else:
999 19708787 Iustin Pop
        ldisk_text = ""
1000 19708787 Iustin Pop
      txt += (" %s, status %s%s" % (sync_text, degr_text, ldisk_text))
1001 19708787 Iustin Pop
    elif dtype == constants.LD_LV:
1002 f208978a Michael Hanselmann
      if ldisk_status == constants.LDS_FAULTY:
1003 19708787 Iustin Pop
        ldisk_text = " *FAILED* (failed drive?)"
1004 19708787 Iustin Pop
      else:
1005 19708787 Iustin Pop
        ldisk_text = ""
1006 19708787 Iustin Pop
      txt += ldisk_text
1007 19708787 Iustin Pop
    return txt
1008 19708787 Iustin Pop
1009 19708787 Iustin Pop
  # the header
1010 19708787 Iustin Pop
  if top_level:
1011 19708787 Iustin Pop
    if dev["iv_name"] is not None:
1012 19708787 Iustin Pop
      txt = dev["iv_name"]
1013 19708787 Iustin Pop
    else:
1014 19708787 Iustin Pop
      txt = "disk %d" % idx
1015 a8083063 Iustin Pop
  else:
1016 19708787 Iustin Pop
    txt = "child %d" % idx
1017 c98162a7 Iustin Pop
  if isinstance(dev["size"], int):
1018 c98162a7 Iustin Pop
    nice_size = utils.FormatUnit(dev["size"], "h")
1019 c98162a7 Iustin Pop
  else:
1020 c98162a7 Iustin Pop
    nice_size = dev["size"]
1021 c98162a7 Iustin Pop
  d1 = ["- %s: %s, size %s" % (txt, dev["dev_type"], nice_size)]
1022 19708787 Iustin Pop
  data = []
1023 19708787 Iustin Pop
  if top_level:
1024 19708787 Iustin Pop
    data.append(("access mode", dev["mode"]))
1025 a8083063 Iustin Pop
  if dev["logical_id"] is not None:
1026 19708787 Iustin Pop
    try:
1027 19708787 Iustin Pop
      l_id = _FormatLogicalID(dev["dev_type"], dev["logical_id"])
1028 19708787 Iustin Pop
    except ValueError:
1029 19708787 Iustin Pop
      l_id = [str(dev["logical_id"])]
1030 19708787 Iustin Pop
    if len(l_id) == 1:
1031 19708787 Iustin Pop
      data.append(("logical_id", l_id[0]))
1032 19708787 Iustin Pop
    else:
1033 19708787 Iustin Pop
      data.extend(l_id)
1034 a8083063 Iustin Pop
  elif dev["physical_id"] is not None:
1035 19708787 Iustin Pop
    data.append("physical_id:")
1036 19708787 Iustin Pop
    data.append([dev["physical_id"]])
1037 57821cac Iustin Pop
  if not static:
1038 19708787 Iustin Pop
    data.append(("on primary", helper(dev["dev_type"], dev["pstatus"])))
1039 57821cac Iustin Pop
  if dev["sstatus"] and not static:
1040 19708787 Iustin Pop
    data.append(("on secondary", helper(dev["dev_type"], dev["sstatus"])))
1041 a8083063 Iustin Pop
1042 a8083063 Iustin Pop
  if dev["children"]:
1043 19708787 Iustin Pop
    data.append("child devices:")
1044 19708787 Iustin Pop
    for c_idx, child in enumerate(dev["children"]):
1045 19708787 Iustin Pop
      data.append(_FormatBlockDevInfo(c_idx, False, child, static))
1046 19708787 Iustin Pop
  d1.append(data)
1047 19708787 Iustin Pop
  return d1
1048 a8083063 Iustin Pop
1049 a8083063 Iustin Pop
1050 19708787 Iustin Pop
def _FormatList(buf, data, indent_level):
1051 19708787 Iustin Pop
  """Formats a list of data at a given indent level.
1052 19708787 Iustin Pop
1053 19708787 Iustin Pop
  If the element of the list is:
1054 19708787 Iustin Pop
    - a string, it is simply formatted as is
1055 19708787 Iustin Pop
    - a tuple, it will be split into key, value and the all the
1056 19708787 Iustin Pop
      values in a list will be aligned all at the same start column
1057 19708787 Iustin Pop
    - a list, will be recursively formatted
1058 19708787 Iustin Pop
1059 19708787 Iustin Pop
  @type buf: StringIO
1060 19708787 Iustin Pop
  @param buf: the buffer into which we write the output
1061 19708787 Iustin Pop
  @param data: the list to format
1062 19708787 Iustin Pop
  @type indent_level: int
1063 19708787 Iustin Pop
  @param indent_level: the indent level to format at
1064 19708787 Iustin Pop
1065 19708787 Iustin Pop
  """
1066 19708787 Iustin Pop
  max_tlen = max([len(elem[0]) for elem in data
1067 19708787 Iustin Pop
                 if isinstance(elem, tuple)] or [0])
1068 19708787 Iustin Pop
  for elem in data:
1069 19708787 Iustin Pop
    if isinstance(elem, basestring):
1070 19708787 Iustin Pop
      buf.write("%*s%s\n" % (2*indent_level, "", elem))
1071 19708787 Iustin Pop
    elif isinstance(elem, tuple):
1072 19708787 Iustin Pop
      key, value = elem
1073 19708787 Iustin Pop
      spacer = "%*s" % (max_tlen - len(key), "")
1074 19708787 Iustin Pop
      buf.write("%*s%s:%s %s\n" % (2*indent_level, "", key, spacer, value))
1075 19708787 Iustin Pop
    elif isinstance(elem, list):
1076 19708787 Iustin Pop
      _FormatList(buf, elem, indent_level+1)
1077 19708787 Iustin Pop
1078 98825740 Michael Hanselmann
1079 a8083063 Iustin Pop
def ShowInstanceConfig(opts, args):
1080 a8083063 Iustin Pop
  """Compute instance run-time status.
1081 a8083063 Iustin Pop
1082 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1083 7232c04c Iustin Pop
  @type args: list
1084 7232c04c Iustin Pop
  @param args: either an empty list, and then we query all
1085 7232c04c Iustin Pop
      instances, or should contain a list of instance names
1086 7232c04c Iustin Pop
  @rtype: int
1087 7232c04c Iustin Pop
  @return: the desired exit code
1088 7232c04c Iustin Pop
1089 a8083063 Iustin Pop
  """
1090 220cde0b Guido Trotter
  if not args and not opts.show_all:
1091 220cde0b Guido Trotter
    ToStderr("No instance selected."
1092 220cde0b Guido Trotter
             " Please pass in --all if you want to query all instances.\n"
1093 220cde0b Guido Trotter
             "Note that this can take a long time on a big cluster.")
1094 220cde0b Guido Trotter
    return 1
1095 220cde0b Guido Trotter
  elif args and opts.show_all:
1096 220cde0b Guido Trotter
    ToStderr("Cannot use --all if you specify instance names.")
1097 220cde0b Guido Trotter
    return 1
1098 220cde0b Guido Trotter
1099 a8083063 Iustin Pop
  retcode = 0
1100 57821cac Iustin Pop
  op = opcodes.OpQueryInstanceData(instances=args, static=opts.static)
1101 a8083063 Iustin Pop
  result = SubmitOpCode(op)
1102 a8083063 Iustin Pop
  if not result:
1103 3a24c527 Iustin Pop
    ToStdout("No instances.")
1104 a8083063 Iustin Pop
    return 1
1105 a8083063 Iustin Pop
1106 a8083063 Iustin Pop
  buf = StringIO()
1107 a8083063 Iustin Pop
  retcode = 0
1108 a8083063 Iustin Pop
  for instance_name in result:
1109 a8083063 Iustin Pop
    instance = result[instance_name]
1110 a8083063 Iustin Pop
    buf.write("Instance name: %s\n" % instance["name"])
1111 033d58b0 Iustin Pop
    buf.write("UUID: %s\n" % instance["uuid"])
1112 90f72445 Iustin Pop
    buf.write("Serial number: %s\n" % instance["serial_no"])
1113 90f72445 Iustin Pop
    buf.write("Creation time: %s\n" % utils.FormatTime(instance["ctime"]))
1114 90f72445 Iustin Pop
    buf.write("Modification time: %s\n" % utils.FormatTime(instance["mtime"]))
1115 57821cac Iustin Pop
    buf.write("State: configured to be %s" % instance["config_state"])
1116 57821cac Iustin Pop
    if not opts.static:
1117 57821cac Iustin Pop
      buf.write(", actual state is %s" % instance["run_state"])
1118 57821cac Iustin Pop
    buf.write("\n")
1119 57821cac Iustin Pop
    ##buf.write("Considered for memory checks in cluster verify: %s\n" %
1120 57821cac Iustin Pop
    ##          instance["auto_balance"])
1121 a8083063 Iustin Pop
    buf.write("  Nodes:\n")
1122 a8083063 Iustin Pop
    buf.write("    - primary: %s\n" % instance["pnode"])
1123 1f864b60 Iustin Pop
    buf.write("    - secondaries: %s\n" % utils.CommaJoin(instance["snodes"]))
1124 a8083063 Iustin Pop
    buf.write("  Operating system: %s\n" % instance["os"])
1125 a8340917 Iustin Pop
    if instance.has_key("network_port"):
1126 a8340917 Iustin Pop
      buf.write("  Allocated network port: %s\n" % instance["network_port"])
1127 24838135 Iustin Pop
    buf.write("  Hypervisor: %s\n" % instance["hypervisor"])
1128 dfff41f8 Guido Trotter
1129 dfff41f8 Guido Trotter
    # custom VNC console information
1130 dfff41f8 Guido Trotter
    vnc_bind_address = instance["hv_actual"].get(constants.HV_VNC_BIND_ADDRESS,
1131 dfff41f8 Guido Trotter
                                                 None)
1132 dfff41f8 Guido Trotter
    if vnc_bind_address:
1133 dfff41f8 Guido Trotter
      port = instance["network_port"]
1134 dfff41f8 Guido Trotter
      display = int(port) - constants.VNC_BASE_PORT
1135 dfff41f8 Guido Trotter
      if display > 0 and vnc_bind_address == constants.BIND_ADDRESS_GLOBAL:
1136 dfff41f8 Guido Trotter
        vnc_console_port = "%s:%s (display %s)" % (instance["pnode"],
1137 dfff41f8 Guido Trotter
                                                   port,
1138 dfff41f8 Guido Trotter
                                                   display)
1139 dfff41f8 Guido Trotter
      elif display > 0 and utils.IsValidIP(vnc_bind_address):
1140 dfff41f8 Guido Trotter
        vnc_console_port = ("%s:%s (node %s) (display %s)" %
1141 dfff41f8 Guido Trotter
                             (vnc_bind_address, port,
1142 dfff41f8 Guido Trotter
                              instance["pnode"], display))
1143 a8340917 Iustin Pop
      else:
1144 dfff41f8 Guido Trotter
        # vnc bind address is a file
1145 dfff41f8 Guido Trotter
        vnc_console_port = "%s:%s" % (instance["pnode"],
1146 dfff41f8 Guido Trotter
                                      vnc_bind_address)
1147 24838135 Iustin Pop
      buf.write("    - console connection: vnc to %s\n" % vnc_console_port)
1148 24838135 Iustin Pop
1149 dfff41f8 Guido Trotter
    for key in instance["hv_actual"]:
1150 24838135 Iustin Pop
      if key in instance["hv_instance"]:
1151 24838135 Iustin Pop
        val = instance["hv_instance"][key]
1152 a8340917 Iustin Pop
      else:
1153 24838135 Iustin Pop
        val = "default (%s)" % instance["hv_actual"][key]
1154 dfff41f8 Guido Trotter
      buf.write("    - %s: %s\n" % (key, val))
1155 a8083063 Iustin Pop
    buf.write("  Hardware:\n")
1156 338e51e8 Iustin Pop
    buf.write("    - VCPUs: %d\n" %
1157 338e51e8 Iustin Pop
              instance["be_actual"][constants.BE_VCPUS])
1158 338e51e8 Iustin Pop
    buf.write("    - memory: %dMiB\n" %
1159 338e51e8 Iustin Pop
              instance["be_actual"][constants.BE_MEMORY])
1160 d2acfe27 Iustin Pop
    buf.write("    - NICs:\n")
1161 14ea9302 Guido Trotter
    for idx, (ip, mac, mode, link) in enumerate(instance["nics"]):
1162 0b13832c Guido Trotter
      buf.write("      - nic/%d: MAC: %s, IP: %s, mode: %s, link: %s\n" %
1163 0b13832c Guido Trotter
                (idx, mac, ip, mode, link))
1164 19708787 Iustin Pop
    buf.write("  Disks:\n")
1165 a8083063 Iustin Pop
1166 19708787 Iustin Pop
    for idx, device in enumerate(instance["disks"]):
1167 19708787 Iustin Pop
      _FormatList(buf, _FormatBlockDevInfo(idx, True, device, opts.static), 2)
1168 a8083063 Iustin Pop
1169 3a24c527 Iustin Pop
  ToStdout(buf.getvalue().rstrip('\n'))
1170 a8083063 Iustin Pop
  return retcode
1171 a8083063 Iustin Pop
1172 a8083063 Iustin Pop
1173 7767bbf5 Manuel Franceschini
def SetInstanceParams(opts, args):
1174 a8083063 Iustin Pop
  """Modifies an instance.
1175 a8083063 Iustin Pop
1176 a8083063 Iustin Pop
  All parameters take effect only at the next restart of the instance.
1177 a8083063 Iustin Pop
1178 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1179 7232c04c Iustin Pop
  @type args: list
1180 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
1181 7232c04c Iustin Pop
  @rtype: int
1182 7232c04c Iustin Pop
  @return: the desired exit code
1183 a8083063 Iustin Pop
1184 a8083063 Iustin Pop
  """
1185 24991749 Iustin Pop
  if not (opts.nics or opts.disks or
1186 48f212d7 Iustin Pop
          opts.hvparams or opts.beparams):
1187 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
1188 a8083063 Iustin Pop
    return 1
1189 a8083063 Iustin Pop
1190 467ae11e Guido Trotter
  for param in opts.beparams:
1191 e9d622bc Guido Trotter
    if isinstance(opts.beparams[param], basestring):
1192 e9d622bc Guido Trotter
      if opts.beparams[param].lower() == "default":
1193 e9d622bc Guido Trotter
        opts.beparams[param] = constants.VALUE_DEFAULT
1194 a5728081 Guido Trotter
1195 a5728081 Guido Trotter
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_TYPES,
1196 a5728081 Guido Trotter
                      allowed_values=[constants.VALUE_DEFAULT])
1197 467ae11e Guido Trotter
1198 48f212d7 Iustin Pop
  for param in opts.hvparams:
1199 48f212d7 Iustin Pop
    if isinstance(opts.hvparams[param], basestring):
1200 48f212d7 Iustin Pop
      if opts.hvparams[param].lower() == "default":
1201 48f212d7 Iustin Pop
        opts.hvparams[param] = constants.VALUE_DEFAULT
1202 a5728081 Guido Trotter
1203 48f212d7 Iustin Pop
  utils.ForceDictType(opts.hvparams, constants.HVS_PARAMETER_TYPES,
1204 a5728081 Guido Trotter
                      allowed_values=[constants.VALUE_DEFAULT])
1205 61be6ba4 Iustin Pop
1206 24991749 Iustin Pop
  for idx, (nic_op, nic_dict) in enumerate(opts.nics):
1207 24991749 Iustin Pop
    try:
1208 24991749 Iustin Pop
      nic_op = int(nic_op)
1209 24991749 Iustin Pop
      opts.nics[idx] = (nic_op, nic_dict)
1210 24991749 Iustin Pop
    except ValueError:
1211 24991749 Iustin Pop
      pass
1212 24991749 Iustin Pop
1213 24991749 Iustin Pop
  for idx, (disk_op, disk_dict) in enumerate(opts.disks):
1214 24991749 Iustin Pop
    try:
1215 24991749 Iustin Pop
      disk_op = int(disk_op)
1216 24991749 Iustin Pop
      opts.disks[idx] = (disk_op, disk_dict)
1217 24991749 Iustin Pop
    except ValueError:
1218 24991749 Iustin Pop
      pass
1219 24991749 Iustin Pop
    if disk_op == constants.DDM_ADD:
1220 24991749 Iustin Pop
      if 'size' not in disk_dict:
1221 debac808 Iustin Pop
        raise errors.OpPrereqError("Missing required parameter 'size'",
1222 debac808 Iustin Pop
                                   errors.ECODE_INVAL)
1223 24991749 Iustin Pop
      disk_dict['size'] = utils.ParseUnit(disk_dict['size'])
1224 24991749 Iustin Pop
1225 338e51e8 Iustin Pop
  op = opcodes.OpSetInstanceParams(instance_name=args[0],
1226 24991749 Iustin Pop
                                   nics=opts.nics,
1227 24991749 Iustin Pop
                                   disks=opts.disks,
1228 48f212d7 Iustin Pop
                                   hvparams=opts.hvparams,
1229 338e51e8 Iustin Pop
                                   beparams=opts.beparams,
1230 4300c4b6 Guido Trotter
                                   force=opts.force)
1231 31a853d2 Iustin Pop
1232 6340bb0a Iustin Pop
  # even if here we process the result, we allow submit only
1233 6340bb0a Iustin Pop
  result = SubmitOrSend(op, opts)
1234 a8083063 Iustin Pop
1235 a8083063 Iustin Pop
  if result:
1236 3a24c527 Iustin Pop
    ToStdout("Modified instance %s", args[0])
1237 a8083063 Iustin Pop
    for param, data in result:
1238 3a24c527 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
1239 3a24c527 Iustin Pop
    ToStdout("Please don't forget that these parameters take effect"
1240 3a24c527 Iustin Pop
             " only at the next start of the instance.")
1241 a8083063 Iustin Pop
  return 0
1242 a8083063 Iustin Pop
1243 a8083063 Iustin Pop
1244 312ac745 Iustin Pop
# multi-instance selection options
1245 c38c44ad Michael Hanselmann
m_force_multi = cli_option("--force-multiple", dest="force_multi",
1246 c38c44ad Michael Hanselmann
                           help="Do not ask for confirmation when more than"
1247 c38c44ad Michael Hanselmann
                           " one instance is affected",
1248 c38c44ad Michael Hanselmann
                           action="store_true", default=False)
1249 804a1e8e Iustin Pop
1250 c38c44ad Michael Hanselmann
m_pri_node_opt = cli_option("--primary", dest="multi_mode",
1251 c38c44ad Michael Hanselmann
                            help="Filter by nodes (primary only)",
1252 c38c44ad Michael Hanselmann
                            const=_SHUTDOWN_NODES_PRI, action="store_const")
1253 312ac745 Iustin Pop
1254 c38c44ad Michael Hanselmann
m_sec_node_opt = cli_option("--secondary", dest="multi_mode",
1255 c38c44ad Michael Hanselmann
                            help="Filter by nodes (secondary only)",
1256 c38c44ad Michael Hanselmann
                            const=_SHUTDOWN_NODES_SEC, action="store_const")
1257 312ac745 Iustin Pop
1258 c38c44ad Michael Hanselmann
m_node_opt = cli_option("--node", dest="multi_mode",
1259 c38c44ad Michael Hanselmann
                        help="Filter by nodes (primary and secondary)",
1260 c38c44ad Michael Hanselmann
                        const=_SHUTDOWN_NODES_BOTH, action="store_const")
1261 312ac745 Iustin Pop
1262 c38c44ad Michael Hanselmann
m_clust_opt = cli_option("--all", dest="multi_mode",
1263 c38c44ad Michael Hanselmann
                         help="Select all instances in the cluster",
1264 c38c44ad Michael Hanselmann
                         const=_SHUTDOWN_CLUSTER, action="store_const")
1265 312ac745 Iustin Pop
1266 c38c44ad Michael Hanselmann
m_inst_opt = cli_option("--instance", dest="multi_mode",
1267 c38c44ad Michael Hanselmann
                        help="Filter by instance name [default]",
1268 c38c44ad Michael Hanselmann
                        const=_SHUTDOWN_INSTANCES, action="store_const")
1269 312ac745 Iustin Pop
1270 312ac745 Iustin Pop
1271 a8083063 Iustin Pop
# this is defined separately due to readability only
1272 a8083063 Iustin Pop
add_opts = [
1273 087ed2ed Iustin Pop
  BACKEND_OPT,
1274 e3876ccb Iustin Pop
  DISK_OPT,
1275 064c21f8 Iustin Pop
  DISK_TEMPLATE_OPT,
1276 4a25828c Iustin Pop
  FILESTORE_DIR_OPT,
1277 0f87c43e Iustin Pop
  FILESTORE_DRIVER_OPT,
1278 236fd9c4 Iustin Pop
  HYPERVISOR_OPT,
1279 064c21f8 Iustin Pop
  IALLOCATOR_OPT,
1280 064c21f8 Iustin Pop
  NET_OPT,
1281 064c21f8 Iustin Pop
  NODE_PLACEMENT_OPT,
1282 064c21f8 Iustin Pop
  NOIPCHECK_OPT,
1283 064c21f8 Iustin Pop
  NONICS_OPT,
1284 064c21f8 Iustin Pop
  NOSTART_OPT,
1285 064c21f8 Iustin Pop
  NWSYNC_OPT,
1286 064c21f8 Iustin Pop
  OS_OPT,
1287 06073e85 Guido Trotter
  FORCE_VARIANT_OPT,
1288 064c21f8 Iustin Pop
  OS_SIZE_OPT,
1289 6340bb0a Iustin Pop
  SUBMIT_OPT,
1290 a8083063 Iustin Pop
  ]
1291 a8083063 Iustin Pop
1292 a8083063 Iustin Pop
commands = {
1293 6ea815cf Iustin Pop
  'add': (
1294 6ea815cf Iustin Pop
    AddInstance, [ArgHost(min=1, max=1)], add_opts,
1295 6ea815cf Iustin Pop
    "[...] -t disk-type -n node[:secondary-node] -o os-type <name>",
1296 6ea815cf Iustin Pop
    "Creates and adds a new instance to the cluster"),
1297 6ea815cf Iustin Pop
  'batch-create': (
1298 064c21f8 Iustin Pop
    BatchCreate, [ArgFile(min=1, max=1)], [],
1299 6ea815cf Iustin Pop
    "<instances.json>",
1300 6ea815cf Iustin Pop
    "Create a bunch of instances based on specs in the file."),
1301 6ea815cf Iustin Pop
  'console': (
1302 6ea815cf Iustin Pop
    ConnectToInstanceConsole, ARGS_ONE_INSTANCE,
1303 064c21f8 Iustin Pop
    [SHOWCMD_OPT],
1304 6ea815cf Iustin Pop
    "[--show-cmd] <instance>", "Opens a console on the specified instance"),
1305 6ea815cf Iustin Pop
  'failover': (
1306 6ea815cf Iustin Pop
    FailoverInstance, ARGS_ONE_INSTANCE,
1307 17c3f802 Guido Trotter
    [FORCE_OPT, IGNORE_CONSIST_OPT, SUBMIT_OPT, SHUTDOWN_TIMEOUT_OPT],
1308 6ea815cf Iustin Pop
    "[-f] <instance>", "Stops the instance and starts it on the backup node,"
1309 6ea815cf Iustin Pop
    " using the remote mirror (only for instances of type drbd)"),
1310 6ea815cf Iustin Pop
  'migrate': (
1311 6ea815cf Iustin Pop
    MigrateInstance, ARGS_ONE_INSTANCE,
1312 064c21f8 Iustin Pop
    [FORCE_OPT, NONLIVE_OPT, CLEANUP_OPT],
1313 6ea815cf Iustin Pop
    "[-f] <instance>", "Migrate instance to its secondary node"
1314 6ea815cf Iustin Pop
    " (only for instances of type drbd)"),
1315 6ea815cf Iustin Pop
  'move': (
1316 6ea815cf Iustin Pop
    MoveInstance, ARGS_ONE_INSTANCE,
1317 17c3f802 Guido Trotter
    [FORCE_OPT, SUBMIT_OPT, SINGLE_NODE_OPT, SHUTDOWN_TIMEOUT_OPT],
1318 6ea815cf Iustin Pop
    "[-f] <instance>", "Move instance to an arbitrary node"
1319 6ea815cf Iustin Pop
    " (only for instances of type file and lv)"),
1320 6ea815cf Iustin Pop
  'info': (
1321 6ea815cf Iustin Pop
    ShowInstanceConfig, ARGS_MANY_INSTANCES,
1322 064c21f8 Iustin Pop
    [STATIC_OPT, ALL_OPT],
1323 6ea815cf Iustin Pop
    "[-s] {--all | <instance>...}",
1324 6ea815cf Iustin Pop
    "Show information on the specified instance(s)"),
1325 6ea815cf Iustin Pop
  'list': (
1326 6ea815cf Iustin Pop
    ListInstances, ARGS_MANY_INSTANCES,
1327 064c21f8 Iustin Pop
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, SYNC_OPT],
1328 6ea815cf Iustin Pop
    "[<instance>...]",
1329 6ea815cf Iustin Pop
    "Lists the instances and their status. The available fields are"
1330 6ea815cf Iustin Pop
    " (see the man page for details): status, oper_state, oper_ram,"
1331 6ea815cf Iustin Pop
    " name, os, pnode, snodes, admin_state, admin_ram, disk_template,"
1332 8619a3bd Guido Trotter
    " ip, mac, nic_mode, nic_link, sda_size, sdb_size, vcpus, serial_no,"
1333 8619a3bd Guido Trotter
    " nic.count, nic.mac/N, nic.ip/N, nic.mode/N, nic.link/N,"
1334 8619a3bd Guido Trotter
    " nic.macs, nic.ips, nic.modes, nic.links,"
1335 8619a3bd Guido Trotter
    " disk.count, disk.size/N, disk.sizes,"
1336 8619a3bd Guido Trotter
    " hv/NAME, be/memory, be/vcpus, be/auto_balance,"
1337 6ea815cf Iustin Pop
    " hypervisor."
1338 6ea815cf Iustin Pop
    " The default field"
1339 1f864b60 Iustin Pop
    " list is (in order): %s." % utils.CommaJoin(_LIST_DEF_FIELDS),
1340 6ea815cf Iustin Pop
    ),
1341 6ea815cf Iustin Pop
  'reinstall': (
1342 3e54ace7 Iustin Pop
    ReinstallInstance, [ArgInstance()],
1343 06073e85 Guido Trotter
    [FORCE_OPT, OS_OPT, FORCE_VARIANT_OPT, m_force_multi, m_node_opt,
1344 06073e85 Guido Trotter
     m_pri_node_opt, m_sec_node_opt, m_clust_opt, m_inst_opt, SELECT_OS_OPT,
1345 06073e85 Guido Trotter
     SUBMIT_OPT],
1346 6ea815cf Iustin Pop
    "[-f] <instance>", "Reinstall a stopped instance"),
1347 6ea815cf Iustin Pop
  'remove': (
1348 6ea815cf Iustin Pop
    RemoveInstance, ARGS_ONE_INSTANCE,
1349 17c3f802 Guido Trotter
    [FORCE_OPT, SHUTDOWN_TIMEOUT_OPT, IGNORE_FAILURES_OPT, SUBMIT_OPT],
1350 6ea815cf Iustin Pop
    "[-f] <instance>", "Shuts down the instance and removes it"),
1351 6ea815cf Iustin Pop
  'rename': (
1352 6ea815cf Iustin Pop
    RenameInstance,
1353 6ea815cf Iustin Pop
    [ArgInstance(min=1, max=1), ArgHost(min=1, max=1)],
1354 064c21f8 Iustin Pop
    [NOIPCHECK_OPT, SUBMIT_OPT],
1355 6ea815cf Iustin Pop
    "<instance> <new_name>", "Rename the instance"),
1356 6ea815cf Iustin Pop
  'replace-disks': (
1357 6ea815cf Iustin Pop
    ReplaceDisks, ARGS_ONE_INSTANCE,
1358 064c21f8 Iustin Pop
    [AUTO_REPLACE_OPT, DISKIDX_OPT, IALLOCATOR_OPT,
1359 6ea815cf Iustin Pop
     NEW_SECONDARY_OPT, ON_PRIMARY_OPT, ON_SECONDARY_OPT, SUBMIT_OPT],
1360 6ea815cf Iustin Pop
    "[-s|-p|-n NODE|-I NAME] <instance>",
1361 6ea815cf Iustin Pop
    "Replaces all disks for the instance"),
1362 6ea815cf Iustin Pop
  'modify': (
1363 6ea815cf Iustin Pop
    SetInstanceParams, ARGS_ONE_INSTANCE,
1364 064c21f8 Iustin Pop
    [BACKEND_OPT, DISK_OPT, FORCE_OPT, HVOPTS_OPT, NET_OPT, SUBMIT_OPT],
1365 6ea815cf Iustin Pop
    "<instance>", "Alters the parameters of an instance"),
1366 6ea815cf Iustin Pop
  'shutdown': (
1367 1c5945b6 Iustin Pop
    GenericManyOps("shutdown", _ShutdownInstance), [ArgInstance()],
1368 064c21f8 Iustin Pop
    [m_node_opt, m_pri_node_opt, m_sec_node_opt, m_clust_opt,
1369 6263189c Guido Trotter
     m_inst_opt, m_force_multi, TIMEOUT_OPT, SUBMIT_OPT],
1370 6ea815cf Iustin Pop
    "<instance>", "Stops an instance"),
1371 6ea815cf Iustin Pop
  'startup': (
1372 1c5945b6 Iustin Pop
    GenericManyOps("startup", _StartupInstance), [ArgInstance()],
1373 064c21f8 Iustin Pop
    [FORCE_OPT, m_force_multi, m_node_opt, m_pri_node_opt,
1374 6ea815cf Iustin Pop
     m_sec_node_opt, m_clust_opt, m_inst_opt, SUBMIT_OPT, HVOPTS_OPT,
1375 6ea815cf Iustin Pop
     BACKEND_OPT],
1376 6ea815cf Iustin Pop
    "<instance>", "Starts an instance"),
1377 6ea815cf Iustin Pop
  'reboot': (
1378 1c5945b6 Iustin Pop
    GenericManyOps("reboot", _RebootInstance), [ArgInstance()],
1379 064c21f8 Iustin Pop
    [m_force_multi, REBOOT_TYPE_OPT, IGNORE_SECONDARIES_OPT, m_node_opt,
1380 17c3f802 Guido Trotter
     m_pri_node_opt, m_sec_node_opt, m_clust_opt, m_inst_opt, SUBMIT_OPT,
1381 17c3f802 Guido Trotter
     SHUTDOWN_TIMEOUT_OPT],
1382 6ea815cf Iustin Pop
    "<instance>", "Reboots an instance"),
1383 6ea815cf Iustin Pop
  'activate-disks': (
1384 064c21f8 Iustin Pop
    ActivateDisks, ARGS_ONE_INSTANCE, [SUBMIT_OPT, IGNORE_SIZE_OPT],
1385 6ea815cf Iustin Pop
    "<instance>", "Activate an instance's disks"),
1386 6ea815cf Iustin Pop
  'deactivate-disks': (
1387 064c21f8 Iustin Pop
    DeactivateDisks, ARGS_ONE_INSTANCE, [SUBMIT_OPT],
1388 6ea815cf Iustin Pop
    "<instance>", "Deactivate an instance's disks"),
1389 6ea815cf Iustin Pop
  'recreate-disks': (
1390 064c21f8 Iustin Pop
    RecreateDisks, ARGS_ONE_INSTANCE, [SUBMIT_OPT, DISKIDX_OPT],
1391 6ea815cf Iustin Pop
    "<instance>", "Recreate an instance's disks"),
1392 6ea815cf Iustin Pop
  'grow-disk': (
1393 6ea815cf Iustin Pop
    GrowDisk,
1394 6ea815cf Iustin Pop
    [ArgInstance(min=1, max=1), ArgUnknown(min=1, max=1),
1395 6ea815cf Iustin Pop
     ArgUnknown(min=1, max=1)],
1396 064c21f8 Iustin Pop
    [SUBMIT_OPT, NWSYNC_OPT],
1397 6ea815cf Iustin Pop
    "<instance> <disk> <size>", "Grow an instance's disk"),
1398 6ea815cf Iustin Pop
  'list-tags': (
1399 064c21f8 Iustin Pop
    ListTags, ARGS_ONE_INSTANCE, [],
1400 6ea815cf Iustin Pop
    "<instance_name>", "List the tags of the given instance"),
1401 6ea815cf Iustin Pop
  'add-tags': (
1402 6ea815cf Iustin Pop
    AddTags, [ArgInstance(min=1, max=1), ArgUnknown()],
1403 064c21f8 Iustin Pop
    [TAG_SRC_OPT],
1404 6ea815cf Iustin Pop
    "<instance_name> tag...", "Add tags to the given instance"),
1405 6ea815cf Iustin Pop
  'remove-tags': (
1406 6ea815cf Iustin Pop
    RemoveTags, [ArgInstance(min=1, max=1), ArgUnknown()],
1407 064c21f8 Iustin Pop
    [TAG_SRC_OPT],
1408 6ea815cf Iustin Pop
    "<instance_name> tag...", "Remove tags from given instance"),
1409 a8083063 Iustin Pop
  }
1410 a8083063 Iustin Pop
1411 7232c04c Iustin Pop
#: dictionary with aliases for commands
1412 dbfd89dd Guido Trotter
aliases = {
1413 dbfd89dd Guido Trotter
  'activate_block_devs': 'activate-disks',
1414 00ce8b29 Guido Trotter
  'replace_disks': 'replace-disks',
1415 536fda25 Guido Trotter
  'start': 'startup',
1416 536fda25 Guido Trotter
  'stop': 'shutdown',
1417 dbfd89dd Guido Trotter
  }
1418 dbfd89dd Guido Trotter
1419 a8005e17 Michael Hanselmann
1420 a8083063 Iustin Pop
if __name__ == '__main__':
1421 dbfd89dd Guido Trotter
  sys.exit(GenericMain(commands, aliases=aliases,
1422 846baef9 Iustin Pop
                       override={"tag_type": constants.TAG_INSTANCE}))