Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_instance.py @ 016acd85

History | View | Annotate | Download (50.5 kB)

1 e792102d Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 783a6c0b Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 7260cfbe Iustin Pop
"""Instance related commands"""
22 a8083063 Iustin Pop
23 7260cfbe Iustin Pop
# pylint: disable-msg=W0401,W0614,C0103
24 2f79bd34 Iustin Pop
# W0401: Wildcard import ganeti.cli
25 2f79bd34 Iustin Pop
# W0614: Unused import %s from wildcard import (since we need cli)
26 7260cfbe Iustin Pop
# C0103: Invalid name gnt-instance
27 2f79bd34 Iustin Pop
28 a8083063 Iustin Pop
import os
29 312ac745 Iustin Pop
import itertools
30 0d0e9090 René Nussbaumer
import simplejson
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 312ac745 Iustin Pop
41 312ac745 Iustin Pop
42 312ac745 Iustin Pop
_SHUTDOWN_CLUSTER = "cluster"
43 312ac745 Iustin Pop
_SHUTDOWN_NODES_BOTH = "nodes"
44 312ac745 Iustin Pop
_SHUTDOWN_NODES_PRI = "nodes-pri"
45 312ac745 Iustin Pop
_SHUTDOWN_NODES_SEC = "nodes-sec"
46 39dfd93e René Nussbaumer
_SHUTDOWN_NODES_BOTH_BY_TAGS = "nodes-by-tags"
47 39dfd93e René Nussbaumer
_SHUTDOWN_NODES_PRI_BY_TAGS = "nodes-pri-by-tags"
48 39dfd93e René Nussbaumer
_SHUTDOWN_NODES_SEC_BY_TAGS = "nodes-sec-by-tags"
49 312ac745 Iustin Pop
_SHUTDOWN_INSTANCES = "instances"
50 39dfd93e René Nussbaumer
_SHUTDOWN_INSTANCES_BY_TAGS = "instances-by-tags"
51 39dfd93e René Nussbaumer
52 39dfd93e René Nussbaumer
_SHUTDOWN_NODES_TAGS_MODES = (
53 39dfd93e René Nussbaumer
    _SHUTDOWN_NODES_BOTH_BY_TAGS,
54 39dfd93e René Nussbaumer
    _SHUTDOWN_NODES_PRI_BY_TAGS,
55 39dfd93e René Nussbaumer
    _SHUTDOWN_NODES_SEC_BY_TAGS)
56 312ac745 Iustin Pop
57 7c0d6283 Michael Hanselmann
58 31a853d2 Iustin Pop
_VALUE_TRUE = "true"
59 31a853d2 Iustin Pop
60 7232c04c Iustin Pop
#: default list of options for L{ListInstances}
61 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
62 e69d05fd Iustin Pop
  "name", "hypervisor", "os", "pnode", "status", "oper_ram",
63 48c4dfa8 Iustin Pop
  ]
64 48c4dfa8 Iustin Pop
65 bdb7d4e8 Michael Hanselmann
66 479636a3 Iustin Pop
def _ExpandMultiNames(mode, names, client=None):
67 312ac745 Iustin Pop
  """Expand the given names using the passed mode.
68 312ac745 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

277 d77490c5 Iustin Pop
  This is just a wrapper over GenericInstanceCreate.
278 a8083063 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

772 a8083063 Iustin Pop
  The failover is done by shutting it down on its present node and
773 a8083063 Iustin Pop
  starting it on the secondary.
774 a8083063 Iustin Pop

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

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

805 53c776b5 Iustin Pop
  The migrate is done without shutdown.
806 53c776b5 Iustin Pop

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

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

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

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

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

886 a8083063 Iustin Pop
  """
887 a8083063 Iustin Pop
  instance_name = args[0]
888 a8083063 Iustin Pop
889 a8083063 Iustin Pop
  op = opcodes.OpConnectConsole(instance_name=instance_name)
890 400ca2f7 Iustin Pop
  cmd = SubmitOpCode(op, opts=opts)
891 51c6e7b5 Michael Hanselmann
892 51c6e7b5 Michael Hanselmann
  if opts.show_command:
893 3a24c527 Iustin Pop
    ToStdout("%s", utils.ShellQuoteArgs(cmd))
894 51c6e7b5 Michael Hanselmann
  else:
895 51c6e7b5 Michael Hanselmann
    try:
896 51c6e7b5 Michael Hanselmann
      os.execvp(cmd[0], cmd)
897 51c6e7b5 Michael Hanselmann
    finally:
898 3a24c527 Iustin Pop
      ToStderr("Can't run console command %s with arguments:\n'%s'",
899 2f79bd34 Iustin Pop
               cmd[0], " ".join(cmd))
900 7260cfbe Iustin Pop
      os._exit(1) # pylint: disable-msg=W0212
901 a8083063 Iustin Pop
902 a8083063 Iustin Pop
903 e2736e40 Guido Trotter
def _FormatLogicalID(dev_type, logical_id, roman):
904 19708787 Iustin Pop
  """Formats the logical_id of a disk.
905 19708787 Iustin Pop

906 19708787 Iustin Pop
  """
907 19708787 Iustin Pop
  if dev_type == constants.LD_DRBD8:
908 19708787 Iustin Pop
    node_a, node_b, port, minor_a, minor_b, key = logical_id
909 19708787 Iustin Pop
    data = [
910 e2736e40 Guido Trotter
      ("nodeA", "%s, minor=%s" % (node_a, compat.TryToRoman(minor_a,
911 e2736e40 Guido Trotter
                                                            convert=roman))),
912 e2736e40 Guido Trotter
      ("nodeB", "%s, minor=%s" % (node_b, compat.TryToRoman(minor_b,
913 e2736e40 Guido Trotter
                                                            convert=roman))),
914 e2736e40 Guido Trotter
      ("port", compat.TryToRoman(port, convert=roman)),
915 19708787 Iustin Pop
      ("auth key", key),
916 19708787 Iustin Pop
      ]
917 19708787 Iustin Pop
  elif dev_type == constants.LD_LV:
918 19708787 Iustin Pop
    vg_name, lv_name = logical_id
919 19708787 Iustin Pop
    data = ["%s/%s" % (vg_name, lv_name)]
920 19708787 Iustin Pop
  else:
921 19708787 Iustin Pop
    data = [str(logical_id)]
922 19708787 Iustin Pop
923 19708787 Iustin Pop
  return data
924 19708787 Iustin Pop
925 19708787 Iustin Pop
926 e2736e40 Guido Trotter
def _FormatBlockDevInfo(idx, top_level, dev, static, roman):
927 a8083063 Iustin Pop
  """Show block device information.
928 a8083063 Iustin Pop

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

932 19708787 Iustin Pop
  @type idx: int
933 19708787 Iustin Pop
  @param idx: the index of the current disk
934 19708787 Iustin Pop
  @type top_level: boolean
935 19708787 Iustin Pop
  @param top_level: if this a top-level disk?
936 7232c04c Iustin Pop
  @type dev: dict
937 7232c04c Iustin Pop
  @param dev: dictionary with disk information
938 7232c04c Iustin Pop
  @type static: boolean
939 7232c04c Iustin Pop
  @param static: wheter the device information doesn't contain
940 7232c04c Iustin Pop
      runtime information but only static data
941 e2736e40 Guido Trotter
  @type roman: boolean
942 e2736e40 Guido Trotter
  @param roman: whether to try to use roman integers
943 19708787 Iustin Pop
  @return: a list of either strings, tuples or lists
944 19708787 Iustin Pop
      (which should be formatted at a higher indent level)
945 7232c04c Iustin Pop

946 a8083063 Iustin Pop
  """
947 19708787 Iustin Pop
  def helper(dtype, status):
948 7232c04c Iustin Pop
    """Format one line for physical device status.
949 7232c04c Iustin Pop

950 7232c04c Iustin Pop
    @type dtype: str
951 7232c04c Iustin Pop
    @param dtype: a constant from the L{constants.LDS_BLOCK} set
952 7232c04c Iustin Pop
    @type status: tuple
953 7232c04c Iustin Pop
    @param status: a tuple as returned from L{backend.FindBlockDevice}
954 19708787 Iustin Pop
    @return: the string representing the status
955 7232c04c Iustin Pop

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

1044 19708787 Iustin Pop
  If the element of the list is:
1045 19708787 Iustin Pop
    - a string, it is simply formatted as is
1046 19708787 Iustin Pop
    - a tuple, it will be split into key, value and the all the
1047 19708787 Iustin Pop
      values in a list will be aligned all at the same start column
1048 19708787 Iustin Pop
    - a list, will be recursively formatted
1049 19708787 Iustin Pop

1050 19708787 Iustin Pop
  @type buf: StringIO
1051 19708787 Iustin Pop
  @param buf: the buffer into which we write the output
1052 19708787 Iustin Pop
  @param data: the list to format
1053 19708787 Iustin Pop
  @type indent_level: int
1054 19708787 Iustin Pop
  @param indent_level: the indent level to format at
1055 19708787 Iustin Pop

1056 19708787 Iustin Pop
  """
1057 19708787 Iustin Pop
  max_tlen = max([len(elem[0]) for elem in data
1058 19708787 Iustin Pop
                 if isinstance(elem, tuple)] or [0])
1059 19708787 Iustin Pop
  for elem in data:
1060 19708787 Iustin Pop
    if isinstance(elem, basestring):
1061 19708787 Iustin Pop
      buf.write("%*s%s\n" % (2*indent_level, "", elem))
1062 19708787 Iustin Pop
    elif isinstance(elem, tuple):
1063 19708787 Iustin Pop
      key, value = elem
1064 19708787 Iustin Pop
      spacer = "%*s" % (max_tlen - len(key), "")
1065 19708787 Iustin Pop
      buf.write("%*s%s:%s %s\n" % (2*indent_level, "", key, spacer, value))
1066 19708787 Iustin Pop
    elif isinstance(elem, list):
1067 19708787 Iustin Pop
      _FormatList(buf, elem, indent_level+1)
1068 19708787 Iustin Pop
1069 98825740 Michael Hanselmann
1070 dbb24ec7 Iustin Pop
def _FormatParameterDict(buf, per_inst, actual):
1071 dbb24ec7 Iustin Pop
  """Formats a parameter dictionary.
1072 dbb24ec7 Iustin Pop

1073 dbb24ec7 Iustin Pop
  @type buf: L{StringIO}
1074 dbb24ec7 Iustin Pop
  @param buf: the buffer into which to write
1075 dbb24ec7 Iustin Pop
  @type per_inst: dict
1076 dbb24ec7 Iustin Pop
  @param per_inst: the instance's own parameters
1077 dbb24ec7 Iustin Pop
  @type actual: dict
1078 dbb24ec7 Iustin Pop
  @param actual: the current parameter set (including defaults)
1079 dbb24ec7 Iustin Pop

1080 dbb24ec7 Iustin Pop
  """
1081 dbb24ec7 Iustin Pop
  for key in sorted(actual):
1082 dbb24ec7 Iustin Pop
    val = per_inst.get(key, "default (%s)" % actual[key])
1083 dbb24ec7 Iustin Pop
    buf.write("    - %s: %s\n" % (key, val))
1084 dbb24ec7 Iustin Pop
1085 a8083063 Iustin Pop
def ShowInstanceConfig(opts, args):
1086 a8083063 Iustin Pop
  """Compute instance run-time status.
1087 a8083063 Iustin Pop

1088 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1089 7232c04c Iustin Pop
  @type args: list
1090 7232c04c Iustin Pop
  @param args: either an empty list, and then we query all
1091 7232c04c Iustin Pop
      instances, or should contain a list of instance names
1092 7232c04c Iustin Pop
  @rtype: int
1093 7232c04c Iustin Pop
  @return: the desired exit code
1094 7232c04c Iustin Pop

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

1185 a8083063 Iustin Pop
  All parameters take effect only at the next restart of the instance.
1186 a8083063 Iustin Pop

1187 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1188 7232c04c Iustin Pop
  @type args: list
1189 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
1190 7232c04c Iustin Pop
  @rtype: int
1191 7232c04c Iustin Pop
  @return: the desired exit code
1192 a8083063 Iustin Pop

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