Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_instance.py @ f86426f5

History | View | Annotate | Download (51.4 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 7232c04c Iustin Pop
#: default list of options for L{ListInstances}
61 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
62 e69d05fd Iustin Pop
  "name", "hypervisor", "os", "pnode", "status", "oper_ram",
63 48c4dfa8 Iustin Pop
  ]
64 48c4dfa8 Iustin Pop
65 bdb7d4e8 Michael Hanselmann
66 479636a3 Iustin Pop
def _ExpandMultiNames(mode, names, client=None):
67 312ac745 Iustin Pop
  """Expand the given names using the passed mode.
68 312ac745 Iustin Pop

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

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

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

148 a76f0c4a Iustin Pop
  This function will raise an OpPrereqError in case they don't
149 a76f0c4a Iustin Pop
  exist. Otherwise it will exit cleanly.
150 a76f0c4a Iustin Pop

151 f2fd87d7 Iustin Pop
  @type client: L{ganeti.luxi.Client}
152 a76f0c4a Iustin Pop
  @param client: the client to use for the query
153 a76f0c4a Iustin Pop
  @type names: list
154 a76f0c4a Iustin Pop
  @param names: the list of instance names to query
155 a76f0c4a Iustin Pop
  @raise errors.OpPrereqError: in case any instance is missing
156 a76f0c4a Iustin Pop

157 a76f0c4a Iustin Pop
  """
158 f2af0bec Iustin Pop
  # TODO: change LUInstanceQuery to that it actually returns None
159 a76f0c4a Iustin Pop
  # instead of raising an exception, or devise a better mechanism
160 ec79568d Iustin Pop
  result = client.QueryInstances(names, ["name"], False)
161 a76f0c4a Iustin Pop
  for orig_name, row in zip(names, result):
162 a76f0c4a Iustin Pop
    if row[0] is None:
163 debac808 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' does not exist" % orig_name,
164 debac808 Iustin Pop
                                 errors.ECODE_NOENT)
165 a76f0c4a Iustin Pop
166 a76f0c4a Iustin Pop
167 1c5945b6 Iustin Pop
def GenericManyOps(operation, fn):
168 1c5945b6 Iustin Pop
  """Generic multi-instance operations.
169 1c5945b6 Iustin Pop

170 1c5945b6 Iustin Pop
  The will return a wrapper that processes the options and arguments
171 1c5945b6 Iustin Pop
  given, and uses the passed function to build the opcode needed for
172 1c5945b6 Iustin Pop
  the specific operation. Thus all the generic loop/confirmation code
173 1c5945b6 Iustin Pop
  is abstracted into this function.
174 1c5945b6 Iustin Pop

175 1c5945b6 Iustin Pop
  """
176 1c5945b6 Iustin Pop
  def realfn(opts, args):
177 1c5945b6 Iustin Pop
    if opts.multi_mode is None:
178 1c5945b6 Iustin Pop
      opts.multi_mode = _SHUTDOWN_INSTANCES
179 1c5945b6 Iustin Pop
    cl = GetClient()
180 1c5945b6 Iustin Pop
    inames = _ExpandMultiNames(opts.multi_mode, args, client=cl)
181 1c5945b6 Iustin Pop
    if not inames:
182 1c5945b6 Iustin Pop
      raise errors.OpPrereqError("Selection filter does not match"
183 debac808 Iustin Pop
                                 " any instances", errors.ECODE_INVAL)
184 1c5945b6 Iustin Pop
    multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
185 1c5945b6 Iustin Pop
    if not (opts.force_multi or not multi_on
186 25bd815c René Nussbaumer
            or ConfirmOperation(inames, "instances", operation)):
187 1c5945b6 Iustin Pop
      return 1
188 cb573a31 Iustin Pop
    jex = JobExecutor(verbose=multi_on, cl=cl, opts=opts)
189 1c5945b6 Iustin Pop
    for name in inames:
190 1c5945b6 Iustin Pop
      op = fn(name, opts)
191 1c5945b6 Iustin Pop
      jex.QueueJob(name, op)
192 b4e68848 Iustin Pop
    results = jex.WaitOrShow(not opts.submit_only)
193 b4e68848 Iustin Pop
    rcode = compat.all(row[0] for row in results)
194 b4e68848 Iustin Pop
    return int(not rcode)
195 1c5945b6 Iustin Pop
  return realfn
196 1c5945b6 Iustin Pop
197 1c5945b6 Iustin Pop
198 a8083063 Iustin Pop
def ListInstances(opts, args):
199 f5abe9bd Oleksiy Mishchenko
  """List instances and their properties.
200 a8083063 Iustin Pop

201 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
202 7232c04c Iustin Pop
  @type args: list
203 7232c04c Iustin Pop
  @param args: should be an empty list
204 7232c04c Iustin Pop
  @rtype: int
205 7232c04c Iustin Pop
  @return: the desired exit code
206 7232c04c Iustin Pop

207 a8083063 Iustin Pop
  """
208 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
209 a8083063 Iustin Pop
210 b82c5ff5 Michael Hanselmann
  fmtoverride = dict.fromkeys(["tags", "disk.sizes", "nic.macs", "nic.ips",
211 b82c5ff5 Michael Hanselmann
                               "nic.modes", "nic.links", "nic.bridges",
212 b82c5ff5 Michael Hanselmann
                               "snodes"],
213 b82c5ff5 Michael Hanselmann
                              (lambda value: ",".join(str(item)
214 b82c5ff5 Michael Hanselmann
                                                      for item in value),
215 b82c5ff5 Michael Hanselmann
                               False))
216 a8083063 Iustin Pop
217 b82c5ff5 Michael Hanselmann
  return GenericList(constants.QR_INSTANCE, selected_fields, args, opts.units,
218 b82c5ff5 Michael Hanselmann
                     opts.separator, not opts.no_headers,
219 b82c5ff5 Michael Hanselmann
                     format_override=fmtoverride)
220 b82c5ff5 Michael Hanselmann
221 b82c5ff5 Michael Hanselmann
222 b82c5ff5 Michael Hanselmann
def ListInstanceFields(opts, args):
223 b82c5ff5 Michael Hanselmann
  """List instance fields.
224 b82c5ff5 Michael Hanselmann

225 b82c5ff5 Michael Hanselmann
  @param opts: the command line options selected by the user
226 b82c5ff5 Michael Hanselmann
  @type args: list
227 b82c5ff5 Michael Hanselmann
  @param args: fields to list, or empty for all
228 b82c5ff5 Michael Hanselmann
  @rtype: int
229 b82c5ff5 Michael Hanselmann
  @return: the desired exit code
230 b82c5ff5 Michael Hanselmann

231 b82c5ff5 Michael Hanselmann
  """
232 b82c5ff5 Michael Hanselmann
  return GenericListFields(constants.QR_INSTANCE, args, opts.separator,
233 b82c5ff5 Michael Hanselmann
                           not opts.no_headers)
234 a8083063 Iustin Pop
235 a8083063 Iustin Pop
236 a8083063 Iustin Pop
def AddInstance(opts, args):
237 a8083063 Iustin Pop
  """Add an instance to the cluster.
238 a8083063 Iustin Pop

239 d77490c5 Iustin Pop
  This is just a wrapper over GenericInstanceCreate.
240 a8083063 Iustin Pop

241 a8083063 Iustin Pop
  """
242 d77490c5 Iustin Pop
  return GenericInstanceCreate(constants.INSTANCE_CREATE, opts, args)
243 a8083063 Iustin Pop
244 a8083063 Iustin Pop
245 0d0e9090 René Nussbaumer
def BatchCreate(opts, args):
246 7232c04c Iustin Pop
  """Create instances using a definition file.
247 7232c04c Iustin Pop

248 7232c04c Iustin Pop
  This function reads a json file with instances defined
249 7232c04c Iustin Pop
  in the form::
250 7232c04c Iustin Pop

251 7232c04c Iustin Pop
    {"instance-name":{
252 9939547b Iustin Pop
      "disk_size": [20480],
253 7232c04c Iustin Pop
      "template": "drbd",
254 7232c04c Iustin Pop
      "backend": {
255 7232c04c Iustin Pop
        "memory": 512,
256 7232c04c Iustin Pop
        "vcpus": 1 },
257 9939547b Iustin Pop
      "os": "debootstrap",
258 7232c04c Iustin Pop
      "primary_node": "firstnode",
259 7232c04c Iustin Pop
      "secondary_node": "secondnode",
260 7232c04c Iustin Pop
      "iallocator": "dumb"}
261 7232c04c Iustin Pop
    }
262 7232c04c Iustin Pop

263 7232c04c Iustin Pop
  Note that I{primary_node} and I{secondary_node} have precedence over
264 7232c04c Iustin Pop
  I{iallocator}.
265 7232c04c Iustin Pop

266 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
267 7232c04c Iustin Pop
  @type args: list
268 7232c04c Iustin Pop
  @param args: should contain one element, the json filename
269 7232c04c Iustin Pop
  @rtype: int
270 7232c04c Iustin Pop
  @return: the desired exit code
271 0d0e9090 René Nussbaumer

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

402 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
403 7232c04c Iustin Pop
  @type args: list
404 7232c04c Iustin Pop
  @param args: should contain only one element, the name of the
405 7232c04c Iustin Pop
      instance to be reinstalled
406 7232c04c Iustin Pop
  @rtype: int
407 7232c04c Iustin Pop
  @return: the desired exit code
408 fe7b0351 Michael Hanselmann

409 fe7b0351 Michael Hanselmann
  """
410 55efe6da Iustin Pop
  # first, compute the desired name list
411 55efe6da Iustin Pop
  if opts.multi_mode is None:
412 55efe6da Iustin Pop
    opts.multi_mode = _SHUTDOWN_INSTANCES
413 55efe6da Iustin Pop
414 55efe6da Iustin Pop
  inames = _ExpandMultiNames(opts.multi_mode, args)
415 55efe6da Iustin Pop
  if not inames:
416 debac808 Iustin Pop
    raise errors.OpPrereqError("Selection filter does not match any instances",
417 debac808 Iustin Pop
                               errors.ECODE_INVAL)
418 fe7b0351 Michael Hanselmann
419 55efe6da Iustin Pop
  # second, if requested, ask for an OS
420 20e23543 Alexander Schreiber
  if opts.select_os is True:
421 da2d02e7 Iustin Pop
    op = opcodes.OpOsDiagnose(output_fields=["name", "variants"], names=[])
422 400ca2f7 Iustin Pop
    result = SubmitOpCode(op, opts=opts)
423 20e23543 Alexander Schreiber
424 20e23543 Alexander Schreiber
    if not result:
425 3a24c527 Iustin Pop
      ToStdout("Can't get the OS list")
426 20e23543 Alexander Schreiber
      return 1
427 20e23543 Alexander Schreiber
428 3a24c527 Iustin Pop
    ToStdout("Available OS templates:")
429 20e23543 Alexander Schreiber
    number = 0
430 20e23543 Alexander Schreiber
    choices = []
431 d22dfef7 Iustin Pop
    for (name, variants) in result:
432 d22dfef7 Iustin Pop
      for entry in CalculateOSNames(name, variants):
433 d22dfef7 Iustin Pop
        ToStdout("%3s: %s", number, entry)
434 d22dfef7 Iustin Pop
        choices.append(("%s" % number, entry, entry))
435 d22dfef7 Iustin Pop
        number += 1
436 20e23543 Alexander Schreiber
437 20e23543 Alexander Schreiber
    choices.append(('x', 'exit', 'Exit gnt-instance reinstall'))
438 949bdabe Iustin Pop
    selected = AskUser("Enter OS template number (or x to abort):",
439 20e23543 Alexander Schreiber
                       choices)
440 20e23543 Alexander Schreiber
441 20e23543 Alexander Schreiber
    if selected == 'exit':
442 55efe6da Iustin Pop
      ToStderr("User aborted reinstall, exiting")
443 20e23543 Alexander Schreiber
      return 1
444 20e23543 Alexander Schreiber
445 2f79bd34 Iustin Pop
    os_name = selected
446 f86426f5 Iustin Pop
    os_msg = "change the OS to '%s'" % selected
447 20e23543 Alexander Schreiber
  else:
448 2f79bd34 Iustin Pop
    os_name = opts.os
449 f86426f5 Iustin Pop
    if opts.os is not None:
450 f86426f5 Iustin Pop
      os_msg = "change the OS to '%s'" % os_name
451 f86426f5 Iustin Pop
    else:
452 f86426f5 Iustin Pop
      os_msg = "keep the same OS"
453 20e23543 Alexander Schreiber
454 297ddce9 Iustin Pop
  # third, get confirmation: multi-reinstall requires --force-multi,
455 297ddce9 Iustin Pop
  # single-reinstall either --force or --force-multi (--force-multi is
456 297ddce9 Iustin Pop
  # a stronger --force)
457 55efe6da Iustin Pop
  multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
458 55efe6da Iustin Pop
  if multi_on:
459 f86426f5 Iustin Pop
    warn_msg = ("Note: this will remove *all* data for the"
460 f86426f5 Iustin Pop
                " below instances! It will %s.\n" % os_msg)
461 297ddce9 Iustin Pop
    if not (opts.force_multi or
462 25bd815c René Nussbaumer
            ConfirmOperation(inames, "instances", "reinstall", extra=warn_msg)):
463 fe7b0351 Michael Hanselmann
      return 1
464 55efe6da Iustin Pop
  else:
465 297ddce9 Iustin Pop
    if not (opts.force or opts.force_multi):
466 f86426f5 Iustin Pop
      usertext = ("This will reinstall the instance '%s' (and %s) which"
467 f86426f5 Iustin Pop
                  " removes all data. Continue?") % (inames[0], os_msg)
468 55efe6da Iustin Pop
      if not AskUser(usertext):
469 55efe6da Iustin Pop
        return 1
470 55efe6da Iustin Pop
471 cb573a31 Iustin Pop
  jex = JobExecutor(verbose=multi_on, opts=opts)
472 55efe6da Iustin Pop
  for instance_name in inames:
473 5073fd8f Iustin Pop
    op = opcodes.OpInstanceReinstall(instance_name=instance_name,
474 06073e85 Guido Trotter
                                     os_type=os_name,
475 8d8c4eff Michael Hanselmann
                                     force_variant=opts.force_variant,
476 8d8c4eff Michael Hanselmann
                                     osparams=opts.osparams)
477 55efe6da Iustin Pop
    jex.QueueJob(instance_name, op)
478 fe7b0351 Michael Hanselmann
479 55efe6da Iustin Pop
  jex.WaitOrShow(not opts.submit_only)
480 fe7b0351 Michael Hanselmann
  return 0
481 fe7b0351 Michael Hanselmann
482 fe7b0351 Michael Hanselmann
483 a8083063 Iustin Pop
def RemoveInstance(opts, args):
484 a8083063 Iustin Pop
  """Remove an instance.
485 a8083063 Iustin Pop

486 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
487 7232c04c Iustin Pop
  @type args: list
488 7232c04c Iustin Pop
  @param args: should contain only one element, the name of
489 7232c04c Iustin Pop
      the instance to be removed
490 7232c04c Iustin Pop
  @rtype: int
491 7232c04c Iustin Pop
  @return: the desired exit code
492 a8083063 Iustin Pop

493 a8083063 Iustin Pop
  """
494 a8083063 Iustin Pop
  instance_name = args[0]
495 a8083063 Iustin Pop
  force = opts.force
496 a76f0c4a Iustin Pop
  cl = GetClient()
497 a8083063 Iustin Pop
498 a8083063 Iustin Pop
  if not force:
499 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
500 a76f0c4a Iustin Pop
501 a8083063 Iustin Pop
    usertext = ("This will remove the volumes of the instance %s"
502 a8083063 Iustin Pop
                " (including mirrors), thus removing all the data"
503 a8083063 Iustin Pop
                " of the instance. Continue?") % instance_name
504 47988778 Iustin Pop
    if not AskUser(usertext):
505 a8083063 Iustin Pop
      return 1
506 a8083063 Iustin Pop
507 3cd2d4b1 Iustin Pop
  op = opcodes.OpInstanceRemove(instance_name=instance_name,
508 17c3f802 Guido Trotter
                                ignore_failures=opts.ignore_failures,
509 4d98c565 Guido Trotter
                                shutdown_timeout=opts.shutdown_timeout)
510 a76f0c4a Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
511 a8083063 Iustin Pop
  return 0
512 a8083063 Iustin Pop
513 a8083063 Iustin Pop
514 decd5f45 Iustin Pop
def RenameInstance(opts, args):
515 4ab0b9e3 Guido Trotter
  """Rename an instance.
516 decd5f45 Iustin Pop

517 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
518 7232c04c Iustin Pop
  @type args: list
519 7232c04c Iustin Pop
  @param args: should contain two elements, the old and the
520 7232c04c Iustin Pop
      new instance names
521 7232c04c Iustin Pop
  @rtype: int
522 7232c04c Iustin Pop
  @return: the desired exit code
523 decd5f45 Iustin Pop

524 decd5f45 Iustin Pop
  """
525 90ed09b0 René Nussbaumer
  if not opts.name_check:
526 1b6dddc8 René Nussbaumer
    if not AskUser("As you disabled the check of the DNS entry, please verify"
527 1b6dddc8 René Nussbaumer
                   " that '%s' is a FQDN. Continue?" % args[1]):
528 1b6dddc8 René Nussbaumer
      return 1
529 1b6dddc8 René Nussbaumer
530 5659e2e2 Iustin Pop
  op = opcodes.OpInstanceRename(instance_name=args[0],
531 decd5f45 Iustin Pop
                                new_name=args[1],
532 3fe11ba3 Manuel Franceschini
                                ip_check=opts.ip_check,
533 3fe11ba3 Manuel Franceschini
                                name_check=opts.name_check)
534 6a016df9 Michael Hanselmann
  result = SubmitOrSend(op, opts)
535 6a016df9 Michael Hanselmann
536 48418fea Iustin Pop
  if result:
537 48418fea Iustin Pop
    ToStdout("Instance '%s' renamed to '%s'", args[0], result)
538 6a016df9 Michael Hanselmann
539 decd5f45 Iustin Pop
  return 0
540 decd5f45 Iustin Pop
541 decd5f45 Iustin Pop
542 a8083063 Iustin Pop
def ActivateDisks(opts, args):
543 a8083063 Iustin Pop
  """Activate an instance's disks.
544 a8083063 Iustin Pop

545 a8083063 Iustin Pop
  This serves two purposes:
546 7232c04c Iustin Pop
    - it allows (as long as the instance is not running)
547 7232c04c Iustin Pop
      mounting the disks and modifying them from the node
548 a8083063 Iustin Pop
    - it repairs inactive secondary drbds
549 a8083063 Iustin Pop

550 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
551 7232c04c Iustin Pop
  @type args: list
552 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
553 7232c04c Iustin Pop
  @rtype: int
554 7232c04c Iustin Pop
  @return: the desired exit code
555 7232c04c Iustin Pop

556 a8083063 Iustin Pop
  """
557 a8083063 Iustin Pop
  instance_name = args[0]
558 83f5d475 Iustin Pop
  op = opcodes.OpInstanceActivateDisks(instance_name=instance_name,
559 b4ec07f8 Iustin Pop
                                       ignore_size=opts.ignore_size)
560 6340bb0a Iustin Pop
  disks_info = SubmitOrSend(op, opts)
561 a8083063 Iustin Pop
  for host, iname, nname in disks_info:
562 3a24c527 Iustin Pop
    ToStdout("%s:%s:%s", host, iname, nname)
563 a8083063 Iustin Pop
  return 0
564 a8083063 Iustin Pop
565 a8083063 Iustin Pop
566 a8083063 Iustin Pop
def DeactivateDisks(opts, args):
567 bd315bfa Iustin Pop
  """Deactivate an instance's disks.
568 a8083063 Iustin Pop

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

572 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
573 7232c04c Iustin Pop
  @type args: list
574 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
575 7232c04c Iustin Pop
  @rtype: int
576 7232c04c Iustin Pop
  @return: the desired exit code
577 7232c04c Iustin Pop

578 a8083063 Iustin Pop
  """
579 a8083063 Iustin Pop
  instance_name = args[0]
580 c9c41373 Iustin Pop
  op = opcodes.OpInstanceDeactivateDisks(instance_name=instance_name,
581 c9c41373 Iustin Pop
                                         force=opts.force)
582 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
583 a8083063 Iustin Pop
  return 0
584 a8083063 Iustin Pop
585 a8083063 Iustin Pop
586 bd315bfa Iustin Pop
def RecreateDisks(opts, args):
587 bd315bfa Iustin Pop
  """Recreate an instance's disks.
588 bd315bfa Iustin Pop

589 bd315bfa Iustin Pop
  @param opts: the command line options selected by the user
590 bd315bfa Iustin Pop
  @type args: list
591 bd315bfa Iustin Pop
  @param args: should contain only one element, the instance name
592 bd315bfa Iustin Pop
  @rtype: int
593 bd315bfa Iustin Pop
  @return: the desired exit code
594 bd315bfa Iustin Pop

595 bd315bfa Iustin Pop
  """
596 bd315bfa Iustin Pop
  instance_name = args[0]
597 bd315bfa Iustin Pop
  if opts.disks:
598 bd315bfa Iustin Pop
    try:
599 bd315bfa Iustin Pop
      opts.disks = [int(v) for v in opts.disks.split(",")]
600 bd315bfa Iustin Pop
    except (ValueError, TypeError), err:
601 bd315bfa Iustin Pop
      ToStderr("Invalid disks value: %s" % str(err))
602 bd315bfa Iustin Pop
      return 1
603 bd315bfa Iustin Pop
  else:
604 bd315bfa Iustin Pop
    opts.disks = []
605 bd315bfa Iustin Pop
606 6b273e78 Iustin Pop
  op = opcodes.OpInstanceRecreateDisks(instance_name=instance_name,
607 bd315bfa Iustin Pop
                                       disks=opts.disks)
608 bd315bfa Iustin Pop
  SubmitOrSend(op, opts)
609 bd315bfa Iustin Pop
  return 0
610 bd315bfa Iustin Pop
611 bd315bfa Iustin Pop
612 c6e911bc Iustin Pop
def GrowDisk(opts, args):
613 7232c04c Iustin Pop
  """Grow an instance's disks.
614 c6e911bc Iustin Pop

615 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
616 7232c04c Iustin Pop
  @type args: list
617 7232c04c Iustin Pop
  @param args: should contain two elements, the instance name
618 7232c04c Iustin Pop
      whose disks we grow and the disk name, e.g. I{sda}
619 7232c04c Iustin Pop
  @rtype: int
620 7232c04c Iustin Pop
  @return: the desired exit code
621 c6e911bc Iustin Pop

622 c6e911bc Iustin Pop
  """
623 c6e911bc Iustin Pop
  instance = args[0]
624 c6e911bc Iustin Pop
  disk = args[1]
625 ad24e046 Iustin Pop
  try:
626 ad24e046 Iustin Pop
    disk = int(disk)
627 691744c4 Iustin Pop
  except (TypeError, ValueError), err:
628 debac808 Iustin Pop
    raise errors.OpPrereqError("Invalid disk index: %s" % str(err),
629 debac808 Iustin Pop
                               errors.ECODE_INVAL)
630 c6e911bc Iustin Pop
  amount = utils.ParseUnit(args[2])
631 60472d29 Iustin Pop
  op = opcodes.OpInstanceGrowDisk(instance_name=instance,
632 60472d29 Iustin Pop
                                  disk=disk, amount=amount,
633 60472d29 Iustin Pop
                                  wait_for_sync=opts.wait_for_sync)
634 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
635 c6e911bc Iustin Pop
  return 0
636 c6e911bc Iustin Pop
637 c6e911bc Iustin Pop
638 1c5945b6 Iustin Pop
def _StartupInstance(name, opts):
639 7232c04c Iustin Pop
  """Startup instances.
640 a8083063 Iustin Pop

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

644 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
645 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
646 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
647 a8083063 Iustin Pop

648 a8083063 Iustin Pop
  """
649 c873d91c Iustin Pop
  op = opcodes.OpInstanceStartup(instance_name=name,
650 b44bd844 Michael Hanselmann
                                 force=opts.force,
651 b44bd844 Michael Hanselmann
                                 ignore_offline_nodes=opts.ignore_offline)
652 1c5945b6 Iustin Pop
  # do not add these parameters to the opcode unless they're defined
653 1c5945b6 Iustin Pop
  if opts.hvparams:
654 1c5945b6 Iustin Pop
    op.hvparams = opts.hvparams
655 1c5945b6 Iustin Pop
  if opts.beparams:
656 1c5945b6 Iustin Pop
    op.beparams = opts.beparams
657 1c5945b6 Iustin Pop
  return op
658 a8083063 Iustin Pop
659 7c0d6283 Michael Hanselmann
660 1c5945b6 Iustin Pop
def _RebootInstance(name, opts):
661 7232c04c Iustin Pop
  """Reboot instance(s).
662 7232c04c Iustin Pop

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

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

670 579d4337 Alexander Schreiber
  """
671 90ab1a95 Iustin Pop
  return opcodes.OpInstanceReboot(instance_name=name,
672 579d4337 Alexander Schreiber
                                  reboot_type=opts.reboot_type,
673 17c3f802 Guido Trotter
                                  ignore_secondaries=opts.ignore_secondaries,
674 4d98c565 Guido Trotter
                                  shutdown_timeout=opts.shutdown_timeout)
675 a8083063 Iustin Pop
676 7c0d6283 Michael Hanselmann
677 1c5945b6 Iustin Pop
def _ShutdownInstance(name, opts):
678 a8083063 Iustin Pop
  """Shutdown an instance.
679 a8083063 Iustin Pop

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

683 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
684 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
685 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
686 a8083063 Iustin Pop

687 a8083063 Iustin Pop
  """
688 ee3e37a7 Iustin Pop
  return opcodes.OpInstanceShutdown(instance_name=name,
689 b44bd844 Michael Hanselmann
                                    timeout=opts.timeout,
690 b44bd844 Michael Hanselmann
                                    ignore_offline_nodes=opts.ignore_offline)
691 a8083063 Iustin Pop
692 a8083063 Iustin Pop
693 a8083063 Iustin Pop
def ReplaceDisks(opts, args):
694 a8083063 Iustin Pop
  """Replace the disks of an instance
695 a8083063 Iustin Pop

696 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
697 7232c04c Iustin Pop
  @type args: list
698 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
699 7232c04c Iustin Pop
  @rtype: int
700 7232c04c Iustin Pop
  @return: the desired exit code
701 a8083063 Iustin Pop

702 a8083063 Iustin Pop
  """
703 a14db5ff Iustin Pop
  new_2ndary = opts.dst_node
704 b6e82a65 Iustin Pop
  iallocator = opts.iallocator
705 a9e0c397 Iustin Pop
  if opts.disks is None:
706 54155f52 Iustin Pop
    disks = []
707 a9e0c397 Iustin Pop
  else:
708 54155f52 Iustin Pop
    try:
709 54155f52 Iustin Pop
      disks = [int(i) for i in opts.disks.split(",")]
710 691744c4 Iustin Pop
    except (TypeError, ValueError), err:
711 debac808 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err),
712 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
713 05d47e33 Michael Hanselmann
  cnt = [opts.on_primary, opts.on_secondary, opts.auto,
714 7e9366f7 Iustin Pop
         new_2ndary is not None, iallocator is not None].count(True)
715 7e9366f7 Iustin Pop
  if cnt != 1:
716 05d47e33 Michael Hanselmann
    raise errors.OpPrereqError("One and only one of the -p, -s, -a, -n and -i"
717 debac808 Iustin Pop
                               " options must be passed", errors.ECODE_INVAL)
718 7e9366f7 Iustin Pop
  elif opts.on_primary:
719 a9e0c397 Iustin Pop
    mode = constants.REPLACE_DISK_PRI
720 7e9366f7 Iustin Pop
  elif opts.on_secondary:
721 a9e0c397 Iustin Pop
    mode = constants.REPLACE_DISK_SEC
722 05d47e33 Michael Hanselmann
  elif opts.auto:
723 05d47e33 Michael Hanselmann
    mode = constants.REPLACE_DISK_AUTO
724 05d47e33 Michael Hanselmann
    if disks:
725 05d47e33 Michael Hanselmann
      raise errors.OpPrereqError("Cannot specify disks when using automatic"
726 debac808 Iustin Pop
                                 " mode", errors.ECODE_INVAL)
727 7e9366f7 Iustin Pop
  elif new_2ndary is not None or iallocator is not None:
728 7e9366f7 Iustin Pop
    # replace secondary
729 7e9366f7 Iustin Pop
    mode = constants.REPLACE_DISK_CHG
730 a9e0c397 Iustin Pop
731 668f755d Iustin Pop
  op = opcodes.OpInstanceReplaceDisks(instance_name=args[0], disks=disks,
732 668f755d Iustin Pop
                                      remote_node=new_2ndary, mode=mode,
733 668f755d Iustin Pop
                                      iallocator=iallocator,
734 668f755d Iustin Pop
                                      early_release=opts.early_release)
735 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
736 a8083063 Iustin Pop
  return 0
737 a8083063 Iustin Pop
738 a8083063 Iustin Pop
739 a8083063 Iustin Pop
def FailoverInstance(opts, args):
740 a8083063 Iustin Pop
  """Failover an instance.
741 a8083063 Iustin Pop

742 a8083063 Iustin Pop
  The failover is done by shutting it down on its present node and
743 a8083063 Iustin Pop
  starting it on the secondary.
744 a8083063 Iustin Pop

745 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
746 7232c04c Iustin Pop
  @type args: list
747 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
748 7232c04c Iustin Pop
  @rtype: int
749 7232c04c Iustin Pop
  @return: the desired exit code
750 a8083063 Iustin Pop

751 a8083063 Iustin Pop
  """
752 a76f0c4a Iustin Pop
  cl = GetClient()
753 80de0e3f Iustin Pop
  instance_name = args[0]
754 80de0e3f Iustin Pop
  force = opts.force
755 a8083063 Iustin Pop
756 80de0e3f Iustin Pop
  if not force:
757 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
758 a76f0c4a Iustin Pop
759 80de0e3f Iustin Pop
    usertext = ("Failover will happen to image %s."
760 80de0e3f Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
761 80de0e3f Iustin Pop
                (instance_name,))
762 80de0e3f Iustin Pop
    if not AskUser(usertext):
763 80de0e3f Iustin Pop
      return 1
764 a8083063 Iustin Pop
765 019dbee1 Iustin Pop
  op = opcodes.OpInstanceFailover(instance_name=instance_name,
766 17c3f802 Guido Trotter
                                  ignore_consistency=opts.ignore_consistency,
767 4d98c565 Guido Trotter
                                  shutdown_timeout=opts.shutdown_timeout)
768 a76f0c4a Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
769 80de0e3f Iustin Pop
  return 0
770 a8083063 Iustin Pop
771 a8083063 Iustin Pop
772 53c776b5 Iustin Pop
def MigrateInstance(opts, args):
773 53c776b5 Iustin Pop
  """Migrate an instance.
774 53c776b5 Iustin Pop

775 53c776b5 Iustin Pop
  The migrate is done without shutdown.
776 53c776b5 Iustin Pop

777 2f907a8c Iustin Pop
  @param opts: the command line options selected by the user
778 2f907a8c Iustin Pop
  @type args: list
779 2f907a8c Iustin Pop
  @param args: should contain only one element, the instance name
780 2f907a8c Iustin Pop
  @rtype: int
781 2f907a8c Iustin Pop
  @return: the desired exit code
782 53c776b5 Iustin Pop

783 53c776b5 Iustin Pop
  """
784 a76f0c4a Iustin Pop
  cl = GetClient()
785 53c776b5 Iustin Pop
  instance_name = args[0]
786 53c776b5 Iustin Pop
  force = opts.force
787 53c776b5 Iustin Pop
788 53c776b5 Iustin Pop
  if not force:
789 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
790 a76f0c4a Iustin Pop
791 53c776b5 Iustin Pop
    if opts.cleanup:
792 53c776b5 Iustin Pop
      usertext = ("Instance %s will be recovered from a failed migration."
793 53c776b5 Iustin Pop
                  " Note that the migration procedure (including cleanup)" %
794 53c776b5 Iustin Pop
                  (instance_name,))
795 53c776b5 Iustin Pop
    else:
796 53c776b5 Iustin Pop
      usertext = ("Instance %s will be migrated. Note that migration" %
797 53c776b5 Iustin Pop
                  (instance_name,))
798 cf29cfb6 Iustin Pop
    usertext += (" might impact the instance if anything goes wrong"
799 cf29cfb6 Iustin Pop
                 " (e.g. due to bugs in the hypervisor). Continue?")
800 53c776b5 Iustin Pop
    if not AskUser(usertext):
801 53c776b5 Iustin Pop
      return 1
802 53c776b5 Iustin Pop
803 e71b9ef4 Iustin Pop
  # this should be removed once --non-live is deprecated
804 783a6c0b Iustin Pop
  if not opts.live and opts.migration_mode is not None:
805 e71b9ef4 Iustin Pop
    raise errors.OpPrereqError("Only one of the --non-live and "
806 783a6c0b Iustin Pop
                               "--migration-mode options can be passed",
807 e71b9ef4 Iustin Pop
                               errors.ECODE_INVAL)
808 e71b9ef4 Iustin Pop
  if not opts.live: # --non-live passed
809 8c35561f Iustin Pop
    mode = constants.HT_MIGRATION_NONLIVE
810 e71b9ef4 Iustin Pop
  else:
811 8c35561f Iustin Pop
    mode = opts.migration_mode
812 e71b9ef4 Iustin Pop
813 75c866c2 Iustin Pop
  op = opcodes.OpInstanceMigrate(instance_name=instance_name, mode=mode,
814 53c776b5 Iustin Pop
                                 cleanup=opts.cleanup)
815 400ca2f7 Iustin Pop
  SubmitOpCode(op, cl=cl, opts=opts)
816 53c776b5 Iustin Pop
  return 0
817 53c776b5 Iustin Pop
818 53c776b5 Iustin Pop
819 fbf5a861 Iustin Pop
def MoveInstance(opts, args):
820 fbf5a861 Iustin Pop
  """Move an instance.
821 fbf5a861 Iustin Pop

822 fbf5a861 Iustin Pop
  @param opts: the command line options selected by the user
823 fbf5a861 Iustin Pop
  @type args: list
824 fbf5a861 Iustin Pop
  @param args: should contain only one element, the instance name
825 fbf5a861 Iustin Pop
  @rtype: int
826 fbf5a861 Iustin Pop
  @return: the desired exit code
827 fbf5a861 Iustin Pop

828 fbf5a861 Iustin Pop
  """
829 fbf5a861 Iustin Pop
  cl = GetClient()
830 fbf5a861 Iustin Pop
  instance_name = args[0]
831 fbf5a861 Iustin Pop
  force = opts.force
832 fbf5a861 Iustin Pop
833 fbf5a861 Iustin Pop
  if not force:
834 fbf5a861 Iustin Pop
    usertext = ("Instance %s will be moved."
835 fbf5a861 Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
836 fbf5a861 Iustin Pop
                (instance_name,))
837 fbf5a861 Iustin Pop
    if not AskUser(usertext):
838 fbf5a861 Iustin Pop
      return 1
839 fbf5a861 Iustin Pop
840 0091b480 Iustin Pop
  op = opcodes.OpInstanceMove(instance_name=instance_name,
841 17c3f802 Guido Trotter
                              target_node=opts.node,
842 4d98c565 Guido Trotter
                              shutdown_timeout=opts.shutdown_timeout)
843 fbf5a861 Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
844 fbf5a861 Iustin Pop
  return 0
845 fbf5a861 Iustin Pop
846 fbf5a861 Iustin Pop
847 a8083063 Iustin Pop
def ConnectToInstanceConsole(opts, args):
848 a8083063 Iustin Pop
  """Connect to the console of an instance.
849 a8083063 Iustin Pop

850 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
851 7232c04c Iustin Pop
  @type args: list
852 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
853 7232c04c Iustin Pop
  @rtype: int
854 7232c04c Iustin Pop
  @return: the desired exit code
855 a8083063 Iustin Pop

856 a8083063 Iustin Pop
  """
857 a8083063 Iustin Pop
  instance_name = args[0]
858 a8083063 Iustin Pop
859 cc0dec7b Iustin Pop
  op = opcodes.OpInstanceConsole(instance_name=instance_name)
860 51c6e7b5 Michael Hanselmann
861 25ce3ec4 Michael Hanselmann
  cl = GetClient()
862 25ce3ec4 Michael Hanselmann
  try:
863 25ce3ec4 Michael Hanselmann
    cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
864 25ce3ec4 Michael Hanselmann
    console_data = SubmitOpCode(op, opts=opts, cl=cl)
865 25ce3ec4 Michael Hanselmann
  finally:
866 25ce3ec4 Michael Hanselmann
    # Ensure client connection is closed while external commands are run
867 25ce3ec4 Michael Hanselmann
    cl.Close()
868 25ce3ec4 Michael Hanselmann
869 25ce3ec4 Michael Hanselmann
  del cl
870 25ce3ec4 Michael Hanselmann
871 25ce3ec4 Michael Hanselmann
  return _DoConsole(objects.InstanceConsole.FromDict(console_data),
872 25ce3ec4 Michael Hanselmann
                    opts.show_command, cluster_name)
873 25ce3ec4 Michael Hanselmann
874 25ce3ec4 Michael Hanselmann
875 25ce3ec4 Michael Hanselmann
def _DoConsole(console, show_command, cluster_name, feedback_fn=ToStdout,
876 25ce3ec4 Michael Hanselmann
               _runcmd_fn=utils.RunCmd):
877 cc0dec7b Iustin Pop
  """Acts based on the result of L{opcodes.OpInstanceConsole}.
878 25ce3ec4 Michael Hanselmann

879 25ce3ec4 Michael Hanselmann
  @type console: L{objects.InstanceConsole}
880 25ce3ec4 Michael Hanselmann
  @param console: Console object
881 25ce3ec4 Michael Hanselmann
  @type show_command: bool
882 25ce3ec4 Michael Hanselmann
  @param show_command: Whether to just display commands
883 25ce3ec4 Michael Hanselmann
  @type cluster_name: string
884 25ce3ec4 Michael Hanselmann
  @param cluster_name: Cluster name as retrieved from master daemon
885 25ce3ec4 Michael Hanselmann

886 25ce3ec4 Michael Hanselmann
  """
887 25ce3ec4 Michael Hanselmann
  assert console.Validate()
888 25ce3ec4 Michael Hanselmann
889 25ce3ec4 Michael Hanselmann
  if console.kind == constants.CONS_MESSAGE:
890 25ce3ec4 Michael Hanselmann
    feedback_fn(console.message)
891 25ce3ec4 Michael Hanselmann
  elif console.kind == constants.CONS_VNC:
892 25ce3ec4 Michael Hanselmann
    feedback_fn("Instance %s has VNC listening on %s:%s (display %s),"
893 25ce3ec4 Michael Hanselmann
                " URL <vnc://%s:%s/>",
894 25ce3ec4 Michael Hanselmann
                console.instance, console.host, console.port,
895 25ce3ec4 Michael Hanselmann
                console.display, console.host, console.port)
896 25ce3ec4 Michael Hanselmann
  elif console.kind == constants.CONS_SSH:
897 25ce3ec4 Michael Hanselmann
    # Convert to string if not already one
898 25ce3ec4 Michael Hanselmann
    if isinstance(console.command, basestring):
899 25ce3ec4 Michael Hanselmann
      cmd = console.command
900 25ce3ec4 Michael Hanselmann
    else:
901 25ce3ec4 Michael Hanselmann
      cmd = utils.ShellQuoteArgs(console.command)
902 25ce3ec4 Michael Hanselmann
903 25ce3ec4 Michael Hanselmann
    srun = ssh.SshRunner(cluster_name=cluster_name)
904 25ce3ec4 Michael Hanselmann
    ssh_cmd = srun.BuildCmd(console.host, console.user, cmd,
905 25ce3ec4 Michael Hanselmann
                            batch=True, quiet=False, tty=True)
906 25ce3ec4 Michael Hanselmann
907 25ce3ec4 Michael Hanselmann
    if show_command:
908 25ce3ec4 Michael Hanselmann
      feedback_fn(utils.ShellQuoteArgs(ssh_cmd))
909 25ce3ec4 Michael Hanselmann
    else:
910 25ce3ec4 Michael Hanselmann
      result = _runcmd_fn(ssh_cmd, interactive=True)
911 25ce3ec4 Michael Hanselmann
      if result.failed:
912 25ce3ec4 Michael Hanselmann
        logging.error("Console command \"%s\" failed with reason '%s' and"
913 25ce3ec4 Michael Hanselmann
                      " output %r", result.cmd, result.fail_reason,
914 25ce3ec4 Michael Hanselmann
                      result.output)
915 25ce3ec4 Michael Hanselmann
        raise errors.OpExecError("Connection to console of instance %s failed,"
916 25ce3ec4 Michael Hanselmann
                                 " please check cluster configuration" %
917 25ce3ec4 Michael Hanselmann
                                 console.instance)
918 51c6e7b5 Michael Hanselmann
  else:
919 25ce3ec4 Michael Hanselmann
    raise errors.GenericError("Unknown console type '%s'" % console.kind)
920 678aa6d3 Michael Hanselmann
921 678aa6d3 Michael Hanselmann
  return constants.EXIT_SUCCESS
922 a8083063 Iustin Pop
923 a8083063 Iustin Pop
924 e2736e40 Guido Trotter
def _FormatLogicalID(dev_type, logical_id, roman):
925 19708787 Iustin Pop
  """Formats the logical_id of a disk.
926 19708787 Iustin Pop

927 19708787 Iustin Pop
  """
928 19708787 Iustin Pop
  if dev_type == constants.LD_DRBD8:
929 19708787 Iustin Pop
    node_a, node_b, port, minor_a, minor_b, key = logical_id
930 19708787 Iustin Pop
    data = [
931 e2736e40 Guido Trotter
      ("nodeA", "%s, minor=%s" % (node_a, compat.TryToRoman(minor_a,
932 e2736e40 Guido Trotter
                                                            convert=roman))),
933 e2736e40 Guido Trotter
      ("nodeB", "%s, minor=%s" % (node_b, compat.TryToRoman(minor_b,
934 e2736e40 Guido Trotter
                                                            convert=roman))),
935 e2736e40 Guido Trotter
      ("port", compat.TryToRoman(port, convert=roman)),
936 19708787 Iustin Pop
      ("auth key", key),
937 19708787 Iustin Pop
      ]
938 19708787 Iustin Pop
  elif dev_type == constants.LD_LV:
939 19708787 Iustin Pop
    vg_name, lv_name = logical_id
940 19708787 Iustin Pop
    data = ["%s/%s" % (vg_name, lv_name)]
941 19708787 Iustin Pop
  else:
942 19708787 Iustin Pop
    data = [str(logical_id)]
943 19708787 Iustin Pop
944 19708787 Iustin Pop
  return data
945 19708787 Iustin Pop
946 19708787 Iustin Pop
947 e2736e40 Guido Trotter
def _FormatBlockDevInfo(idx, top_level, dev, static, roman):
948 a8083063 Iustin Pop
  """Show block device information.
949 a8083063 Iustin Pop

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

953 19708787 Iustin Pop
  @type idx: int
954 19708787 Iustin Pop
  @param idx: the index of the current disk
955 19708787 Iustin Pop
  @type top_level: boolean
956 19708787 Iustin Pop
  @param top_level: if this a top-level disk?
957 7232c04c Iustin Pop
  @type dev: dict
958 7232c04c Iustin Pop
  @param dev: dictionary with disk information
959 7232c04c Iustin Pop
  @type static: boolean
960 7232c04c Iustin Pop
  @param static: wheter the device information doesn't contain
961 7232c04c Iustin Pop
      runtime information but only static data
962 e2736e40 Guido Trotter
  @type roman: boolean
963 e2736e40 Guido Trotter
  @param roman: whether to try to use roman integers
964 19708787 Iustin Pop
  @return: a list of either strings, tuples or lists
965 19708787 Iustin Pop
      (which should be formatted at a higher indent level)
966 7232c04c Iustin Pop

967 a8083063 Iustin Pop
  """
968 19708787 Iustin Pop
  def helper(dtype, status):
969 7232c04c Iustin Pop
    """Format one line for physical device status.
970 7232c04c Iustin Pop

971 7232c04c Iustin Pop
    @type dtype: str
972 7232c04c Iustin Pop
    @param dtype: a constant from the L{constants.LDS_BLOCK} set
973 7232c04c Iustin Pop
    @type status: tuple
974 7232c04c Iustin Pop
    @param status: a tuple as returned from L{backend.FindBlockDevice}
975 19708787 Iustin Pop
    @return: the string representing the status
976 7232c04c Iustin Pop

977 7232c04c Iustin Pop
    """
978 a8083063 Iustin Pop
    if not status:
979 19708787 Iustin Pop
      return "not active"
980 19708787 Iustin Pop
    txt = ""
981 f208978a Michael Hanselmann
    (path, major, minor, syncp, estt, degr, ldisk_status) = status
982 19708787 Iustin Pop
    if major is None:
983 19708787 Iustin Pop
      major_string = "N/A"
984 a8083063 Iustin Pop
    else:
985 e2736e40 Guido Trotter
      major_string = str(compat.TryToRoman(major, convert=roman))
986 fd38ef95 Manuel Franceschini
987 19708787 Iustin Pop
    if minor is None:
988 19708787 Iustin Pop
      minor_string = "N/A"
989 19708787 Iustin Pop
    else:
990 e2736e40 Guido Trotter
      minor_string = str(compat.TryToRoman(minor, convert=roman))
991 19708787 Iustin Pop
992 19708787 Iustin Pop
    txt += ("%s (%s:%s)" % (path, major_string, minor_string))
993 19708787 Iustin Pop
    if dtype in (constants.LD_DRBD8, ):
994 19708787 Iustin Pop
      if syncp is not None:
995 19708787 Iustin Pop
        sync_text = "*RECOVERING* %5.2f%%," % syncp
996 19708787 Iustin Pop
        if estt:
997 e2736e40 Guido Trotter
          sync_text += " ETA %ss" % compat.TryToRoman(estt, convert=roman)
998 9db6dbce Iustin Pop
        else:
999 19708787 Iustin Pop
          sync_text += " ETA unknown"
1000 19708787 Iustin Pop
      else:
1001 19708787 Iustin Pop
        sync_text = "in sync"
1002 19708787 Iustin Pop
      if degr:
1003 19708787 Iustin Pop
        degr_text = "*DEGRADED*"
1004 19708787 Iustin Pop
      else:
1005 19708787 Iustin Pop
        degr_text = "ok"
1006 f208978a Michael Hanselmann
      if ldisk_status == constants.LDS_FAULTY:
1007 19708787 Iustin Pop
        ldisk_text = " *MISSING DISK*"
1008 f208978a Michael Hanselmann
      elif ldisk_status == constants.LDS_UNKNOWN:
1009 f208978a Michael Hanselmann
        ldisk_text = " *UNCERTAIN STATE*"
1010 19708787 Iustin Pop
      else:
1011 19708787 Iustin Pop
        ldisk_text = ""
1012 19708787 Iustin Pop
      txt += (" %s, status %s%s" % (sync_text, degr_text, ldisk_text))
1013 19708787 Iustin Pop
    elif dtype == constants.LD_LV:
1014 f208978a Michael Hanselmann
      if ldisk_status == constants.LDS_FAULTY:
1015 19708787 Iustin Pop
        ldisk_text = " *FAILED* (failed drive?)"
1016 19708787 Iustin Pop
      else:
1017 19708787 Iustin Pop
        ldisk_text = ""
1018 19708787 Iustin Pop
      txt += ldisk_text
1019 19708787 Iustin Pop
    return txt
1020 19708787 Iustin Pop
1021 19708787 Iustin Pop
  # the header
1022 19708787 Iustin Pop
  if top_level:
1023 19708787 Iustin Pop
    if dev["iv_name"] is not None:
1024 19708787 Iustin Pop
      txt = dev["iv_name"]
1025 19708787 Iustin Pop
    else:
1026 e2736e40 Guido Trotter
      txt = "disk %s" % compat.TryToRoman(idx, convert=roman)
1027 a8083063 Iustin Pop
  else:
1028 e2736e40 Guido Trotter
    txt = "child %s" % compat.TryToRoman(idx, convert=roman)
1029 c98162a7 Iustin Pop
  if isinstance(dev["size"], int):
1030 c98162a7 Iustin Pop
    nice_size = utils.FormatUnit(dev["size"], "h")
1031 c98162a7 Iustin Pop
  else:
1032 c98162a7 Iustin Pop
    nice_size = dev["size"]
1033 c98162a7 Iustin Pop
  d1 = ["- %s: %s, size %s" % (txt, dev["dev_type"], nice_size)]
1034 19708787 Iustin Pop
  data = []
1035 19708787 Iustin Pop
  if top_level:
1036 19708787 Iustin Pop
    data.append(("access mode", dev["mode"]))
1037 a8083063 Iustin Pop
  if dev["logical_id"] is not None:
1038 19708787 Iustin Pop
    try:
1039 e2736e40 Guido Trotter
      l_id = _FormatLogicalID(dev["dev_type"], dev["logical_id"], roman)
1040 19708787 Iustin Pop
    except ValueError:
1041 19708787 Iustin Pop
      l_id = [str(dev["logical_id"])]
1042 19708787 Iustin Pop
    if len(l_id) == 1:
1043 19708787 Iustin Pop
      data.append(("logical_id", l_id[0]))
1044 19708787 Iustin Pop
    else:
1045 19708787 Iustin Pop
      data.extend(l_id)
1046 a8083063 Iustin Pop
  elif dev["physical_id"] is not None:
1047 19708787 Iustin Pop
    data.append("physical_id:")
1048 19708787 Iustin Pop
    data.append([dev["physical_id"]])
1049 57821cac Iustin Pop
  if not static:
1050 19708787 Iustin Pop
    data.append(("on primary", helper(dev["dev_type"], dev["pstatus"])))
1051 57821cac Iustin Pop
  if dev["sstatus"] and not static:
1052 19708787 Iustin Pop
    data.append(("on secondary", helper(dev["dev_type"], dev["sstatus"])))
1053 a8083063 Iustin Pop
1054 a8083063 Iustin Pop
  if dev["children"]:
1055 19708787 Iustin Pop
    data.append("child devices:")
1056 19708787 Iustin Pop
    for c_idx, child in enumerate(dev["children"]):
1057 e2736e40 Guido Trotter
      data.append(_FormatBlockDevInfo(c_idx, False, child, static, roman))
1058 19708787 Iustin Pop
  d1.append(data)
1059 19708787 Iustin Pop
  return d1
1060 a8083063 Iustin Pop
1061 a8083063 Iustin Pop
1062 19708787 Iustin Pop
def _FormatList(buf, data, indent_level):
1063 19708787 Iustin Pop
  """Formats a list of data at a given indent level.
1064 19708787 Iustin Pop

1065 19708787 Iustin Pop
  If the element of the list is:
1066 19708787 Iustin Pop
    - a string, it is simply formatted as is
1067 19708787 Iustin Pop
    - a tuple, it will be split into key, value and the all the
1068 19708787 Iustin Pop
      values in a list will be aligned all at the same start column
1069 19708787 Iustin Pop
    - a list, will be recursively formatted
1070 19708787 Iustin Pop

1071 19708787 Iustin Pop
  @type buf: StringIO
1072 19708787 Iustin Pop
  @param buf: the buffer into which we write the output
1073 19708787 Iustin Pop
  @param data: the list to format
1074 19708787 Iustin Pop
  @type indent_level: int
1075 19708787 Iustin Pop
  @param indent_level: the indent level to format at
1076 19708787 Iustin Pop

1077 19708787 Iustin Pop
  """
1078 19708787 Iustin Pop
  max_tlen = max([len(elem[0]) for elem in data
1079 19708787 Iustin Pop
                 if isinstance(elem, tuple)] or [0])
1080 19708787 Iustin Pop
  for elem in data:
1081 19708787 Iustin Pop
    if isinstance(elem, basestring):
1082 19708787 Iustin Pop
      buf.write("%*s%s\n" % (2*indent_level, "", elem))
1083 19708787 Iustin Pop
    elif isinstance(elem, tuple):
1084 19708787 Iustin Pop
      key, value = elem
1085 19708787 Iustin Pop
      spacer = "%*s" % (max_tlen - len(key), "")
1086 19708787 Iustin Pop
      buf.write("%*s%s:%s %s\n" % (2*indent_level, "", key, spacer, value))
1087 19708787 Iustin Pop
    elif isinstance(elem, list):
1088 19708787 Iustin Pop
      _FormatList(buf, elem, indent_level+1)
1089 19708787 Iustin Pop
1090 98825740 Michael Hanselmann
1091 a8083063 Iustin Pop
def ShowInstanceConfig(opts, args):
1092 a8083063 Iustin Pop
  """Compute instance run-time status.
1093 a8083063 Iustin Pop

1094 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1095 7232c04c Iustin Pop
  @type args: list
1096 7232c04c Iustin Pop
  @param args: either an empty list, and then we query all
1097 7232c04c Iustin Pop
      instances, or should contain a list of instance names
1098 7232c04c Iustin Pop
  @rtype: int
1099 7232c04c Iustin Pop
  @return: the desired exit code
1100 7232c04c Iustin Pop

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

1194 a8083063 Iustin Pop
  All parameters take effect only at the next restart of the instance.
1195 a8083063 Iustin Pop

1196 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1197 7232c04c Iustin Pop
  @type args: list
1198 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
1199 7232c04c Iustin Pop
  @rtype: int
1200 7232c04c Iustin Pop
  @return: the desired exit code
1201 a8083063 Iustin Pop

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