Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-instance @ 7ea7bcf6

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