Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_instance.py @ 6b273e78

History | View | Annotate | Download (52.2 kB)

1 e792102d Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 60472d29 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 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 312ac745 Iustin Pop
import itertools
29 0d0e9090 René Nussbaumer
import simplejson
30 25ce3ec4 Michael Hanselmann
import logging
31 a8083063 Iustin Pop
from cStringIO import StringIO
32 a8083063 Iustin Pop
33 a8083063 Iustin Pop
from ganeti.cli import *
34 a8083063 Iustin Pop
from ganeti import opcodes
35 a8083063 Iustin Pop
from ganeti import constants
36 e2736e40 Guido Trotter
from ganeti import compat
37 a8083063 Iustin Pop
from ganeti import utils
38 312ac745 Iustin Pop
from ganeti import errors
39 a744b676 Manuel Franceschini
from ganeti import netutils
40 25ce3ec4 Michael Hanselmann
from ganeti import ssh
41 25ce3ec4 Michael Hanselmann
from ganeti import objects
42 312ac745 Iustin Pop
43 312ac745 Iustin Pop
44 312ac745 Iustin Pop
_SHUTDOWN_CLUSTER = "cluster"
45 312ac745 Iustin Pop
_SHUTDOWN_NODES_BOTH = "nodes"
46 312ac745 Iustin Pop
_SHUTDOWN_NODES_PRI = "nodes-pri"
47 312ac745 Iustin Pop
_SHUTDOWN_NODES_SEC = "nodes-sec"
48 39dfd93e René Nussbaumer
_SHUTDOWN_NODES_BOTH_BY_TAGS = "nodes-by-tags"
49 39dfd93e René Nussbaumer
_SHUTDOWN_NODES_PRI_BY_TAGS = "nodes-pri-by-tags"
50 39dfd93e René Nussbaumer
_SHUTDOWN_NODES_SEC_BY_TAGS = "nodes-sec-by-tags"
51 312ac745 Iustin Pop
_SHUTDOWN_INSTANCES = "instances"
52 39dfd93e René Nussbaumer
_SHUTDOWN_INSTANCES_BY_TAGS = "instances-by-tags"
53 39dfd93e René Nussbaumer
54 39dfd93e René Nussbaumer
_SHUTDOWN_NODES_TAGS_MODES = (
55 39dfd93e René Nussbaumer
    _SHUTDOWN_NODES_BOTH_BY_TAGS,
56 39dfd93e René Nussbaumer
    _SHUTDOWN_NODES_PRI_BY_TAGS,
57 39dfd93e René Nussbaumer
    _SHUTDOWN_NODES_SEC_BY_TAGS)
58 312ac745 Iustin Pop
59 7c0d6283 Michael Hanselmann
60 31a853d2 Iustin Pop
_VALUE_TRUE = "true"
61 31a853d2 Iustin Pop
62 7232c04c Iustin Pop
#: default list of options for L{ListInstances}
63 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
64 e69d05fd Iustin Pop
  "name", "hypervisor", "os", "pnode", "status", "oper_ram",
65 48c4dfa8 Iustin Pop
  ]
66 48c4dfa8 Iustin Pop
67 bdb7d4e8 Michael Hanselmann
68 479636a3 Iustin Pop
def _ExpandMultiNames(mode, names, client=None):
69 312ac745 Iustin Pop
  """Expand the given names using the passed mode.
70 312ac745 Iustin Pop

71 312ac745 Iustin Pop
  For _SHUTDOWN_CLUSTER, all instances will be returned. For
72 312ac745 Iustin Pop
  _SHUTDOWN_NODES_PRI/SEC, all instances having those nodes as
73 7232c04c Iustin Pop
  primary/secondary will be returned. For _SHUTDOWN_NODES_BOTH, all
74 312ac745 Iustin Pop
  instances having those nodes as either primary or secondary will be
75 312ac745 Iustin Pop
  returned. For _SHUTDOWN_INSTANCES, the given instances will be
76 312ac745 Iustin Pop
  returned.
77 312ac745 Iustin Pop

78 7232c04c Iustin Pop
  @param mode: one of L{_SHUTDOWN_CLUSTER}, L{_SHUTDOWN_NODES_BOTH},
79 7232c04c Iustin Pop
      L{_SHUTDOWN_NODES_PRI}, L{_SHUTDOWN_NODES_SEC} or
80 7232c04c Iustin Pop
      L{_SHUTDOWN_INSTANCES}
81 7232c04c Iustin Pop
  @param names: a list of names; for cluster, it must be empty,
82 7232c04c Iustin Pop
      and for node and instance it must be a list of valid item
83 7232c04c Iustin Pop
      names (short names are valid as usual, e.g. node1 instead of
84 7232c04c Iustin Pop
      node1.example.com)
85 7232c04c Iustin Pop
  @rtype: list
86 7232c04c Iustin Pop
  @return: the list of names after the expansion
87 7232c04c Iustin Pop
  @raise errors.ProgrammerError: for unknown selection type
88 7232c04c Iustin Pop
  @raise errors.OpPrereqError: for invalid input parameters
89 7232c04c Iustin Pop

90 312ac745 Iustin Pop
  """
91 7260cfbe Iustin Pop
  # pylint: disable-msg=W0142
92 39dfd93e René Nussbaumer
93 479636a3 Iustin Pop
  if client is None:
94 479636a3 Iustin Pop
    client = GetClient()
95 312ac745 Iustin Pop
  if mode == _SHUTDOWN_CLUSTER:
96 312ac745 Iustin Pop
    if names:
97 debac808 Iustin Pop
      raise errors.OpPrereqError("Cluster filter mode takes no arguments",
98 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
99 ec79568d Iustin Pop
    idata = client.QueryInstances([], ["name"], False)
100 312ac745 Iustin Pop
    inames = [row[0] for row in idata]
101 312ac745 Iustin Pop
102 312ac745 Iustin Pop
  elif mode in (_SHUTDOWN_NODES_BOTH,
103 312ac745 Iustin Pop
                _SHUTDOWN_NODES_PRI,
104 39dfd93e René Nussbaumer
                _SHUTDOWN_NODES_SEC) + _SHUTDOWN_NODES_TAGS_MODES:
105 39dfd93e René Nussbaumer
    if mode in _SHUTDOWN_NODES_TAGS_MODES:
106 39dfd93e René Nussbaumer
      if not names:
107 39dfd93e René Nussbaumer
        raise errors.OpPrereqError("No node tags passed", errors.ECODE_INVAL)
108 39dfd93e René Nussbaumer
      ndata = client.QueryNodes([], ["name", "pinst_list",
109 39dfd93e René Nussbaumer
                                     "sinst_list", "tags"], False)
110 39dfd93e René Nussbaumer
      ndata = [row for row in ndata if set(row[3]).intersection(names)]
111 39dfd93e René Nussbaumer
    else:
112 39dfd93e René Nussbaumer
      if not names:
113 39dfd93e René Nussbaumer
        raise errors.OpPrereqError("No node names passed", errors.ECODE_INVAL)
114 39dfd93e René Nussbaumer
      ndata = client.QueryNodes(names, ["name", "pinst_list", "sinst_list"],
115 77921a95 Iustin Pop
                              False)
116 39dfd93e René Nussbaumer
117 312ac745 Iustin Pop
    ipri = [row[1] for row in ndata]
118 312ac745 Iustin Pop
    pri_names = list(itertools.chain(*ipri))
119 312ac745 Iustin Pop
    isec = [row[2] for row in ndata]
120 312ac745 Iustin Pop
    sec_names = list(itertools.chain(*isec))
121 39dfd93e René Nussbaumer
    if mode in (_SHUTDOWN_NODES_BOTH, _SHUTDOWN_NODES_BOTH_BY_TAGS):
122 312ac745 Iustin Pop
      inames = pri_names + sec_names
123 39dfd93e René Nussbaumer
    elif mode in (_SHUTDOWN_NODES_PRI, _SHUTDOWN_NODES_PRI_BY_TAGS):
124 312ac745 Iustin Pop
      inames = pri_names
125 39dfd93e René Nussbaumer
    elif mode in (_SHUTDOWN_NODES_SEC, _SHUTDOWN_NODES_SEC_BY_TAGS):
126 312ac745 Iustin Pop
      inames = sec_names
127 312ac745 Iustin Pop
    else:
128 312ac745 Iustin Pop
      raise errors.ProgrammerError("Unhandled shutdown type")
129 312ac745 Iustin Pop
  elif mode == _SHUTDOWN_INSTANCES:
130 312ac745 Iustin Pop
    if not names:
131 debac808 Iustin Pop
      raise errors.OpPrereqError("No instance names passed",
132 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
133 ec79568d Iustin Pop
    idata = client.QueryInstances(names, ["name"], False)
134 312ac745 Iustin Pop
    inames = [row[0] for row in idata]
135 39dfd93e René Nussbaumer
  elif mode == _SHUTDOWN_INSTANCES_BY_TAGS:
136 39dfd93e René Nussbaumer
    if not names:
137 39dfd93e René Nussbaumer
      raise errors.OpPrereqError("No instance tags passed",
138 39dfd93e René Nussbaumer
                                 errors.ECODE_INVAL)
139 39dfd93e René Nussbaumer
    idata = client.QueryInstances([], ["name", "tags"], False)
140 39dfd93e René Nussbaumer
    inames = [row[0] for row in idata if set(row[1]).intersection(names)]
141 312ac745 Iustin Pop
  else:
142 debac808 Iustin Pop
    raise errors.OpPrereqError("Unknown mode '%s'" % mode, errors.ECODE_INVAL)
143 312ac745 Iustin Pop
144 312ac745 Iustin Pop
  return inames
145 a8083063 Iustin Pop
146 a8083063 Iustin Pop
147 55efe6da Iustin Pop
def _ConfirmOperation(inames, text, extra=""):
148 804a1e8e Iustin Pop
  """Ask the user to confirm an operation on a list of instances.
149 804a1e8e Iustin Pop

150 804a1e8e Iustin Pop
  This function is used to request confirmation for doing an operation
151 804a1e8e Iustin Pop
  on a given list of instances.
152 804a1e8e Iustin Pop

153 7232c04c Iustin Pop
  @type inames: list
154 7232c04c Iustin Pop
  @param inames: the list of names that we display when
155 7232c04c Iustin Pop
      we ask for confirmation
156 7232c04c Iustin Pop
  @type text: str
157 7232c04c Iustin Pop
  @param text: the operation that the user should confirm
158 7232c04c Iustin Pop
      (e.g. I{shutdown} or I{startup})
159 7232c04c Iustin Pop
  @rtype: boolean
160 7232c04c Iustin Pop
  @return: True or False depending on user's confirmation.
161 804a1e8e Iustin Pop

162 804a1e8e Iustin Pop
  """
163 804a1e8e Iustin Pop
  count = len(inames)
164 55efe6da Iustin Pop
  msg = ("The %s will operate on %d instances.\n%s"
165 55efe6da Iustin Pop
         "Do you want to continue?" % (text, count, extra))
166 804a1e8e Iustin Pop
  affected = ("\nAffected instances:\n" +
167 804a1e8e Iustin Pop
              "\n".join(["  %s" % name for name in inames]))
168 804a1e8e Iustin Pop
169 804a1e8e Iustin Pop
  choices = [('y', True, 'Yes, execute the %s' % text),
170 804a1e8e Iustin Pop
             ('n', False, 'No, abort the %s' % text)]
171 804a1e8e Iustin Pop
172 804a1e8e Iustin Pop
  if count > 20:
173 804a1e8e Iustin Pop
    choices.insert(1, ('v', 'v', 'View the list of affected instances'))
174 804a1e8e Iustin Pop
    ask = msg
175 804a1e8e Iustin Pop
  else:
176 804a1e8e Iustin Pop
    ask = msg + affected
177 804a1e8e Iustin Pop
178 804a1e8e Iustin Pop
  choice = AskUser(ask, choices)
179 804a1e8e Iustin Pop
  if choice == 'v':
180 804a1e8e Iustin Pop
    choices.pop(1)
181 5e66b7e6 Iustin Pop
    choice = AskUser(msg + affected, choices)
182 804a1e8e Iustin Pop
  return choice
183 804a1e8e Iustin Pop
184 804a1e8e Iustin Pop
185 a76f0c4a Iustin Pop
def _EnsureInstancesExist(client, names):
186 a76f0c4a Iustin Pop
  """Check for and ensure the given instance names exist.
187 a76f0c4a Iustin Pop

188 a76f0c4a Iustin Pop
  This function will raise an OpPrereqError in case they don't
189 a76f0c4a Iustin Pop
  exist. Otherwise it will exit cleanly.
190 a76f0c4a Iustin Pop

191 f2fd87d7 Iustin Pop
  @type client: L{ganeti.luxi.Client}
192 a76f0c4a Iustin Pop
  @param client: the client to use for the query
193 a76f0c4a Iustin Pop
  @type names: list
194 a76f0c4a Iustin Pop
  @param names: the list of instance names to query
195 a76f0c4a Iustin Pop
  @raise errors.OpPrereqError: in case any instance is missing
196 a76f0c4a Iustin Pop

197 a76f0c4a Iustin Pop
  """
198 f2af0bec Iustin Pop
  # TODO: change LUInstanceQuery to that it actually returns None
199 a76f0c4a Iustin Pop
  # instead of raising an exception, or devise a better mechanism
200 ec79568d Iustin Pop
  result = client.QueryInstances(names, ["name"], False)
201 a76f0c4a Iustin Pop
  for orig_name, row in zip(names, result):
202 a76f0c4a Iustin Pop
    if row[0] is None:
203 debac808 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' does not exist" % orig_name,
204 debac808 Iustin Pop
                                 errors.ECODE_NOENT)
205 a76f0c4a Iustin Pop
206 a76f0c4a Iustin Pop
207 1c5945b6 Iustin Pop
def GenericManyOps(operation, fn):
208 1c5945b6 Iustin Pop
  """Generic multi-instance operations.
209 1c5945b6 Iustin Pop

210 1c5945b6 Iustin Pop
  The will return a wrapper that processes the options and arguments
211 1c5945b6 Iustin Pop
  given, and uses the passed function to build the opcode needed for
212 1c5945b6 Iustin Pop
  the specific operation. Thus all the generic loop/confirmation code
213 1c5945b6 Iustin Pop
  is abstracted into this function.
214 1c5945b6 Iustin Pop

215 1c5945b6 Iustin Pop
  """
216 1c5945b6 Iustin Pop
  def realfn(opts, args):
217 1c5945b6 Iustin Pop
    if opts.multi_mode is None:
218 1c5945b6 Iustin Pop
      opts.multi_mode = _SHUTDOWN_INSTANCES
219 1c5945b6 Iustin Pop
    cl = GetClient()
220 1c5945b6 Iustin Pop
    inames = _ExpandMultiNames(opts.multi_mode, args, client=cl)
221 1c5945b6 Iustin Pop
    if not inames:
222 1c5945b6 Iustin Pop
      raise errors.OpPrereqError("Selection filter does not match"
223 debac808 Iustin Pop
                                 " any instances", errors.ECODE_INVAL)
224 1c5945b6 Iustin Pop
    multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
225 1c5945b6 Iustin Pop
    if not (opts.force_multi or not multi_on
226 1c5945b6 Iustin Pop
            or _ConfirmOperation(inames, operation)):
227 1c5945b6 Iustin Pop
      return 1
228 cb573a31 Iustin Pop
    jex = JobExecutor(verbose=multi_on, cl=cl, opts=opts)
229 1c5945b6 Iustin Pop
    for name in inames:
230 1c5945b6 Iustin Pop
      op = fn(name, opts)
231 1c5945b6 Iustin Pop
      jex.QueueJob(name, op)
232 b4e68848 Iustin Pop
    results = jex.WaitOrShow(not opts.submit_only)
233 b4e68848 Iustin Pop
    rcode = compat.all(row[0] for row in results)
234 b4e68848 Iustin Pop
    return int(not rcode)
235 1c5945b6 Iustin Pop
  return realfn
236 1c5945b6 Iustin Pop
237 1c5945b6 Iustin Pop
238 a8083063 Iustin Pop
def ListInstances(opts, args):
239 f5abe9bd Oleksiy Mishchenko
  """List instances and their properties.
240 a8083063 Iustin Pop

241 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
242 7232c04c Iustin Pop
  @type args: list
243 7232c04c Iustin Pop
  @param args: should be an empty list
244 7232c04c Iustin Pop
  @rtype: int
245 7232c04c Iustin Pop
  @return: the desired exit code
246 7232c04c Iustin Pop

247 a8083063 Iustin Pop
  """
248 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
249 a8083063 Iustin Pop
250 b82c5ff5 Michael Hanselmann
  fmtoverride = dict.fromkeys(["tags", "disk.sizes", "nic.macs", "nic.ips",
251 b82c5ff5 Michael Hanselmann
                               "nic.modes", "nic.links", "nic.bridges",
252 b82c5ff5 Michael Hanselmann
                               "snodes"],
253 b82c5ff5 Michael Hanselmann
                              (lambda value: ",".join(str(item)
254 b82c5ff5 Michael Hanselmann
                                                      for item in value),
255 b82c5ff5 Michael Hanselmann
                               False))
256 a8083063 Iustin Pop
257 b82c5ff5 Michael Hanselmann
  return GenericList(constants.QR_INSTANCE, selected_fields, args, opts.units,
258 b82c5ff5 Michael Hanselmann
                     opts.separator, not opts.no_headers,
259 b82c5ff5 Michael Hanselmann
                     format_override=fmtoverride)
260 b82c5ff5 Michael Hanselmann
261 b82c5ff5 Michael Hanselmann
262 b82c5ff5 Michael Hanselmann
def ListInstanceFields(opts, args):
263 b82c5ff5 Michael Hanselmann
  """List instance fields.
264 b82c5ff5 Michael Hanselmann

265 b82c5ff5 Michael Hanselmann
  @param opts: the command line options selected by the user
266 b82c5ff5 Michael Hanselmann
  @type args: list
267 b82c5ff5 Michael Hanselmann
  @param args: fields to list, or empty for all
268 b82c5ff5 Michael Hanselmann
  @rtype: int
269 b82c5ff5 Michael Hanselmann
  @return: the desired exit code
270 b82c5ff5 Michael Hanselmann

271 b82c5ff5 Michael Hanselmann
  """
272 b82c5ff5 Michael Hanselmann
  return GenericListFields(constants.QR_INSTANCE, args, opts.separator,
273 b82c5ff5 Michael Hanselmann
                           not opts.no_headers)
274 a8083063 Iustin Pop
275 a8083063 Iustin Pop
276 a8083063 Iustin Pop
def AddInstance(opts, args):
277 a8083063 Iustin Pop
  """Add an instance to the cluster.
278 a8083063 Iustin Pop

279 d77490c5 Iustin Pop
  This is just a wrapper over GenericInstanceCreate.
280 a8083063 Iustin Pop

281 a8083063 Iustin Pop
  """
282 d77490c5 Iustin Pop
  return GenericInstanceCreate(constants.INSTANCE_CREATE, opts, args)
283 a8083063 Iustin Pop
284 a8083063 Iustin Pop
285 0d0e9090 René Nussbaumer
def BatchCreate(opts, args):
286 7232c04c Iustin Pop
  """Create instances using a definition file.
287 7232c04c Iustin Pop

288 7232c04c Iustin Pop
  This function reads a json file with instances defined
289 7232c04c Iustin Pop
  in the form::
290 7232c04c Iustin Pop

291 7232c04c Iustin Pop
    {"instance-name":{
292 9939547b Iustin Pop
      "disk_size": [20480],
293 7232c04c Iustin Pop
      "template": "drbd",
294 7232c04c Iustin Pop
      "backend": {
295 7232c04c Iustin Pop
        "memory": 512,
296 7232c04c Iustin Pop
        "vcpus": 1 },
297 9939547b Iustin Pop
      "os": "debootstrap",
298 7232c04c Iustin Pop
      "primary_node": "firstnode",
299 7232c04c Iustin Pop
      "secondary_node": "secondnode",
300 7232c04c Iustin Pop
      "iallocator": "dumb"}
301 7232c04c Iustin Pop
    }
302 7232c04c Iustin Pop

303 7232c04c Iustin Pop
  Note that I{primary_node} and I{secondary_node} have precedence over
304 7232c04c Iustin Pop
  I{iallocator}.
305 7232c04c Iustin Pop

306 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
307 7232c04c Iustin Pop
  @type args: list
308 7232c04c Iustin Pop
  @param args: should contain one element, the json filename
309 7232c04c Iustin Pop
  @rtype: int
310 7232c04c Iustin Pop
  @return: the desired exit code
311 0d0e9090 René Nussbaumer

312 0d0e9090 René Nussbaumer
  """
313 9939547b Iustin Pop
  _DEFAULT_SPECS = {"disk_size": [20 * 1024],
314 0d0e9090 René Nussbaumer
                    "backend": {},
315 0d0e9090 René Nussbaumer
                    "iallocator": None,
316 0d0e9090 René Nussbaumer
                    "primary_node": None,
317 0d0e9090 René Nussbaumer
                    "secondary_node": None,
318 a379d9bd Guido Trotter
                    "nics": None,
319 0d0e9090 René Nussbaumer
                    "start": True,
320 0d0e9090 René Nussbaumer
                    "ip_check": True,
321 460d22be Iustin Pop
                    "name_check": True,
322 0d0e9090 René Nussbaumer
                    "hypervisor": None,
323 4082e6f9 Iustin Pop
                    "hvparams": {},
324 0d0e9090 René Nussbaumer
                    "file_storage_dir": None,
325 27ba7eab Guido Trotter
                    "force_variant": False,
326 0d0e9090 René Nussbaumer
                    "file_driver": 'loop'}
327 0d0e9090 René Nussbaumer
328 0d0e9090 René Nussbaumer
  def _PopulateWithDefaults(spec):
329 0d0e9090 René Nussbaumer
    """Returns a new hash combined with default values."""
330 2f79bd34 Iustin Pop
    mydict = _DEFAULT_SPECS.copy()
331 2f79bd34 Iustin Pop
    mydict.update(spec)
332 2f79bd34 Iustin Pop
    return mydict
333 0d0e9090 René Nussbaumer
334 0d0e9090 René Nussbaumer
  def _Validate(spec):
335 0d0e9090 René Nussbaumer
    """Validate the instance specs."""
336 0d0e9090 René Nussbaumer
    # Validate fields required under any circumstances
337 0d0e9090 René Nussbaumer
    for required_field in ('os', 'template'):
338 0d0e9090 René Nussbaumer
      if required_field not in spec:
339 0d0e9090 René Nussbaumer
        raise errors.OpPrereqError('Required field "%s" is missing.' %
340 debac808 Iustin Pop
                                   required_field, errors.ECODE_INVAL)
341 0d0e9090 René Nussbaumer
    # Validate special fields
342 0d0e9090 René Nussbaumer
    if spec['primary_node'] is not None:
343 0d0e9090 René Nussbaumer
      if (spec['template'] in constants.DTS_NET_MIRROR and
344 0d0e9090 René Nussbaumer
          spec['secondary_node'] is None):
345 0d0e9090 René Nussbaumer
        raise errors.OpPrereqError('Template requires secondary node, but'
346 debac808 Iustin Pop
                                   ' there was no secondary provided.',
347 debac808 Iustin Pop
                                   errors.ECODE_INVAL)
348 0d0e9090 René Nussbaumer
    elif spec['iallocator'] is None:
349 0d0e9090 René Nussbaumer
      raise errors.OpPrereqError('You have to provide at least a primary_node'
350 debac808 Iustin Pop
                                 ' or an iallocator.',
351 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
352 0d0e9090 René Nussbaumer
353 4082e6f9 Iustin Pop
    if (spec['hvparams'] and
354 4082e6f9 Iustin Pop
        not isinstance(spec['hvparams'], dict)):
355 debac808 Iustin Pop
      raise errors.OpPrereqError('Hypervisor parameters must be a dict.',
356 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
357 0d0e9090 René Nussbaumer
358 0d0e9090 René Nussbaumer
  json_filename = args[0]
359 0d0e9090 René Nussbaumer
  try:
360 13998ef2 Michael Hanselmann
    instance_data = simplejson.loads(utils.ReadFile(json_filename))
361 7260cfbe Iustin Pop
  except Exception, err: # pylint: disable-msg=W0703
362 4082e6f9 Iustin Pop
    ToStderr("Can't parse the instance definition file: %s" % str(err))
363 4082e6f9 Iustin Pop
    return 1
364 0d0e9090 René Nussbaumer
365 fe7c59d5 Guido Trotter
  if not isinstance(instance_data, dict):
366 fe7c59d5 Guido Trotter
    ToStderr("The instance definition file is not in dict format.")
367 fe7c59d5 Guido Trotter
    return 1
368 fe7c59d5 Guido Trotter
369 cb573a31 Iustin Pop
  jex = JobExecutor(opts=opts)
370 d4dd4b74 Iustin Pop
371 0d0e9090 René Nussbaumer
  # Iterate over the instances and do:
372 0d0e9090 René Nussbaumer
  #  * Populate the specs with default value
373 0d0e9090 René Nussbaumer
  #  * Validate the instance specs
374 fe7c59d5 Guido Trotter
  i_names = utils.NiceSort(instance_data.keys()) # pylint: disable-msg=E1103
375 7312b33d Iustin Pop
  for name in i_names:
376 7312b33d Iustin Pop
    specs = instance_data[name]
377 0d0e9090 René Nussbaumer
    specs = _PopulateWithDefaults(specs)
378 0d0e9090 René Nussbaumer
    _Validate(specs)
379 0d0e9090 René Nussbaumer
380 4082e6f9 Iustin Pop
    hypervisor = specs['hypervisor']
381 4082e6f9 Iustin Pop
    hvparams = specs['hvparams']
382 0d0e9090 René Nussbaumer
383 9939547b Iustin Pop
    disks = []
384 9939547b Iustin Pop
    for elem in specs['disk_size']:
385 9939547b Iustin Pop
      try:
386 9939547b Iustin Pop
        size = utils.ParseUnit(elem)
387 691744c4 Iustin Pop
      except (TypeError, ValueError), err:
388 9939547b Iustin Pop
        raise errors.OpPrereqError("Invalid disk size '%s' for"
389 9939547b Iustin Pop
                                   " instance %s: %s" %
390 debac808 Iustin Pop
                                   (elem, name, err), errors.ECODE_INVAL)
391 9939547b Iustin Pop
      disks.append({"size": size})
392 9939547b Iustin Pop
393 a5728081 Guido Trotter
    utils.ForceDictType(specs['backend'], constants.BES_PARAMETER_TYPES)
394 a5728081 Guido Trotter
    utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
395 a5728081 Guido Trotter
396 a379d9bd Guido Trotter
    tmp_nics = []
397 a379d9bd Guido Trotter
    for field in ('ip', 'mac', 'mode', 'link', 'bridge'):
398 a379d9bd Guido Trotter
      if field in specs:
399 a379d9bd Guido Trotter
        if not tmp_nics:
400 a379d9bd Guido Trotter
          tmp_nics.append({})
401 a379d9bd Guido Trotter
        tmp_nics[0][field] = specs[field]
402 a379d9bd Guido Trotter
403 a379d9bd Guido Trotter
    if specs['nics'] is not None and tmp_nics:
404 a379d9bd Guido Trotter
      raise errors.OpPrereqError("'nics' list incompatible with using"
405 debac808 Iustin Pop
                                 " individual nic fields as well",
406 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
407 a379d9bd Guido Trotter
    elif specs['nics'] is not None:
408 a379d9bd Guido Trotter
      tmp_nics = specs['nics']
409 a379d9bd Guido Trotter
    elif not tmp_nics:
410 a379d9bd Guido Trotter
      tmp_nics = [{}]
411 a379d9bd Guido Trotter
412 e1530b10 Iustin Pop
    op = opcodes.OpInstanceCreate(instance_name=name,
413 9939547b Iustin Pop
                                  disks=disks,
414 0d0e9090 René Nussbaumer
                                  disk_template=specs['template'],
415 0d0e9090 René Nussbaumer
                                  mode=constants.INSTANCE_CREATE,
416 0d0e9090 René Nussbaumer
                                  os_type=specs['os'],
417 de372295 Guido Trotter
                                  force_variant=specs["force_variant"],
418 0d0e9090 René Nussbaumer
                                  pnode=specs['primary_node'],
419 0d0e9090 René Nussbaumer
                                  snode=specs['secondary_node'],
420 a379d9bd Guido Trotter
                                  nics=tmp_nics,
421 0d0e9090 René Nussbaumer
                                  start=specs['start'],
422 0d0e9090 René Nussbaumer
                                  ip_check=specs['ip_check'],
423 460d22be Iustin Pop
                                  name_check=specs['name_check'],
424 0d0e9090 René Nussbaumer
                                  wait_for_sync=True,
425 0d0e9090 René Nussbaumer
                                  iallocator=specs['iallocator'],
426 0d0e9090 René Nussbaumer
                                  hypervisor=hypervisor,
427 0d0e9090 René Nussbaumer
                                  hvparams=hvparams,
428 0d0e9090 René Nussbaumer
                                  beparams=specs['backend'],
429 0d0e9090 René Nussbaumer
                                  file_storage_dir=specs['file_storage_dir'],
430 0d0e9090 René Nussbaumer
                                  file_driver=specs['file_driver'])
431 0d0e9090 René Nussbaumer
432 d4dd4b74 Iustin Pop
    jex.QueueJob(name, op)
433 d4dd4b74 Iustin Pop
  # we never want to wait, just show the submitted job IDs
434 d4dd4b74 Iustin Pop
  jex.WaitOrShow(False)
435 0d0e9090 René Nussbaumer
436 0d0e9090 René Nussbaumer
  return 0
437 0d0e9090 René Nussbaumer
438 0d0e9090 René Nussbaumer
439 fe7b0351 Michael Hanselmann
def ReinstallInstance(opts, args):
440 fe7b0351 Michael Hanselmann
  """Reinstall an instance.
441 fe7b0351 Michael Hanselmann

442 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
443 7232c04c Iustin Pop
  @type args: list
444 7232c04c Iustin Pop
  @param args: should contain only one element, the name of the
445 7232c04c Iustin Pop
      instance to be reinstalled
446 7232c04c Iustin Pop
  @rtype: int
447 7232c04c Iustin Pop
  @return: the desired exit code
448 fe7b0351 Michael Hanselmann

449 fe7b0351 Michael Hanselmann
  """
450 55efe6da Iustin Pop
  # first, compute the desired name list
451 55efe6da Iustin Pop
  if opts.multi_mode is None:
452 55efe6da Iustin Pop
    opts.multi_mode = _SHUTDOWN_INSTANCES
453 55efe6da Iustin Pop
454 55efe6da Iustin Pop
  inames = _ExpandMultiNames(opts.multi_mode, args)
455 55efe6da Iustin Pop
  if not inames:
456 debac808 Iustin Pop
    raise errors.OpPrereqError("Selection filter does not match any instances",
457 debac808 Iustin Pop
                               errors.ECODE_INVAL)
458 fe7b0351 Michael Hanselmann
459 55efe6da Iustin Pop
  # second, if requested, ask for an OS
460 20e23543 Alexander Schreiber
  if opts.select_os is True:
461 d22dfef7 Iustin Pop
    op = opcodes.OpDiagnoseOS(output_fields=["name", "variants"], names=[])
462 400ca2f7 Iustin Pop
    result = SubmitOpCode(op, opts=opts)
463 20e23543 Alexander Schreiber
464 20e23543 Alexander Schreiber
    if not result:
465 3a24c527 Iustin Pop
      ToStdout("Can't get the OS list")
466 20e23543 Alexander Schreiber
      return 1
467 20e23543 Alexander Schreiber
468 3a24c527 Iustin Pop
    ToStdout("Available OS templates:")
469 20e23543 Alexander Schreiber
    number = 0
470 20e23543 Alexander Schreiber
    choices = []
471 d22dfef7 Iustin Pop
    for (name, variants) in result:
472 d22dfef7 Iustin Pop
      for entry in CalculateOSNames(name, variants):
473 d22dfef7 Iustin Pop
        ToStdout("%3s: %s", number, entry)
474 d22dfef7 Iustin Pop
        choices.append(("%s" % number, entry, entry))
475 d22dfef7 Iustin Pop
        number += 1
476 20e23543 Alexander Schreiber
477 20e23543 Alexander Schreiber
    choices.append(('x', 'exit', 'Exit gnt-instance reinstall'))
478 949bdabe Iustin Pop
    selected = AskUser("Enter OS template number (or x to abort):",
479 20e23543 Alexander Schreiber
                       choices)
480 20e23543 Alexander Schreiber
481 20e23543 Alexander Schreiber
    if selected == 'exit':
482 55efe6da Iustin Pop
      ToStderr("User aborted reinstall, exiting")
483 20e23543 Alexander Schreiber
      return 1
484 20e23543 Alexander Schreiber
485 2f79bd34 Iustin Pop
    os_name = selected
486 20e23543 Alexander Schreiber
  else:
487 2f79bd34 Iustin Pop
    os_name = opts.os
488 20e23543 Alexander Schreiber
489 297ddce9 Iustin Pop
  # third, get confirmation: multi-reinstall requires --force-multi,
490 297ddce9 Iustin Pop
  # single-reinstall either --force or --force-multi (--force-multi is
491 297ddce9 Iustin Pop
  # a stronger --force)
492 55efe6da Iustin Pop
  multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
493 55efe6da Iustin Pop
  if multi_on:
494 55efe6da Iustin Pop
    warn_msg = "Note: this will remove *all* data for the below instances!\n"
495 297ddce9 Iustin Pop
    if not (opts.force_multi or
496 55efe6da Iustin Pop
            _ConfirmOperation(inames, "reinstall", extra=warn_msg)):
497 fe7b0351 Michael Hanselmann
      return 1
498 55efe6da Iustin Pop
  else:
499 297ddce9 Iustin Pop
    if not (opts.force or opts.force_multi):
500 55efe6da Iustin Pop
      usertext = ("This will reinstall the instance %s and remove"
501 b6e243ab Iustin Pop
                  " all data. Continue?") % inames[0]
502 55efe6da Iustin Pop
      if not AskUser(usertext):
503 55efe6da Iustin Pop
        return 1
504 55efe6da Iustin Pop
505 cb573a31 Iustin Pop
  jex = JobExecutor(verbose=multi_on, opts=opts)
506 55efe6da Iustin Pop
  for instance_name in inames:
507 55efe6da Iustin Pop
    op = opcodes.OpReinstallInstance(instance_name=instance_name,
508 06073e85 Guido Trotter
                                     os_type=os_name,
509 8d8c4eff Michael Hanselmann
                                     force_variant=opts.force_variant,
510 8d8c4eff Michael Hanselmann
                                     osparams=opts.osparams)
511 55efe6da Iustin Pop
    jex.QueueJob(instance_name, op)
512 fe7b0351 Michael Hanselmann
513 55efe6da Iustin Pop
  jex.WaitOrShow(not opts.submit_only)
514 fe7b0351 Michael Hanselmann
  return 0
515 fe7b0351 Michael Hanselmann
516 fe7b0351 Michael Hanselmann
517 a8083063 Iustin Pop
def RemoveInstance(opts, args):
518 a8083063 Iustin Pop
  """Remove an instance.
519 a8083063 Iustin Pop

520 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
521 7232c04c Iustin Pop
  @type args: list
522 7232c04c Iustin Pop
  @param args: should contain only one element, the name of
523 7232c04c Iustin Pop
      the instance to be removed
524 7232c04c Iustin Pop
  @rtype: int
525 7232c04c Iustin Pop
  @return: the desired exit code
526 a8083063 Iustin Pop

527 a8083063 Iustin Pop
  """
528 a8083063 Iustin Pop
  instance_name = args[0]
529 a8083063 Iustin Pop
  force = opts.force
530 a76f0c4a Iustin Pop
  cl = GetClient()
531 a8083063 Iustin Pop
532 a8083063 Iustin Pop
  if not force:
533 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
534 a76f0c4a Iustin Pop
535 a8083063 Iustin Pop
    usertext = ("This will remove the volumes of the instance %s"
536 a8083063 Iustin Pop
                " (including mirrors), thus removing all the data"
537 a8083063 Iustin Pop
                " of the instance. Continue?") % instance_name
538 47988778 Iustin Pop
    if not AskUser(usertext):
539 a8083063 Iustin Pop
      return 1
540 a8083063 Iustin Pop
541 1d67656e Iustin Pop
  op = opcodes.OpRemoveInstance(instance_name=instance_name,
542 17c3f802 Guido Trotter
                                ignore_failures=opts.ignore_failures,
543 4d98c565 Guido Trotter
                                shutdown_timeout=opts.shutdown_timeout)
544 a76f0c4a Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
545 a8083063 Iustin Pop
  return 0
546 a8083063 Iustin Pop
547 a8083063 Iustin Pop
548 decd5f45 Iustin Pop
def RenameInstance(opts, args):
549 4ab0b9e3 Guido Trotter
  """Rename an instance.
550 decd5f45 Iustin Pop

551 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
552 7232c04c Iustin Pop
  @type args: list
553 7232c04c Iustin Pop
  @param args: should contain two elements, the old and the
554 7232c04c Iustin Pop
      new instance names
555 7232c04c Iustin Pop
  @rtype: int
556 7232c04c Iustin Pop
  @return: the desired exit code
557 decd5f45 Iustin Pop

558 decd5f45 Iustin Pop
  """
559 90ed09b0 René Nussbaumer
  if not opts.name_check:
560 1b6dddc8 René Nussbaumer
    if not AskUser("As you disabled the check of the DNS entry, please verify"
561 1b6dddc8 René Nussbaumer
                   " that '%s' is a FQDN. Continue?" % args[1]):
562 1b6dddc8 René Nussbaumer
      return 1
563 1b6dddc8 René Nussbaumer
564 decd5f45 Iustin Pop
  op = opcodes.OpRenameInstance(instance_name=args[0],
565 decd5f45 Iustin Pop
                                new_name=args[1],
566 3fe11ba3 Manuel Franceschini
                                ip_check=opts.ip_check,
567 3fe11ba3 Manuel Franceschini
                                name_check=opts.name_check)
568 6a016df9 Michael Hanselmann
  result = SubmitOrSend(op, opts)
569 6a016df9 Michael Hanselmann
570 48418fea Iustin Pop
  if result:
571 48418fea Iustin Pop
    ToStdout("Instance '%s' renamed to '%s'", args[0], result)
572 6a016df9 Michael Hanselmann
573 decd5f45 Iustin Pop
  return 0
574 decd5f45 Iustin Pop
575 decd5f45 Iustin Pop
576 a8083063 Iustin Pop
def ActivateDisks(opts, args):
577 a8083063 Iustin Pop
  """Activate an instance's disks.
578 a8083063 Iustin Pop

579 a8083063 Iustin Pop
  This serves two purposes:
580 7232c04c Iustin Pop
    - it allows (as long as the instance is not running)
581 7232c04c Iustin Pop
      mounting the disks and modifying them from the node
582 a8083063 Iustin Pop
    - it repairs inactive secondary drbds
583 a8083063 Iustin Pop

584 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
585 7232c04c Iustin Pop
  @type args: list
586 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
587 7232c04c Iustin Pop
  @rtype: int
588 7232c04c Iustin Pop
  @return: the desired exit code
589 7232c04c Iustin Pop

590 a8083063 Iustin Pop
  """
591 a8083063 Iustin Pop
  instance_name = args[0]
592 83f5d475 Iustin Pop
  op = opcodes.OpInstanceActivateDisks(instance_name=instance_name,
593 b4ec07f8 Iustin Pop
                                       ignore_size=opts.ignore_size)
594 6340bb0a Iustin Pop
  disks_info = SubmitOrSend(op, opts)
595 a8083063 Iustin Pop
  for host, iname, nname in disks_info:
596 3a24c527 Iustin Pop
    ToStdout("%s:%s:%s", host, iname, nname)
597 a8083063 Iustin Pop
  return 0
598 a8083063 Iustin Pop
599 a8083063 Iustin Pop
600 a8083063 Iustin Pop
def DeactivateDisks(opts, args):
601 bd315bfa Iustin Pop
  """Deactivate an instance's disks.
602 a8083063 Iustin Pop

603 a8083063 Iustin Pop
  This function takes the instance name, looks for its primary node
604 a8083063 Iustin Pop
  and the tries to shutdown its block devices on that node.
605 a8083063 Iustin Pop

606 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
607 7232c04c Iustin Pop
  @type args: list
608 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
609 7232c04c Iustin Pop
  @rtype: int
610 7232c04c Iustin Pop
  @return: the desired exit code
611 7232c04c Iustin Pop

612 a8083063 Iustin Pop
  """
613 a8083063 Iustin Pop
  instance_name = args[0]
614 e176281f Iustin Pop
  op = opcodes.OpInstanceDeactivateDisks(instance_name=instance_name)
615 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
616 a8083063 Iustin Pop
  return 0
617 a8083063 Iustin Pop
618 a8083063 Iustin Pop
619 bd315bfa Iustin Pop
def RecreateDisks(opts, args):
620 bd315bfa Iustin Pop
  """Recreate an instance's disks.
621 bd315bfa Iustin Pop

622 bd315bfa Iustin Pop
  @param opts: the command line options selected by the user
623 bd315bfa Iustin Pop
  @type args: list
624 bd315bfa Iustin Pop
  @param args: should contain only one element, the instance name
625 bd315bfa Iustin Pop
  @rtype: int
626 bd315bfa Iustin Pop
  @return: the desired exit code
627 bd315bfa Iustin Pop

628 bd315bfa Iustin Pop
  """
629 bd315bfa Iustin Pop
  instance_name = args[0]
630 bd315bfa Iustin Pop
  if opts.disks:
631 bd315bfa Iustin Pop
    try:
632 bd315bfa Iustin Pop
      opts.disks = [int(v) for v in opts.disks.split(",")]
633 bd315bfa Iustin Pop
    except (ValueError, TypeError), err:
634 bd315bfa Iustin Pop
      ToStderr("Invalid disks value: %s" % str(err))
635 bd315bfa Iustin Pop
      return 1
636 bd315bfa Iustin Pop
  else:
637 bd315bfa Iustin Pop
    opts.disks = []
638 bd315bfa Iustin Pop
639 6b273e78 Iustin Pop
  op = opcodes.OpInstanceRecreateDisks(instance_name=instance_name,
640 bd315bfa Iustin Pop
                                       disks=opts.disks)
641 bd315bfa Iustin Pop
  SubmitOrSend(op, opts)
642 bd315bfa Iustin Pop
  return 0
643 bd315bfa Iustin Pop
644 bd315bfa Iustin Pop
645 c6e911bc Iustin Pop
def GrowDisk(opts, args):
646 7232c04c Iustin Pop
  """Grow an instance's disks.
647 c6e911bc Iustin Pop

648 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
649 7232c04c Iustin Pop
  @type args: list
650 7232c04c Iustin Pop
  @param args: should contain two elements, the instance name
651 7232c04c Iustin Pop
      whose disks we grow and the disk name, e.g. I{sda}
652 7232c04c Iustin Pop
  @rtype: int
653 7232c04c Iustin Pop
  @return: the desired exit code
654 c6e911bc Iustin Pop

655 c6e911bc Iustin Pop
  """
656 c6e911bc Iustin Pop
  instance = args[0]
657 c6e911bc Iustin Pop
  disk = args[1]
658 ad24e046 Iustin Pop
  try:
659 ad24e046 Iustin Pop
    disk = int(disk)
660 691744c4 Iustin Pop
  except (TypeError, ValueError), err:
661 debac808 Iustin Pop
    raise errors.OpPrereqError("Invalid disk index: %s" % str(err),
662 debac808 Iustin Pop
                               errors.ECODE_INVAL)
663 c6e911bc Iustin Pop
  amount = utils.ParseUnit(args[2])
664 60472d29 Iustin Pop
  op = opcodes.OpInstanceGrowDisk(instance_name=instance,
665 60472d29 Iustin Pop
                                  disk=disk, amount=amount,
666 60472d29 Iustin Pop
                                  wait_for_sync=opts.wait_for_sync)
667 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
668 c6e911bc Iustin Pop
  return 0
669 c6e911bc Iustin Pop
670 c6e911bc Iustin Pop
671 1c5945b6 Iustin Pop
def _StartupInstance(name, opts):
672 7232c04c Iustin Pop
  """Startup instances.
673 a8083063 Iustin Pop

674 1c5945b6 Iustin Pop
  This returns the opcode to start an instance, and its decorator will
675 1c5945b6 Iustin Pop
  wrap this into a loop starting all desired instances.
676 7232c04c Iustin Pop

677 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
678 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
679 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
680 a8083063 Iustin Pop

681 a8083063 Iustin Pop
  """
682 1c5945b6 Iustin Pop
  op = opcodes.OpStartupInstance(instance_name=name,
683 b44bd844 Michael Hanselmann
                                 force=opts.force,
684 b44bd844 Michael Hanselmann
                                 ignore_offline_nodes=opts.ignore_offline)
685 1c5945b6 Iustin Pop
  # do not add these parameters to the opcode unless they're defined
686 1c5945b6 Iustin Pop
  if opts.hvparams:
687 1c5945b6 Iustin Pop
    op.hvparams = opts.hvparams
688 1c5945b6 Iustin Pop
  if opts.beparams:
689 1c5945b6 Iustin Pop
    op.beparams = opts.beparams
690 1c5945b6 Iustin Pop
  return op
691 a8083063 Iustin Pop
692 7c0d6283 Michael Hanselmann
693 1c5945b6 Iustin Pop
def _RebootInstance(name, opts):
694 7232c04c Iustin Pop
  """Reboot instance(s).
695 7232c04c Iustin Pop

696 1c5945b6 Iustin Pop
  This returns the opcode to reboot an instance, and its decorator
697 1c5945b6 Iustin Pop
  will wrap this into a loop rebooting all desired instances.
698 579d4337 Alexander Schreiber

699 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
700 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
701 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
702 579d4337 Alexander Schreiber

703 579d4337 Alexander Schreiber
  """
704 90ab1a95 Iustin Pop
  return opcodes.OpInstanceReboot(instance_name=name,
705 579d4337 Alexander Schreiber
                                  reboot_type=opts.reboot_type,
706 17c3f802 Guido Trotter
                                  ignore_secondaries=opts.ignore_secondaries,
707 4d98c565 Guido Trotter
                                  shutdown_timeout=opts.shutdown_timeout)
708 a8083063 Iustin Pop
709 7c0d6283 Michael Hanselmann
710 1c5945b6 Iustin Pop
def _ShutdownInstance(name, opts):
711 a8083063 Iustin Pop
  """Shutdown an instance.
712 a8083063 Iustin Pop

713 1c5945b6 Iustin Pop
  This returns the opcode to shutdown an instance, and its decorator
714 1c5945b6 Iustin Pop
  will wrap this into a loop shutting down all desired instances.
715 1c5945b6 Iustin Pop

716 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
717 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
718 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
719 a8083063 Iustin Pop

720 a8083063 Iustin Pop
  """
721 6263189c Guido Trotter
  return opcodes.OpShutdownInstance(instance_name=name,
722 b44bd844 Michael Hanselmann
                                    timeout=opts.timeout,
723 b44bd844 Michael Hanselmann
                                    ignore_offline_nodes=opts.ignore_offline)
724 a8083063 Iustin Pop
725 a8083063 Iustin Pop
726 a8083063 Iustin Pop
def ReplaceDisks(opts, args):
727 a8083063 Iustin Pop
  """Replace the disks of an instance
728 a8083063 Iustin Pop

729 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
730 7232c04c Iustin Pop
  @type args: list
731 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
732 7232c04c Iustin Pop
  @rtype: int
733 7232c04c Iustin Pop
  @return: the desired exit code
734 a8083063 Iustin Pop

735 a8083063 Iustin Pop
  """
736 a14db5ff Iustin Pop
  new_2ndary = opts.dst_node
737 b6e82a65 Iustin Pop
  iallocator = opts.iallocator
738 a9e0c397 Iustin Pop
  if opts.disks is None:
739 54155f52 Iustin Pop
    disks = []
740 a9e0c397 Iustin Pop
  else:
741 54155f52 Iustin Pop
    try:
742 54155f52 Iustin Pop
      disks = [int(i) for i in opts.disks.split(",")]
743 691744c4 Iustin Pop
    except (TypeError, ValueError), err:
744 debac808 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err),
745 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
746 05d47e33 Michael Hanselmann
  cnt = [opts.on_primary, opts.on_secondary, opts.auto,
747 7e9366f7 Iustin Pop
         new_2ndary is not None, iallocator is not None].count(True)
748 7e9366f7 Iustin Pop
  if cnt != 1:
749 05d47e33 Michael Hanselmann
    raise errors.OpPrereqError("One and only one of the -p, -s, -a, -n and -i"
750 debac808 Iustin Pop
                               " options must be passed", errors.ECODE_INVAL)
751 7e9366f7 Iustin Pop
  elif opts.on_primary:
752 a9e0c397 Iustin Pop
    mode = constants.REPLACE_DISK_PRI
753 7e9366f7 Iustin Pop
  elif opts.on_secondary:
754 a9e0c397 Iustin Pop
    mode = constants.REPLACE_DISK_SEC
755 05d47e33 Michael Hanselmann
  elif opts.auto:
756 05d47e33 Michael Hanselmann
    mode = constants.REPLACE_DISK_AUTO
757 05d47e33 Michael Hanselmann
    if disks:
758 05d47e33 Michael Hanselmann
      raise errors.OpPrereqError("Cannot specify disks when using automatic"
759 debac808 Iustin Pop
                                 " mode", errors.ECODE_INVAL)
760 7e9366f7 Iustin Pop
  elif new_2ndary is not None or iallocator is not None:
761 7e9366f7 Iustin Pop
    # replace secondary
762 7e9366f7 Iustin Pop
    mode = constants.REPLACE_DISK_CHG
763 a9e0c397 Iustin Pop
764 a9e0c397 Iustin Pop
  op = opcodes.OpReplaceDisks(instance_name=args[0], disks=disks,
765 b6e82a65 Iustin Pop
                              remote_node=new_2ndary, mode=mode,
766 7ea7bcf6 Iustin Pop
                              iallocator=iallocator,
767 7ea7bcf6 Iustin Pop
                              early_release=opts.early_release)
768 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
769 a8083063 Iustin Pop
  return 0
770 a8083063 Iustin Pop
771 a8083063 Iustin Pop
772 a8083063 Iustin Pop
def FailoverInstance(opts, args):
773 a8083063 Iustin Pop
  """Failover an instance.
774 a8083063 Iustin Pop

775 a8083063 Iustin Pop
  The failover is done by shutting it down on its present node and
776 a8083063 Iustin Pop
  starting it on the secondary.
777 a8083063 Iustin Pop

778 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
779 7232c04c Iustin Pop
  @type args: list
780 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
781 7232c04c Iustin Pop
  @rtype: int
782 7232c04c Iustin Pop
  @return: the desired exit code
783 a8083063 Iustin Pop

784 a8083063 Iustin Pop
  """
785 a76f0c4a Iustin Pop
  cl = GetClient()
786 80de0e3f Iustin Pop
  instance_name = args[0]
787 80de0e3f Iustin Pop
  force = opts.force
788 a8083063 Iustin Pop
789 80de0e3f Iustin Pop
  if not force:
790 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
791 a76f0c4a Iustin Pop
792 80de0e3f Iustin Pop
    usertext = ("Failover will happen to image %s."
793 80de0e3f Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
794 80de0e3f Iustin Pop
                (instance_name,))
795 80de0e3f Iustin Pop
    if not AskUser(usertext):
796 80de0e3f Iustin Pop
      return 1
797 a8083063 Iustin Pop
798 019dbee1 Iustin Pop
  op = opcodes.OpInstanceFailover(instance_name=instance_name,
799 17c3f802 Guido Trotter
                                  ignore_consistency=opts.ignore_consistency,
800 4d98c565 Guido Trotter
                                  shutdown_timeout=opts.shutdown_timeout)
801 a76f0c4a Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
802 80de0e3f Iustin Pop
  return 0
803 a8083063 Iustin Pop
804 a8083063 Iustin Pop
805 53c776b5 Iustin Pop
def MigrateInstance(opts, args):
806 53c776b5 Iustin Pop
  """Migrate an instance.
807 53c776b5 Iustin Pop

808 53c776b5 Iustin Pop
  The migrate is done without shutdown.
809 53c776b5 Iustin Pop

810 2f907a8c Iustin Pop
  @param opts: the command line options selected by the user
811 2f907a8c Iustin Pop
  @type args: list
812 2f907a8c Iustin Pop
  @param args: should contain only one element, the instance name
813 2f907a8c Iustin Pop
  @rtype: int
814 2f907a8c Iustin Pop
  @return: the desired exit code
815 53c776b5 Iustin Pop

816 53c776b5 Iustin Pop
  """
817 a76f0c4a Iustin Pop
  cl = GetClient()
818 53c776b5 Iustin Pop
  instance_name = args[0]
819 53c776b5 Iustin Pop
  force = opts.force
820 53c776b5 Iustin Pop
821 53c776b5 Iustin Pop
  if not force:
822 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
823 a76f0c4a Iustin Pop
824 53c776b5 Iustin Pop
    if opts.cleanup:
825 53c776b5 Iustin Pop
      usertext = ("Instance %s will be recovered from a failed migration."
826 53c776b5 Iustin Pop
                  " Note that the migration procedure (including cleanup)" %
827 53c776b5 Iustin Pop
                  (instance_name,))
828 53c776b5 Iustin Pop
    else:
829 53c776b5 Iustin Pop
      usertext = ("Instance %s will be migrated. Note that migration" %
830 53c776b5 Iustin Pop
                  (instance_name,))
831 cf29cfb6 Iustin Pop
    usertext += (" might impact the instance if anything goes wrong"
832 cf29cfb6 Iustin Pop
                 " (e.g. due to bugs in the hypervisor). Continue?")
833 53c776b5 Iustin Pop
    if not AskUser(usertext):
834 53c776b5 Iustin Pop
      return 1
835 53c776b5 Iustin Pop
836 e71b9ef4 Iustin Pop
  # this should be removed once --non-live is deprecated
837 783a6c0b Iustin Pop
  if not opts.live and opts.migration_mode is not None:
838 e71b9ef4 Iustin Pop
    raise errors.OpPrereqError("Only one of the --non-live and "
839 783a6c0b Iustin Pop
                               "--migration-mode options can be passed",
840 e71b9ef4 Iustin Pop
                               errors.ECODE_INVAL)
841 e71b9ef4 Iustin Pop
  if not opts.live: # --non-live passed
842 8c35561f Iustin Pop
    mode = constants.HT_MIGRATION_NONLIVE
843 e71b9ef4 Iustin Pop
  else:
844 8c35561f Iustin Pop
    mode = opts.migration_mode
845 e71b9ef4 Iustin Pop
846 75c866c2 Iustin Pop
  op = opcodes.OpInstanceMigrate(instance_name=instance_name, mode=mode,
847 53c776b5 Iustin Pop
                                 cleanup=opts.cleanup)
848 400ca2f7 Iustin Pop
  SubmitOpCode(op, cl=cl, opts=opts)
849 53c776b5 Iustin Pop
  return 0
850 53c776b5 Iustin Pop
851 53c776b5 Iustin Pop
852 fbf5a861 Iustin Pop
def MoveInstance(opts, args):
853 fbf5a861 Iustin Pop
  """Move an instance.
854 fbf5a861 Iustin Pop

855 fbf5a861 Iustin Pop
  @param opts: the command line options selected by the user
856 fbf5a861 Iustin Pop
  @type args: list
857 fbf5a861 Iustin Pop
  @param args: should contain only one element, the instance name
858 fbf5a861 Iustin Pop
  @rtype: int
859 fbf5a861 Iustin Pop
  @return: the desired exit code
860 fbf5a861 Iustin Pop

861 fbf5a861 Iustin Pop
  """
862 fbf5a861 Iustin Pop
  cl = GetClient()
863 fbf5a861 Iustin Pop
  instance_name = args[0]
864 fbf5a861 Iustin Pop
  force = opts.force
865 fbf5a861 Iustin Pop
866 fbf5a861 Iustin Pop
  if not force:
867 fbf5a861 Iustin Pop
    usertext = ("Instance %s will be moved."
868 fbf5a861 Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
869 fbf5a861 Iustin Pop
                (instance_name,))
870 fbf5a861 Iustin Pop
    if not AskUser(usertext):
871 fbf5a861 Iustin Pop
      return 1
872 fbf5a861 Iustin Pop
873 0091b480 Iustin Pop
  op = opcodes.OpInstanceMove(instance_name=instance_name,
874 17c3f802 Guido Trotter
                              target_node=opts.node,
875 4d98c565 Guido Trotter
                              shutdown_timeout=opts.shutdown_timeout)
876 fbf5a861 Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
877 fbf5a861 Iustin Pop
  return 0
878 fbf5a861 Iustin Pop
879 fbf5a861 Iustin Pop
880 a8083063 Iustin Pop
def ConnectToInstanceConsole(opts, args):
881 a8083063 Iustin Pop
  """Connect to the console of an instance.
882 a8083063 Iustin Pop

883 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
884 7232c04c Iustin Pop
  @type args: list
885 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
886 7232c04c Iustin Pop
  @rtype: int
887 7232c04c Iustin Pop
  @return: the desired exit code
888 a8083063 Iustin Pop

889 a8083063 Iustin Pop
  """
890 a8083063 Iustin Pop
  instance_name = args[0]
891 a8083063 Iustin Pop
892 cc0dec7b Iustin Pop
  op = opcodes.OpInstanceConsole(instance_name=instance_name)
893 51c6e7b5 Michael Hanselmann
894 25ce3ec4 Michael Hanselmann
  cl = GetClient()
895 25ce3ec4 Michael Hanselmann
  try:
896 25ce3ec4 Michael Hanselmann
    cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
897 25ce3ec4 Michael Hanselmann
    console_data = SubmitOpCode(op, opts=opts, cl=cl)
898 25ce3ec4 Michael Hanselmann
  finally:
899 25ce3ec4 Michael Hanselmann
    # Ensure client connection is closed while external commands are run
900 25ce3ec4 Michael Hanselmann
    cl.Close()
901 25ce3ec4 Michael Hanselmann
902 25ce3ec4 Michael Hanselmann
  del cl
903 25ce3ec4 Michael Hanselmann
904 25ce3ec4 Michael Hanselmann
  return _DoConsole(objects.InstanceConsole.FromDict(console_data),
905 25ce3ec4 Michael Hanselmann
                    opts.show_command, cluster_name)
906 25ce3ec4 Michael Hanselmann
907 25ce3ec4 Michael Hanselmann
908 25ce3ec4 Michael Hanselmann
def _DoConsole(console, show_command, cluster_name, feedback_fn=ToStdout,
909 25ce3ec4 Michael Hanselmann
               _runcmd_fn=utils.RunCmd):
910 cc0dec7b Iustin Pop
  """Acts based on the result of L{opcodes.OpInstanceConsole}.
911 25ce3ec4 Michael Hanselmann

912 25ce3ec4 Michael Hanselmann
  @type console: L{objects.InstanceConsole}
913 25ce3ec4 Michael Hanselmann
  @param console: Console object
914 25ce3ec4 Michael Hanselmann
  @type show_command: bool
915 25ce3ec4 Michael Hanselmann
  @param show_command: Whether to just display commands
916 25ce3ec4 Michael Hanselmann
  @type cluster_name: string
917 25ce3ec4 Michael Hanselmann
  @param cluster_name: Cluster name as retrieved from master daemon
918 25ce3ec4 Michael Hanselmann

919 25ce3ec4 Michael Hanselmann
  """
920 25ce3ec4 Michael Hanselmann
  assert console.Validate()
921 25ce3ec4 Michael Hanselmann
922 25ce3ec4 Michael Hanselmann
  if console.kind == constants.CONS_MESSAGE:
923 25ce3ec4 Michael Hanselmann
    feedback_fn(console.message)
924 25ce3ec4 Michael Hanselmann
  elif console.kind == constants.CONS_VNC:
925 25ce3ec4 Michael Hanselmann
    feedback_fn("Instance %s has VNC listening on %s:%s (display %s),"
926 25ce3ec4 Michael Hanselmann
                " URL <vnc://%s:%s/>",
927 25ce3ec4 Michael Hanselmann
                console.instance, console.host, console.port,
928 25ce3ec4 Michael Hanselmann
                console.display, console.host, console.port)
929 25ce3ec4 Michael Hanselmann
  elif console.kind == constants.CONS_SSH:
930 25ce3ec4 Michael Hanselmann
    # Convert to string if not already one
931 25ce3ec4 Michael Hanselmann
    if isinstance(console.command, basestring):
932 25ce3ec4 Michael Hanselmann
      cmd = console.command
933 25ce3ec4 Michael Hanselmann
    else:
934 25ce3ec4 Michael Hanselmann
      cmd = utils.ShellQuoteArgs(console.command)
935 25ce3ec4 Michael Hanselmann
936 25ce3ec4 Michael Hanselmann
    srun = ssh.SshRunner(cluster_name=cluster_name)
937 25ce3ec4 Michael Hanselmann
    ssh_cmd = srun.BuildCmd(console.host, console.user, cmd,
938 25ce3ec4 Michael Hanselmann
                            batch=True, quiet=False, tty=True)
939 25ce3ec4 Michael Hanselmann
940 25ce3ec4 Michael Hanselmann
    if show_command:
941 25ce3ec4 Michael Hanselmann
      feedback_fn(utils.ShellQuoteArgs(ssh_cmd))
942 25ce3ec4 Michael Hanselmann
    else:
943 25ce3ec4 Michael Hanselmann
      result = _runcmd_fn(ssh_cmd, interactive=True)
944 25ce3ec4 Michael Hanselmann
      if result.failed:
945 25ce3ec4 Michael Hanselmann
        logging.error("Console command \"%s\" failed with reason '%s' and"
946 25ce3ec4 Michael Hanselmann
                      " output %r", result.cmd, result.fail_reason,
947 25ce3ec4 Michael Hanselmann
                      result.output)
948 25ce3ec4 Michael Hanselmann
        raise errors.OpExecError("Connection to console of instance %s failed,"
949 25ce3ec4 Michael Hanselmann
                                 " please check cluster configuration" %
950 25ce3ec4 Michael Hanselmann
                                 console.instance)
951 51c6e7b5 Michael Hanselmann
  else:
952 25ce3ec4 Michael Hanselmann
    raise errors.GenericError("Unknown console type '%s'" % console.kind)
953 678aa6d3 Michael Hanselmann
954 678aa6d3 Michael Hanselmann
  return constants.EXIT_SUCCESS
955 a8083063 Iustin Pop
956 a8083063 Iustin Pop
957 e2736e40 Guido Trotter
def _FormatLogicalID(dev_type, logical_id, roman):
958 19708787 Iustin Pop
  """Formats the logical_id of a disk.
959 19708787 Iustin Pop

960 19708787 Iustin Pop
  """
961 19708787 Iustin Pop
  if dev_type == constants.LD_DRBD8:
962 19708787 Iustin Pop
    node_a, node_b, port, minor_a, minor_b, key = logical_id
963 19708787 Iustin Pop
    data = [
964 e2736e40 Guido Trotter
      ("nodeA", "%s, minor=%s" % (node_a, compat.TryToRoman(minor_a,
965 e2736e40 Guido Trotter
                                                            convert=roman))),
966 e2736e40 Guido Trotter
      ("nodeB", "%s, minor=%s" % (node_b, compat.TryToRoman(minor_b,
967 e2736e40 Guido Trotter
                                                            convert=roman))),
968 e2736e40 Guido Trotter
      ("port", compat.TryToRoman(port, convert=roman)),
969 19708787 Iustin Pop
      ("auth key", key),
970 19708787 Iustin Pop
      ]
971 19708787 Iustin Pop
  elif dev_type == constants.LD_LV:
972 19708787 Iustin Pop
    vg_name, lv_name = logical_id
973 19708787 Iustin Pop
    data = ["%s/%s" % (vg_name, lv_name)]
974 19708787 Iustin Pop
  else:
975 19708787 Iustin Pop
    data = [str(logical_id)]
976 19708787 Iustin Pop
977 19708787 Iustin Pop
  return data
978 19708787 Iustin Pop
979 19708787 Iustin Pop
980 e2736e40 Guido Trotter
def _FormatBlockDevInfo(idx, top_level, dev, static, roman):
981 a8083063 Iustin Pop
  """Show block device information.
982 a8083063 Iustin Pop

983 7232c04c Iustin Pop
  This is only used by L{ShowInstanceConfig}, but it's too big to be
984 a8083063 Iustin Pop
  left for an inline definition.
985 a8083063 Iustin Pop

986 19708787 Iustin Pop
  @type idx: int
987 19708787 Iustin Pop
  @param idx: the index of the current disk
988 19708787 Iustin Pop
  @type top_level: boolean
989 19708787 Iustin Pop
  @param top_level: if this a top-level disk?
990 7232c04c Iustin Pop
  @type dev: dict
991 7232c04c Iustin Pop
  @param dev: dictionary with disk information
992 7232c04c Iustin Pop
  @type static: boolean
993 7232c04c Iustin Pop
  @param static: wheter the device information doesn't contain
994 7232c04c Iustin Pop
      runtime information but only static data
995 e2736e40 Guido Trotter
  @type roman: boolean
996 e2736e40 Guido Trotter
  @param roman: whether to try to use roman integers
997 19708787 Iustin Pop
  @return: a list of either strings, tuples or lists
998 19708787 Iustin Pop
      (which should be formatted at a higher indent level)
999 7232c04c Iustin Pop

1000 a8083063 Iustin Pop
  """
1001 19708787 Iustin Pop
  def helper(dtype, status):
1002 7232c04c Iustin Pop
    """Format one line for physical device status.
1003 7232c04c Iustin Pop

1004 7232c04c Iustin Pop
    @type dtype: str
1005 7232c04c Iustin Pop
    @param dtype: a constant from the L{constants.LDS_BLOCK} set
1006 7232c04c Iustin Pop
    @type status: tuple
1007 7232c04c Iustin Pop
    @param status: a tuple as returned from L{backend.FindBlockDevice}
1008 19708787 Iustin Pop
    @return: the string representing the status
1009 7232c04c Iustin Pop

1010 7232c04c Iustin Pop
    """
1011 a8083063 Iustin Pop
    if not status:
1012 19708787 Iustin Pop
      return "not active"
1013 19708787 Iustin Pop
    txt = ""
1014 f208978a Michael Hanselmann
    (path, major, minor, syncp, estt, degr, ldisk_status) = status
1015 19708787 Iustin Pop
    if major is None:
1016 19708787 Iustin Pop
      major_string = "N/A"
1017 a8083063 Iustin Pop
    else:
1018 e2736e40 Guido Trotter
      major_string = str(compat.TryToRoman(major, convert=roman))
1019 fd38ef95 Manuel Franceschini
1020 19708787 Iustin Pop
    if minor is None:
1021 19708787 Iustin Pop
      minor_string = "N/A"
1022 19708787 Iustin Pop
    else:
1023 e2736e40 Guido Trotter
      minor_string = str(compat.TryToRoman(minor, convert=roman))
1024 19708787 Iustin Pop
1025 19708787 Iustin Pop
    txt += ("%s (%s:%s)" % (path, major_string, minor_string))
1026 19708787 Iustin Pop
    if dtype in (constants.LD_DRBD8, ):
1027 19708787 Iustin Pop
      if syncp is not None:
1028 19708787 Iustin Pop
        sync_text = "*RECOVERING* %5.2f%%," % syncp
1029 19708787 Iustin Pop
        if estt:
1030 e2736e40 Guido Trotter
          sync_text += " ETA %ss" % compat.TryToRoman(estt, convert=roman)
1031 9db6dbce Iustin Pop
        else:
1032 19708787 Iustin Pop
          sync_text += " ETA unknown"
1033 19708787 Iustin Pop
      else:
1034 19708787 Iustin Pop
        sync_text = "in sync"
1035 19708787 Iustin Pop
      if degr:
1036 19708787 Iustin Pop
        degr_text = "*DEGRADED*"
1037 19708787 Iustin Pop
      else:
1038 19708787 Iustin Pop
        degr_text = "ok"
1039 f208978a Michael Hanselmann
      if ldisk_status == constants.LDS_FAULTY:
1040 19708787 Iustin Pop
        ldisk_text = " *MISSING DISK*"
1041 f208978a Michael Hanselmann
      elif ldisk_status == constants.LDS_UNKNOWN:
1042 f208978a Michael Hanselmann
        ldisk_text = " *UNCERTAIN STATE*"
1043 19708787 Iustin Pop
      else:
1044 19708787 Iustin Pop
        ldisk_text = ""
1045 19708787 Iustin Pop
      txt += (" %s, status %s%s" % (sync_text, degr_text, ldisk_text))
1046 19708787 Iustin Pop
    elif dtype == constants.LD_LV:
1047 f208978a Michael Hanselmann
      if ldisk_status == constants.LDS_FAULTY:
1048 19708787 Iustin Pop
        ldisk_text = " *FAILED* (failed drive?)"
1049 19708787 Iustin Pop
      else:
1050 19708787 Iustin Pop
        ldisk_text = ""
1051 19708787 Iustin Pop
      txt += ldisk_text
1052 19708787 Iustin Pop
    return txt
1053 19708787 Iustin Pop
1054 19708787 Iustin Pop
  # the header
1055 19708787 Iustin Pop
  if top_level:
1056 19708787 Iustin Pop
    if dev["iv_name"] is not None:
1057 19708787 Iustin Pop
      txt = dev["iv_name"]
1058 19708787 Iustin Pop
    else:
1059 e2736e40 Guido Trotter
      txt = "disk %s" % compat.TryToRoman(idx, convert=roman)
1060 a8083063 Iustin Pop
  else:
1061 e2736e40 Guido Trotter
    txt = "child %s" % compat.TryToRoman(idx, convert=roman)
1062 c98162a7 Iustin Pop
  if isinstance(dev["size"], int):
1063 c98162a7 Iustin Pop
    nice_size = utils.FormatUnit(dev["size"], "h")
1064 c98162a7 Iustin Pop
  else:
1065 c98162a7 Iustin Pop
    nice_size = dev["size"]
1066 c98162a7 Iustin Pop
  d1 = ["- %s: %s, size %s" % (txt, dev["dev_type"], nice_size)]
1067 19708787 Iustin Pop
  data = []
1068 19708787 Iustin Pop
  if top_level:
1069 19708787 Iustin Pop
    data.append(("access mode", dev["mode"]))
1070 a8083063 Iustin Pop
  if dev["logical_id"] is not None:
1071 19708787 Iustin Pop
    try:
1072 e2736e40 Guido Trotter
      l_id = _FormatLogicalID(dev["dev_type"], dev["logical_id"], roman)
1073 19708787 Iustin Pop
    except ValueError:
1074 19708787 Iustin Pop
      l_id = [str(dev["logical_id"])]
1075 19708787 Iustin Pop
    if len(l_id) == 1:
1076 19708787 Iustin Pop
      data.append(("logical_id", l_id[0]))
1077 19708787 Iustin Pop
    else:
1078 19708787 Iustin Pop
      data.extend(l_id)
1079 a8083063 Iustin Pop
  elif dev["physical_id"] is not None:
1080 19708787 Iustin Pop
    data.append("physical_id:")
1081 19708787 Iustin Pop
    data.append([dev["physical_id"]])
1082 57821cac Iustin Pop
  if not static:
1083 19708787 Iustin Pop
    data.append(("on primary", helper(dev["dev_type"], dev["pstatus"])))
1084 57821cac Iustin Pop
  if dev["sstatus"] and not static:
1085 19708787 Iustin Pop
    data.append(("on secondary", helper(dev["dev_type"], dev["sstatus"])))
1086 a8083063 Iustin Pop
1087 a8083063 Iustin Pop
  if dev["children"]:
1088 19708787 Iustin Pop
    data.append("child devices:")
1089 19708787 Iustin Pop
    for c_idx, child in enumerate(dev["children"]):
1090 e2736e40 Guido Trotter
      data.append(_FormatBlockDevInfo(c_idx, False, child, static, roman))
1091 19708787 Iustin Pop
  d1.append(data)
1092 19708787 Iustin Pop
  return d1
1093 a8083063 Iustin Pop
1094 a8083063 Iustin Pop
1095 19708787 Iustin Pop
def _FormatList(buf, data, indent_level):
1096 19708787 Iustin Pop
  """Formats a list of data at a given indent level.
1097 19708787 Iustin Pop

1098 19708787 Iustin Pop
  If the element of the list is:
1099 19708787 Iustin Pop
    - a string, it is simply formatted as is
1100 19708787 Iustin Pop
    - a tuple, it will be split into key, value and the all the
1101 19708787 Iustin Pop
      values in a list will be aligned all at the same start column
1102 19708787 Iustin Pop
    - a list, will be recursively formatted
1103 19708787 Iustin Pop

1104 19708787 Iustin Pop
  @type buf: StringIO
1105 19708787 Iustin Pop
  @param buf: the buffer into which we write the output
1106 19708787 Iustin Pop
  @param data: the list to format
1107 19708787 Iustin Pop
  @type indent_level: int
1108 19708787 Iustin Pop
  @param indent_level: the indent level to format at
1109 19708787 Iustin Pop

1110 19708787 Iustin Pop
  """
1111 19708787 Iustin Pop
  max_tlen = max([len(elem[0]) for elem in data
1112 19708787 Iustin Pop
                 if isinstance(elem, tuple)] or [0])
1113 19708787 Iustin Pop
  for elem in data:
1114 19708787 Iustin Pop
    if isinstance(elem, basestring):
1115 19708787 Iustin Pop
      buf.write("%*s%s\n" % (2*indent_level, "", elem))
1116 19708787 Iustin Pop
    elif isinstance(elem, tuple):
1117 19708787 Iustin Pop
      key, value = elem
1118 19708787 Iustin Pop
      spacer = "%*s" % (max_tlen - len(key), "")
1119 19708787 Iustin Pop
      buf.write("%*s%s:%s %s\n" % (2*indent_level, "", key, spacer, value))
1120 19708787 Iustin Pop
    elif isinstance(elem, list):
1121 19708787 Iustin Pop
      _FormatList(buf, elem, indent_level+1)
1122 19708787 Iustin Pop
1123 98825740 Michael Hanselmann
1124 a8083063 Iustin Pop
def ShowInstanceConfig(opts, args):
1125 a8083063 Iustin Pop
  """Compute instance run-time status.
1126 a8083063 Iustin Pop

1127 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1128 7232c04c Iustin Pop
  @type args: list
1129 7232c04c Iustin Pop
  @param args: either an empty list, and then we query all
1130 7232c04c Iustin Pop
      instances, or should contain a list of instance names
1131 7232c04c Iustin Pop
  @rtype: int
1132 7232c04c Iustin Pop
  @return: the desired exit code
1133 7232c04c Iustin Pop

1134 a8083063 Iustin Pop
  """
1135 220cde0b Guido Trotter
  if not args and not opts.show_all:
1136 220cde0b Guido Trotter
    ToStderr("No instance selected."
1137 220cde0b Guido Trotter
             " Please pass in --all if you want to query all instances.\n"
1138 220cde0b Guido Trotter
             "Note that this can take a long time on a big cluster.")
1139 220cde0b Guido Trotter
    return 1
1140 220cde0b Guido Trotter
  elif args and opts.show_all:
1141 220cde0b Guido Trotter
    ToStderr("Cannot use --all if you specify instance names.")
1142 220cde0b Guido Trotter
    return 1
1143 220cde0b Guido Trotter
1144 a8083063 Iustin Pop
  retcode = 0
1145 dc28c4e4 Iustin Pop
  op = opcodes.OpInstanceQueryData(instances=args, static=opts.static)
1146 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
1147 a8083063 Iustin Pop
  if not result:
1148 3a24c527 Iustin Pop
    ToStdout("No instances.")
1149 a8083063 Iustin Pop
    return 1
1150 a8083063 Iustin Pop
1151 a8083063 Iustin Pop
  buf = StringIO()
1152 a8083063 Iustin Pop
  retcode = 0
1153 a8083063 Iustin Pop
  for instance_name in result:
1154 a8083063 Iustin Pop
    instance = result[instance_name]
1155 a8083063 Iustin Pop
    buf.write("Instance name: %s\n" % instance["name"])
1156 033d58b0 Iustin Pop
    buf.write("UUID: %s\n" % instance["uuid"])
1157 e2736e40 Guido Trotter
    buf.write("Serial number: %s\n" %
1158 e2736e40 Guido Trotter
              compat.TryToRoman(instance["serial_no"],
1159 e2736e40 Guido Trotter
                                convert=opts.roman_integers))
1160 90f72445 Iustin Pop
    buf.write("Creation time: %s\n" % utils.FormatTime(instance["ctime"]))
1161 90f72445 Iustin Pop
    buf.write("Modification time: %s\n" % utils.FormatTime(instance["mtime"]))
1162 57821cac Iustin Pop
    buf.write("State: configured to be %s" % instance["config_state"])
1163 57821cac Iustin Pop
    if not opts.static:
1164 57821cac Iustin Pop
      buf.write(", actual state is %s" % instance["run_state"])
1165 57821cac Iustin Pop
    buf.write("\n")
1166 57821cac Iustin Pop
    ##buf.write("Considered for memory checks in cluster verify: %s\n" %
1167 57821cac Iustin Pop
    ##          instance["auto_balance"])
1168 a8083063 Iustin Pop
    buf.write("  Nodes:\n")
1169 a8083063 Iustin Pop
    buf.write("    - primary: %s\n" % instance["pnode"])
1170 1f864b60 Iustin Pop
    buf.write("    - secondaries: %s\n" % utils.CommaJoin(instance["snodes"]))
1171 a8083063 Iustin Pop
    buf.write("  Operating system: %s\n" % instance["os"])
1172 acd19189 René Nussbaumer
    FormatParameterDict(buf, instance["os_instance"], instance["os_actual"],
1173 acd19189 René Nussbaumer
                        level=2)
1174 a8340917 Iustin Pop
    if instance.has_key("network_port"):
1175 e2736e40 Guido Trotter
      buf.write("  Allocated network port: %s\n" %
1176 e2736e40 Guido Trotter
                compat.TryToRoman(instance["network_port"],
1177 e2736e40 Guido Trotter
                                  convert=opts.roman_integers))
1178 24838135 Iustin Pop
    buf.write("  Hypervisor: %s\n" % instance["hypervisor"])
1179 dfff41f8 Guido Trotter
1180 dfff41f8 Guido Trotter
    # custom VNC console information
1181 dfff41f8 Guido Trotter
    vnc_bind_address = instance["hv_actual"].get(constants.HV_VNC_BIND_ADDRESS,
1182 dfff41f8 Guido Trotter
                                                 None)
1183 dfff41f8 Guido Trotter
    if vnc_bind_address:
1184 dfff41f8 Guido Trotter
      port = instance["network_port"]
1185 dfff41f8 Guido Trotter
      display = int(port) - constants.VNC_BASE_PORT
1186 9769bb78 Manuel Franceschini
      if display > 0 and vnc_bind_address == constants.IP4_ADDRESS_ANY:
1187 dfff41f8 Guido Trotter
        vnc_console_port = "%s:%s (display %s)" % (instance["pnode"],
1188 dfff41f8 Guido Trotter
                                                   port,
1189 dfff41f8 Guido Trotter
                                                   display)
1190 8b312c1d Manuel Franceschini
      elif display > 0 and netutils.IP4Address.IsValid(vnc_bind_address):
1191 dfff41f8 Guido Trotter
        vnc_console_port = ("%s:%s (node %s) (display %s)" %
1192 dfff41f8 Guido Trotter
                             (vnc_bind_address, port,
1193 dfff41f8 Guido Trotter
                              instance["pnode"], display))
1194 a8340917 Iustin Pop
      else:
1195 dfff41f8 Guido Trotter
        # vnc bind address is a file
1196 dfff41f8 Guido Trotter
        vnc_console_port = "%s:%s" % (instance["pnode"],
1197 dfff41f8 Guido Trotter
                                      vnc_bind_address)
1198 24838135 Iustin Pop
      buf.write("    - console connection: vnc to %s\n" % vnc_console_port)
1199 24838135 Iustin Pop
1200 acd19189 René Nussbaumer
    FormatParameterDict(buf, instance["hv_instance"], instance["hv_actual"],
1201 acd19189 René Nussbaumer
                        level=2)
1202 a8083063 Iustin Pop
    buf.write("  Hardware:\n")
1203 e2736e40 Guido Trotter
    buf.write("    - VCPUs: %s\n" %
1204 e2736e40 Guido Trotter
              compat.TryToRoman(instance["be_actual"][constants.BE_VCPUS],
1205 e2736e40 Guido Trotter
                                convert=opts.roman_integers))
1206 e2736e40 Guido Trotter
    buf.write("    - memory: %sMiB\n" %
1207 e2736e40 Guido Trotter
              compat.TryToRoman(instance["be_actual"][constants.BE_MEMORY],
1208 e2736e40 Guido Trotter
                                convert=opts.roman_integers))
1209 d2acfe27 Iustin Pop
    buf.write("    - NICs:\n")
1210 14ea9302 Guido Trotter
    for idx, (ip, mac, mode, link) in enumerate(instance["nics"]):
1211 0b13832c Guido Trotter
      buf.write("      - nic/%d: MAC: %s, IP: %s, mode: %s, link: %s\n" %
1212 0b13832c Guido Trotter
                (idx, mac, ip, mode, link))
1213 b577dac4 Michael Hanselmann
    buf.write("  Disk template: %s\n" % instance["disk_template"])
1214 19708787 Iustin Pop
    buf.write("  Disks:\n")
1215 a8083063 Iustin Pop
1216 19708787 Iustin Pop
    for idx, device in enumerate(instance["disks"]):
1217 e2736e40 Guido Trotter
      _FormatList(buf, _FormatBlockDevInfo(idx, True, device, opts.static,
1218 e2736e40 Guido Trotter
                  opts.roman_integers), 2)
1219 a8083063 Iustin Pop
1220 3a24c527 Iustin Pop
  ToStdout(buf.getvalue().rstrip('\n'))
1221 a8083063 Iustin Pop
  return retcode
1222 a8083063 Iustin Pop
1223 a8083063 Iustin Pop
1224 7767bbf5 Manuel Franceschini
def SetInstanceParams(opts, args):
1225 a8083063 Iustin Pop
  """Modifies an instance.
1226 a8083063 Iustin Pop

1227 a8083063 Iustin Pop
  All parameters take effect only at the next restart of the instance.
1228 a8083063 Iustin Pop

1229 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1230 7232c04c Iustin Pop
  @type args: list
1231 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
1232 7232c04c Iustin Pop
  @rtype: int
1233 7232c04c Iustin Pop
  @return: the desired exit code
1234 a8083063 Iustin Pop

1235 a8083063 Iustin Pop
  """
1236 e29e9550 Iustin Pop
  if not (opts.nics or opts.disks or opts.disk_template or
1237 1052d622 Iustin Pop
          opts.hvparams or opts.beparams or opts.os or opts.osparams):
1238 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
1239 a8083063 Iustin Pop
    return 1
1240 a8083063 Iustin Pop
1241 467ae11e Guido Trotter
  for param in opts.beparams:
1242 e9d622bc Guido Trotter
    if isinstance(opts.beparams[param], basestring):
1243 e9d622bc Guido Trotter
      if opts.beparams[param].lower() == "default":
1244 e9d622bc Guido Trotter
        opts.beparams[param] = constants.VALUE_DEFAULT
1245 a5728081 Guido Trotter
1246 a5728081 Guido Trotter
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_TYPES,
1247 a5728081 Guido Trotter
                      allowed_values=[constants.VALUE_DEFAULT])
1248 467ae11e Guido Trotter
1249 48f212d7 Iustin Pop
  for param in opts.hvparams:
1250 48f212d7 Iustin Pop
    if isinstance(opts.hvparams[param], basestring):
1251 48f212d7 Iustin Pop
      if opts.hvparams[param].lower() == "default":
1252 48f212d7 Iustin Pop
        opts.hvparams[param] = constants.VALUE_DEFAULT
1253 a5728081 Guido Trotter
1254 48f212d7 Iustin Pop
  utils.ForceDictType(opts.hvparams, constants.HVS_PARAMETER_TYPES,
1255 a5728081 Guido Trotter
                      allowed_values=[constants.VALUE_DEFAULT])
1256 61be6ba4 Iustin Pop
1257 24991749 Iustin Pop
  for idx, (nic_op, nic_dict) in enumerate(opts.nics):
1258 24991749 Iustin Pop
    try:
1259 24991749 Iustin Pop
      nic_op = int(nic_op)
1260 24991749 Iustin Pop
      opts.nics[idx] = (nic_op, nic_dict)
1261 691744c4 Iustin Pop
    except (TypeError, ValueError):
1262 24991749 Iustin Pop
      pass
1263 24991749 Iustin Pop
1264 24991749 Iustin Pop
  for idx, (disk_op, disk_dict) in enumerate(opts.disks):
1265 24991749 Iustin Pop
    try:
1266 24991749 Iustin Pop
      disk_op = int(disk_op)
1267 24991749 Iustin Pop
      opts.disks[idx] = (disk_op, disk_dict)
1268 691744c4 Iustin Pop
    except (TypeError, ValueError):
1269 24991749 Iustin Pop
      pass
1270 24991749 Iustin Pop
    if disk_op == constants.DDM_ADD:
1271 24991749 Iustin Pop
      if 'size' not in disk_dict:
1272 debac808 Iustin Pop
        raise errors.OpPrereqError("Missing required parameter 'size'",
1273 debac808 Iustin Pop
                                   errors.ECODE_INVAL)
1274 24991749 Iustin Pop
      disk_dict['size'] = utils.ParseUnit(disk_dict['size'])
1275 24991749 Iustin Pop
1276 e29e9550 Iustin Pop
  if (opts.disk_template and
1277 e29e9550 Iustin Pop
      opts.disk_template in constants.DTS_NET_MIRROR and
1278 e29e9550 Iustin Pop
      not opts.node):
1279 e29e9550 Iustin Pop
    ToStderr("Changing the disk template to a mirrored one requires"
1280 e29e9550 Iustin Pop
             " specifying a secondary node")
1281 e29e9550 Iustin Pop
    return 1
1282 e29e9550 Iustin Pop
1283 338e51e8 Iustin Pop
  op = opcodes.OpSetInstanceParams(instance_name=args[0],
1284 24991749 Iustin Pop
                                   nics=opts.nics,
1285 24991749 Iustin Pop
                                   disks=opts.disks,
1286 e29e9550 Iustin Pop
                                   disk_template=opts.disk_template,
1287 e29e9550 Iustin Pop
                                   remote_node=opts.node,
1288 48f212d7 Iustin Pop
                                   hvparams=opts.hvparams,
1289 338e51e8 Iustin Pop
                                   beparams=opts.beparams,
1290 96b39bcc Iustin Pop
                                   os_name=opts.os,
1291 1052d622 Iustin Pop
                                   osparams=opts.osparams,
1292 96b39bcc Iustin Pop
                                   force_variant=opts.force_variant,
1293 4300c4b6 Guido Trotter
                                   force=opts.force)
1294 31a853d2 Iustin Pop
1295 6340bb0a Iustin Pop
  # even if here we process the result, we allow submit only
1296 6340bb0a Iustin Pop
  result = SubmitOrSend(op, opts)
1297 a8083063 Iustin Pop
1298 a8083063 Iustin Pop
  if result:
1299 3a24c527 Iustin Pop
    ToStdout("Modified instance %s", args[0])
1300 a8083063 Iustin Pop
    for param, data in result:
1301 3a24c527 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
1302 e29e9550 Iustin Pop
    ToStdout("Please don't forget that most parameters take effect"
1303 3a24c527 Iustin Pop
             " only at the next start of the instance.")
1304 a8083063 Iustin Pop
  return 0
1305 a8083063 Iustin Pop
1306 a8083063 Iustin Pop
1307 312ac745 Iustin Pop
# multi-instance selection options
1308 c38c44ad Michael Hanselmann
m_force_multi = cli_option("--force-multiple", dest="force_multi",
1309 c38c44ad Michael Hanselmann
                           help="Do not ask for confirmation when more than"
1310 c38c44ad Michael Hanselmann
                           " one instance is affected",
1311 c38c44ad Michael Hanselmann
                           action="store_true", default=False)
1312 804a1e8e Iustin Pop
1313 c38c44ad Michael Hanselmann
m_pri_node_opt = cli_option("--primary", dest="multi_mode",
1314 c38c44ad Michael Hanselmann
                            help="Filter by nodes (primary only)",
1315 c38c44ad Michael Hanselmann
                            const=_SHUTDOWN_NODES_PRI, action="store_const")
1316 312ac745 Iustin Pop
1317 c38c44ad Michael Hanselmann
m_sec_node_opt = cli_option("--secondary", dest="multi_mode",
1318 c38c44ad Michael Hanselmann
                            help="Filter by nodes (secondary only)",
1319 c38c44ad Michael Hanselmann
                            const=_SHUTDOWN_NODES_SEC, action="store_const")
1320 312ac745 Iustin Pop
1321 c38c44ad Michael Hanselmann
m_node_opt = cli_option("--node", dest="multi_mode",
1322 c38c44ad Michael Hanselmann
                        help="Filter by nodes (primary and secondary)",
1323 c38c44ad Michael Hanselmann
                        const=_SHUTDOWN_NODES_BOTH, action="store_const")
1324 312ac745 Iustin Pop
1325 c38c44ad Michael Hanselmann
m_clust_opt = cli_option("--all", dest="multi_mode",
1326 c38c44ad Michael Hanselmann
                         help="Select all instances in the cluster",
1327 c38c44ad Michael Hanselmann
                         const=_SHUTDOWN_CLUSTER, action="store_const")
1328 312ac745 Iustin Pop
1329 c38c44ad Michael Hanselmann
m_inst_opt = cli_option("--instance", dest="multi_mode",
1330 c38c44ad Michael Hanselmann
                        help="Filter by instance name [default]",
1331 c38c44ad Michael Hanselmann
                        const=_SHUTDOWN_INSTANCES, action="store_const")
1332 312ac745 Iustin Pop
1333 39dfd93e René Nussbaumer
m_node_tags_opt = cli_option("--node-tags", dest="multi_mode",
1334 39dfd93e René Nussbaumer
                             help="Filter by node tag",
1335 39dfd93e René Nussbaumer
                             const=_SHUTDOWN_NODES_BOTH_BY_TAGS,
1336 39dfd93e René Nussbaumer
                             action="store_const")
1337 39dfd93e René Nussbaumer
1338 39dfd93e René Nussbaumer
m_pri_node_tags_opt = cli_option("--pri-node-tags", dest="multi_mode",
1339 39dfd93e René Nussbaumer
                                 help="Filter by primary node tag",
1340 39dfd93e René Nussbaumer
                                 const=_SHUTDOWN_NODES_PRI_BY_TAGS,
1341 39dfd93e René Nussbaumer
                                 action="store_const")
1342 39dfd93e René Nussbaumer
1343 39dfd93e René Nussbaumer
m_sec_node_tags_opt = cli_option("--sec-node-tags", dest="multi_mode",
1344 39dfd93e René Nussbaumer
                                 help="Filter by secondary node tag",
1345 39dfd93e René Nussbaumer
                                 const=_SHUTDOWN_NODES_SEC_BY_TAGS,
1346 39dfd93e René Nussbaumer
                                 action="store_const")
1347 39dfd93e René Nussbaumer
1348 39dfd93e René Nussbaumer
m_inst_tags_opt = cli_option("--tags", dest="multi_mode",
1349 39dfd93e René Nussbaumer
                             help="Filter by instance tag",
1350 39dfd93e René Nussbaumer
                             const=_SHUTDOWN_INSTANCES_BY_TAGS,
1351 39dfd93e René Nussbaumer
                             action="store_const")
1352 312ac745 Iustin Pop
1353 a8083063 Iustin Pop
# this is defined separately due to readability only
1354 a8083063 Iustin Pop
add_opts = [
1355 064c21f8 Iustin Pop
  NOSTART_OPT,
1356 064c21f8 Iustin Pop
  OS_OPT,
1357 06073e85 Guido Trotter
  FORCE_VARIANT_OPT,
1358 25a8792c Iustin Pop
  NO_INSTALL_OPT,
1359 a8083063 Iustin Pop
  ]
1360 a8083063 Iustin Pop
1361 a8083063 Iustin Pop
commands = {
1362 6ea815cf Iustin Pop
  'add': (
1363 eb28ecf6 Guido Trotter
    AddInstance, [ArgHost(min=1, max=1)], COMMON_CREATE_OPTS + add_opts,
1364 6ea815cf Iustin Pop
    "[...] -t disk-type -n node[:secondary-node] -o os-type <name>",
1365 6ea815cf Iustin Pop
    "Creates and adds a new instance to the cluster"),
1366 6ea815cf Iustin Pop
  'batch-create': (
1367 aa06f8c6 Michael Hanselmann
    BatchCreate, [ArgFile(min=1, max=1)], [DRY_RUN_OPT, PRIORITY_OPT],
1368 6ea815cf Iustin Pop
    "<instances.json>",
1369 6ea815cf Iustin Pop
    "Create a bunch of instances based on specs in the file."),
1370 6ea815cf Iustin Pop
  'console': (
1371 6ea815cf Iustin Pop
    ConnectToInstanceConsole, ARGS_ONE_INSTANCE,
1372 aa06f8c6 Michael Hanselmann
    [SHOWCMD_OPT, PRIORITY_OPT],
1373 6ea815cf Iustin Pop
    "[--show-cmd] <instance>", "Opens a console on the specified instance"),
1374 6ea815cf Iustin Pop
  'failover': (
1375 6ea815cf Iustin Pop
    FailoverInstance, ARGS_ONE_INSTANCE,
1376 db5a8a2d Iustin Pop
    [FORCE_OPT, IGNORE_CONSIST_OPT, SUBMIT_OPT, SHUTDOWN_TIMEOUT_OPT,
1377 aa06f8c6 Michael Hanselmann
     DRY_RUN_OPT, PRIORITY_OPT],
1378 6ea815cf Iustin Pop
    "[-f] <instance>", "Stops the instance and starts it on the backup node,"
1379 6ea815cf Iustin Pop
    " using the remote mirror (only for instances of type drbd)"),
1380 6ea815cf Iustin Pop
  'migrate': (
1381 6ea815cf Iustin Pop
    MigrateInstance, ARGS_ONE_INSTANCE,
1382 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, NONLIVE_OPT, MIGRATION_MODE_OPT, CLEANUP_OPT, DRY_RUN_OPT,
1383 aa06f8c6 Michael Hanselmann
     PRIORITY_OPT],
1384 6ea815cf Iustin Pop
    "[-f] <instance>", "Migrate instance to its secondary node"
1385 6ea815cf Iustin Pop
    " (only for instances of type drbd)"),
1386 6ea815cf Iustin Pop
  'move': (
1387 6ea815cf Iustin Pop
    MoveInstance, ARGS_ONE_INSTANCE,
1388 db5a8a2d Iustin Pop
    [FORCE_OPT, SUBMIT_OPT, SINGLE_NODE_OPT, SHUTDOWN_TIMEOUT_OPT,
1389 aa06f8c6 Michael Hanselmann
     DRY_RUN_OPT, PRIORITY_OPT],
1390 6ea815cf Iustin Pop
    "[-f] <instance>", "Move instance to an arbitrary node"
1391 6ea815cf Iustin Pop
    " (only for instances of type file and lv)"),
1392 6ea815cf Iustin Pop
  'info': (
1393 6ea815cf Iustin Pop
    ShowInstanceConfig, ARGS_MANY_INSTANCES,
1394 aa06f8c6 Michael Hanselmann
    [STATIC_OPT, ALL_OPT, ROMAN_OPT, PRIORITY_OPT],
1395 6ea815cf Iustin Pop
    "[-s] {--all | <instance>...}",
1396 6ea815cf Iustin Pop
    "Show information on the specified instance(s)"),
1397 6ea815cf Iustin Pop
  'list': (
1398 6ea815cf Iustin Pop
    ListInstances, ARGS_MANY_INSTANCES,
1399 b82c5ff5 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
1400 6ea815cf Iustin Pop
    "[<instance>...]",
1401 b82c5ff5 Michael Hanselmann
    "Lists the instances and their status. The available fields can be shown"
1402 b82c5ff5 Michael Hanselmann
    " using the \"list-fields\" command (see the man page for details)."
1403 b82c5ff5 Michael Hanselmann
    " The default field list is (in order): %s." %
1404 b82c5ff5 Michael Hanselmann
    utils.CommaJoin(_LIST_DEF_FIELDS),
1405 6ea815cf Iustin Pop
    ),
1406 b82c5ff5 Michael Hanselmann
  "list-fields": (
1407 b82c5ff5 Michael Hanselmann
    ListInstanceFields, [ArgUnknown()],
1408 b82c5ff5 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT],
1409 b82c5ff5 Michael Hanselmann
    "[fields...]",
1410 b82c5ff5 Michael Hanselmann
    "Lists all available fields for instances"),
1411 6ea815cf Iustin Pop
  'reinstall': (
1412 3e54ace7 Iustin Pop
    ReinstallInstance, [ArgInstance()],
1413 06073e85 Guido Trotter
    [FORCE_OPT, OS_OPT, FORCE_VARIANT_OPT, m_force_multi, m_node_opt,
1414 39dfd93e René Nussbaumer
     m_pri_node_opt, m_sec_node_opt, m_clust_opt, m_inst_opt, m_node_tags_opt,
1415 39dfd93e René Nussbaumer
     m_pri_node_tags_opt, m_sec_node_tags_opt, m_inst_tags_opt, SELECT_OS_OPT,
1416 8d8c4eff Michael Hanselmann
     SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT, OSPARAMS_OPT],
1417 6ea815cf Iustin Pop
    "[-f] <instance>", "Reinstall a stopped instance"),
1418 6ea815cf Iustin Pop
  'remove': (
1419 6ea815cf Iustin Pop
    RemoveInstance, ARGS_ONE_INSTANCE,
1420 db5a8a2d Iustin Pop
    [FORCE_OPT, SHUTDOWN_TIMEOUT_OPT, IGNORE_FAILURES_OPT, SUBMIT_OPT,
1421 aa06f8c6 Michael Hanselmann
     DRY_RUN_OPT, PRIORITY_OPT],
1422 6ea815cf Iustin Pop
    "[-f] <instance>", "Shuts down the instance and removes it"),
1423 6ea815cf Iustin Pop
  'rename': (
1424 6ea815cf Iustin Pop
    RenameInstance,
1425 6ea815cf Iustin Pop
    [ArgInstance(min=1, max=1), ArgHost(min=1, max=1)],
1426 aa06f8c6 Michael Hanselmann
    [NOIPCHECK_OPT, NONAMECHECK_OPT, SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1427 6ea815cf Iustin Pop
    "<instance> <new_name>", "Rename the instance"),
1428 6ea815cf Iustin Pop
  'replace-disks': (
1429 6ea815cf Iustin Pop
    ReplaceDisks, ARGS_ONE_INSTANCE,
1430 7ea7bcf6 Iustin Pop
    [AUTO_REPLACE_OPT, DISKIDX_OPT, IALLOCATOR_OPT, EARLY_RELEASE_OPT,
1431 db5a8a2d Iustin Pop
     NEW_SECONDARY_OPT, ON_PRIMARY_OPT, ON_SECONDARY_OPT, SUBMIT_OPT,
1432 aa06f8c6 Michael Hanselmann
     DRY_RUN_OPT, PRIORITY_OPT],
1433 6ea815cf Iustin Pop
    "[-s|-p|-n NODE|-I NAME] <instance>",
1434 6ea815cf Iustin Pop
    "Replaces all disks for the instance"),
1435 6ea815cf Iustin Pop
  'modify': (
1436 6ea815cf Iustin Pop
    SetInstanceParams, ARGS_ONE_INSTANCE,
1437 e29e9550 Iustin Pop
    [BACKEND_OPT, DISK_OPT, FORCE_OPT, HVOPTS_OPT, NET_OPT, SUBMIT_OPT,
1438 1052d622 Iustin Pop
     DISK_TEMPLATE_OPT, SINGLE_NODE_OPT, OS_OPT, FORCE_VARIANT_OPT,
1439 aa06f8c6 Michael Hanselmann
     OSPARAMS_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1440 6ea815cf Iustin Pop
    "<instance>", "Alters the parameters of an instance"),
1441 6ea815cf Iustin Pop
  'shutdown': (
1442 1c5945b6 Iustin Pop
    GenericManyOps("shutdown", _ShutdownInstance), [ArgInstance()],
1443 064c21f8 Iustin Pop
    [m_node_opt, m_pri_node_opt, m_sec_node_opt, m_clust_opt,
1444 39dfd93e René Nussbaumer
     m_node_tags_opt, m_pri_node_tags_opt, m_sec_node_tags_opt,
1445 db5a8a2d Iustin Pop
     m_inst_tags_opt, m_inst_opt, m_force_multi, TIMEOUT_OPT, SUBMIT_OPT,
1446 b44bd844 Michael Hanselmann
     DRY_RUN_OPT, PRIORITY_OPT, IGNORE_OFFLINE_OPT],
1447 6ea815cf Iustin Pop
    "<instance>", "Stops an instance"),
1448 6ea815cf Iustin Pop
  'startup': (
1449 1c5945b6 Iustin Pop
    GenericManyOps("startup", _StartupInstance), [ArgInstance()],
1450 39dfd93e René Nussbaumer
    [FORCE_OPT, m_force_multi, m_node_opt, m_pri_node_opt, m_sec_node_opt,
1451 39dfd93e René Nussbaumer
     m_node_tags_opt, m_pri_node_tags_opt, m_sec_node_tags_opt,
1452 39dfd93e René Nussbaumer
     m_inst_tags_opt, m_clust_opt, m_inst_opt, SUBMIT_OPT, HVOPTS_OPT,
1453 b44bd844 Michael Hanselmann
     BACKEND_OPT, DRY_RUN_OPT, PRIORITY_OPT, IGNORE_OFFLINE_OPT],
1454 6ea815cf Iustin Pop
    "<instance>", "Starts an instance"),
1455 6ea815cf Iustin Pop
  'reboot': (
1456 1c5945b6 Iustin Pop
    GenericManyOps("reboot", _RebootInstance), [ArgInstance()],
1457 064c21f8 Iustin Pop
    [m_force_multi, REBOOT_TYPE_OPT, IGNORE_SECONDARIES_OPT, m_node_opt,
1458 17c3f802 Guido Trotter
     m_pri_node_opt, m_sec_node_opt, m_clust_opt, m_inst_opt, SUBMIT_OPT,
1459 39dfd93e René Nussbaumer
     m_node_tags_opt, m_pri_node_tags_opt, m_sec_node_tags_opt,
1460 aa06f8c6 Michael Hanselmann
     m_inst_tags_opt, SHUTDOWN_TIMEOUT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1461 6ea815cf Iustin Pop
    "<instance>", "Reboots an instance"),
1462 6ea815cf Iustin Pop
  'activate-disks': (
1463 db5a8a2d Iustin Pop
    ActivateDisks, ARGS_ONE_INSTANCE,
1464 aa06f8c6 Michael Hanselmann
    [SUBMIT_OPT, IGNORE_SIZE_OPT, PRIORITY_OPT],
1465 6ea815cf Iustin Pop
    "<instance>", "Activate an instance's disks"),
1466 6ea815cf Iustin Pop
  'deactivate-disks': (
1467 aa06f8c6 Michael Hanselmann
    DeactivateDisks, ARGS_ONE_INSTANCE,
1468 aa06f8c6 Michael Hanselmann
    [SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1469 6ea815cf Iustin Pop
    "<instance>", "Deactivate an instance's disks"),
1470 6ea815cf Iustin Pop
  'recreate-disks': (
1471 aa06f8c6 Michael Hanselmann
    RecreateDisks, ARGS_ONE_INSTANCE,
1472 aa06f8c6 Michael Hanselmann
    [SUBMIT_OPT, DISKIDX_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1473 6ea815cf Iustin Pop
    "<instance>", "Recreate an instance's disks"),
1474 6ea815cf Iustin Pop
  'grow-disk': (
1475 6ea815cf Iustin Pop
    GrowDisk,
1476 6ea815cf Iustin Pop
    [ArgInstance(min=1, max=1), ArgUnknown(min=1, max=1),
1477 6ea815cf Iustin Pop
     ArgUnknown(min=1, max=1)],
1478 aa06f8c6 Michael Hanselmann
    [SUBMIT_OPT, NWSYNC_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1479 6ea815cf Iustin Pop
    "<instance> <disk> <size>", "Grow an instance's disk"),
1480 6ea815cf Iustin Pop
  'list-tags': (
1481 aa06f8c6 Michael Hanselmann
    ListTags, ARGS_ONE_INSTANCE, [PRIORITY_OPT],
1482 6ea815cf Iustin Pop
    "<instance_name>", "List the tags of the given instance"),
1483 6ea815cf Iustin Pop
  'add-tags': (
1484 6ea815cf Iustin Pop
    AddTags, [ArgInstance(min=1, max=1), ArgUnknown()],
1485 aa06f8c6 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT],
1486 6ea815cf Iustin Pop
    "<instance_name> tag...", "Add tags to the given instance"),
1487 6ea815cf Iustin Pop
  'remove-tags': (
1488 6ea815cf Iustin Pop
    RemoveTags, [ArgInstance(min=1, max=1), ArgUnknown()],
1489 aa06f8c6 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT],
1490 6ea815cf Iustin Pop
    "<instance_name> tag...", "Remove tags from given instance"),
1491 a8083063 Iustin Pop
  }
1492 a8083063 Iustin Pop
1493 7232c04c Iustin Pop
#: dictionary with aliases for commands
1494 dbfd89dd Guido Trotter
aliases = {
1495 536fda25 Guido Trotter
  'start': 'startup',
1496 536fda25 Guido Trotter
  'stop': 'shutdown',
1497 dbfd89dd Guido Trotter
  }
1498 dbfd89dd Guido Trotter
1499 a8005e17 Michael Hanselmann
1500 e792102d Michael Hanselmann
def Main():
1501 e792102d Michael Hanselmann
  return GenericMain(commands, aliases=aliases,
1502 e792102d Michael Hanselmann
                     override={"tag_type": constants.TAG_INSTANCE})