Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-instance @ 19b9ba9a

History | View | Annotate | Download (52.9 kB)

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