Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-instance @ 9769bb78

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