Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_instance.py @ 3086220e

History | View | Annotate | Download (58.6 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 b459a848 Andrea Spadaccini
# pylint: disable=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 735e1318 Michael Hanselmann
from ganeti import ht
43 312ac745 Iustin Pop
44 312ac745 Iustin Pop
45 c20efaa8 Michael Hanselmann
_EXPAND_CLUSTER = "cluster"
46 c20efaa8 Michael Hanselmann
_EXPAND_NODES_BOTH = "nodes"
47 c20efaa8 Michael Hanselmann
_EXPAND_NODES_PRI = "nodes-pri"
48 c20efaa8 Michael Hanselmann
_EXPAND_NODES_SEC = "nodes-sec"
49 c20efaa8 Michael Hanselmann
_EXPAND_NODES_BOTH_BY_TAGS = "nodes-by-tags"
50 c20efaa8 Michael Hanselmann
_EXPAND_NODES_PRI_BY_TAGS = "nodes-pri-by-tags"
51 c20efaa8 Michael Hanselmann
_EXPAND_NODES_SEC_BY_TAGS = "nodes-sec-by-tags"
52 c20efaa8 Michael Hanselmann
_EXPAND_INSTANCES = "instances"
53 c20efaa8 Michael Hanselmann
_EXPAND_INSTANCES_BY_TAGS = "instances-by-tags"
54 c20efaa8 Michael Hanselmann
55 c20efaa8 Michael Hanselmann
_EXPAND_NODES_TAGS_MODES = frozenset([
56 c20efaa8 Michael Hanselmann
  _EXPAND_NODES_BOTH_BY_TAGS,
57 c20efaa8 Michael Hanselmann
  _EXPAND_NODES_PRI_BY_TAGS,
58 c20efaa8 Michael Hanselmann
  _EXPAND_NODES_SEC_BY_TAGS,
59 c20efaa8 Michael Hanselmann
  ])
60 312ac745 Iustin Pop
61 7c0d6283 Michael Hanselmann
62 7232c04c Iustin Pop
#: default list of options for L{ListInstances}
63 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
64 e69d05fd Iustin Pop
  "name", "hypervisor", "os", "pnode", "status", "oper_ram",
65 48c4dfa8 Iustin Pop
  ]
66 48c4dfa8 Iustin Pop
67 bdb7d4e8 Michael Hanselmann
68 a71f835e Michael Hanselmann
_MISSING = object()
69 ef9fa5b9 René Nussbaumer
_ENV_OVERRIDE = frozenset(["list"])
70 ef9fa5b9 René Nussbaumer
71 ef9fa5b9 René Nussbaumer
72 479636a3 Iustin Pop
def _ExpandMultiNames(mode, names, client=None):
73 312ac745 Iustin Pop
  """Expand the given names using the passed mode.
74 312ac745 Iustin Pop

75 c20efaa8 Michael Hanselmann
  For _EXPAND_CLUSTER, all instances will be returned. For
76 c20efaa8 Michael Hanselmann
  _EXPAND_NODES_PRI/SEC, all instances having those nodes as
77 c20efaa8 Michael Hanselmann
  primary/secondary will be returned. For _EXPAND_NODES_BOTH, all
78 312ac745 Iustin Pop
  instances having those nodes as either primary or secondary will be
79 c20efaa8 Michael Hanselmann
  returned. For _EXPAND_INSTANCES, the given instances will be
80 312ac745 Iustin Pop
  returned.
81 312ac745 Iustin Pop

82 c20efaa8 Michael Hanselmann
  @param mode: one of L{_EXPAND_CLUSTER}, L{_EXPAND_NODES_BOTH},
83 c20efaa8 Michael Hanselmann
      L{_EXPAND_NODES_PRI}, L{_EXPAND_NODES_SEC} or
84 c20efaa8 Michael Hanselmann
      L{_EXPAND_INSTANCES}
85 7232c04c Iustin Pop
  @param names: a list of names; for cluster, it must be empty,
86 7232c04c Iustin Pop
      and for node and instance it must be a list of valid item
87 7232c04c Iustin Pop
      names (short names are valid as usual, e.g. node1 instead of
88 7232c04c Iustin Pop
      node1.example.com)
89 7232c04c Iustin Pop
  @rtype: list
90 7232c04c Iustin Pop
  @return: the list of names after the expansion
91 7232c04c Iustin Pop
  @raise errors.ProgrammerError: for unknown selection type
92 7232c04c Iustin Pop
  @raise errors.OpPrereqError: for invalid input parameters
93 7232c04c Iustin Pop

94 312ac745 Iustin Pop
  """
95 b459a848 Andrea Spadaccini
  # pylint: disable=W0142
96 39dfd93e René Nussbaumer
97 479636a3 Iustin Pop
  if client is None:
98 479636a3 Iustin Pop
    client = GetClient()
99 c20efaa8 Michael Hanselmann
  if mode == _EXPAND_CLUSTER:
100 312ac745 Iustin Pop
    if names:
101 debac808 Iustin Pop
      raise errors.OpPrereqError("Cluster filter mode takes no arguments",
102 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
103 ec79568d Iustin Pop
    idata = client.QueryInstances([], ["name"], False)
104 312ac745 Iustin Pop
    inames = [row[0] for row in idata]
105 312ac745 Iustin Pop
106 c20efaa8 Michael Hanselmann
  elif (mode in _EXPAND_NODES_TAGS_MODES or
107 c20efaa8 Michael Hanselmann
        mode in (_EXPAND_NODES_BOTH, _EXPAND_NODES_PRI, _EXPAND_NODES_SEC)):
108 c20efaa8 Michael Hanselmann
    if mode in _EXPAND_NODES_TAGS_MODES:
109 39dfd93e René Nussbaumer
      if not names:
110 39dfd93e René Nussbaumer
        raise errors.OpPrereqError("No node tags passed", errors.ECODE_INVAL)
111 39dfd93e René Nussbaumer
      ndata = client.QueryNodes([], ["name", "pinst_list",
112 39dfd93e René Nussbaumer
                                     "sinst_list", "tags"], False)
113 39dfd93e René Nussbaumer
      ndata = [row for row in ndata if set(row[3]).intersection(names)]
114 39dfd93e René Nussbaumer
    else:
115 39dfd93e René Nussbaumer
      if not names:
116 39dfd93e René Nussbaumer
        raise errors.OpPrereqError("No node names passed", errors.ECODE_INVAL)
117 39dfd93e René Nussbaumer
      ndata = client.QueryNodes(names, ["name", "pinst_list", "sinst_list"],
118 77921a95 Iustin Pop
                              False)
119 39dfd93e René Nussbaumer
120 312ac745 Iustin Pop
    ipri = [row[1] for row in ndata]
121 312ac745 Iustin Pop
    pri_names = list(itertools.chain(*ipri))
122 312ac745 Iustin Pop
    isec = [row[2] for row in ndata]
123 312ac745 Iustin Pop
    sec_names = list(itertools.chain(*isec))
124 c20efaa8 Michael Hanselmann
    if mode in (_EXPAND_NODES_BOTH, _EXPAND_NODES_BOTH_BY_TAGS):
125 312ac745 Iustin Pop
      inames = pri_names + sec_names
126 c20efaa8 Michael Hanselmann
    elif mode in (_EXPAND_NODES_PRI, _EXPAND_NODES_PRI_BY_TAGS):
127 312ac745 Iustin Pop
      inames = pri_names
128 c20efaa8 Michael Hanselmann
    elif mode in (_EXPAND_NODES_SEC, _EXPAND_NODES_SEC_BY_TAGS):
129 312ac745 Iustin Pop
      inames = sec_names
130 312ac745 Iustin Pop
    else:
131 312ac745 Iustin Pop
      raise errors.ProgrammerError("Unhandled shutdown type")
132 c20efaa8 Michael Hanselmann
  elif mode == _EXPAND_INSTANCES:
133 312ac745 Iustin Pop
    if not names:
134 debac808 Iustin Pop
      raise errors.OpPrereqError("No instance names passed",
135 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
136 ec79568d Iustin Pop
    idata = client.QueryInstances(names, ["name"], False)
137 312ac745 Iustin Pop
    inames = [row[0] for row in idata]
138 c20efaa8 Michael Hanselmann
  elif mode == _EXPAND_INSTANCES_BY_TAGS:
139 39dfd93e René Nussbaumer
    if not names:
140 39dfd93e René Nussbaumer
      raise errors.OpPrereqError("No instance tags passed",
141 39dfd93e René Nussbaumer
                                 errors.ECODE_INVAL)
142 39dfd93e René Nussbaumer
    idata = client.QueryInstances([], ["name", "tags"], False)
143 39dfd93e René Nussbaumer
    inames = [row[0] for row in idata if set(row[1]).intersection(names)]
144 312ac745 Iustin Pop
  else:
145 debac808 Iustin Pop
    raise errors.OpPrereqError("Unknown mode '%s'" % mode, errors.ECODE_INVAL)
146 312ac745 Iustin Pop
147 312ac745 Iustin Pop
  return inames
148 a8083063 Iustin Pop
149 a8083063 Iustin Pop
150 a76f0c4a Iustin Pop
def _EnsureInstancesExist(client, names):
151 a76f0c4a Iustin Pop
  """Check for and ensure the given instance names exist.
152 a76f0c4a Iustin Pop

153 a76f0c4a Iustin Pop
  This function will raise an OpPrereqError in case they don't
154 a76f0c4a Iustin Pop
  exist. Otherwise it will exit cleanly.
155 a76f0c4a Iustin Pop

156 f2fd87d7 Iustin Pop
  @type client: L{ganeti.luxi.Client}
157 a76f0c4a Iustin Pop
  @param client: the client to use for the query
158 a76f0c4a Iustin Pop
  @type names: list
159 a76f0c4a Iustin Pop
  @param names: the list of instance names to query
160 a76f0c4a Iustin Pop
  @raise errors.OpPrereqError: in case any instance is missing
161 a76f0c4a Iustin Pop

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

175 1c5945b6 Iustin Pop
  The will return a wrapper that processes the options and arguments
176 1c5945b6 Iustin Pop
  given, and uses the passed function to build the opcode needed for
177 1c5945b6 Iustin Pop
  the specific operation. Thus all the generic loop/confirmation code
178 1c5945b6 Iustin Pop
  is abstracted into this function.
179 1c5945b6 Iustin Pop

180 1c5945b6 Iustin Pop
  """
181 1c5945b6 Iustin Pop
  def realfn(opts, args):
182 1c5945b6 Iustin Pop
    if opts.multi_mode is None:
183 c20efaa8 Michael Hanselmann
      opts.multi_mode = _EXPAND_INSTANCES
184 1c5945b6 Iustin Pop
    cl = GetClient()
185 1c5945b6 Iustin Pop
    inames = _ExpandMultiNames(opts.multi_mode, args, client=cl)
186 1c5945b6 Iustin Pop
    if not inames:
187 c20efaa8 Michael Hanselmann
      if opts.multi_mode == _EXPAND_CLUSTER:
188 c37bb2c6 Stephen Shirley
        ToStdout("Cluster is empty, no instances to shutdown")
189 c37bb2c6 Stephen Shirley
        return 0
190 1c5945b6 Iustin Pop
      raise errors.OpPrereqError("Selection filter does not match"
191 debac808 Iustin Pop
                                 " any instances", errors.ECODE_INVAL)
192 c20efaa8 Michael Hanselmann
    multi_on = opts.multi_mode != _EXPAND_INSTANCES or len(inames) > 1
193 1c5945b6 Iustin Pop
    if not (opts.force_multi or not multi_on
194 25bd815c René Nussbaumer
            or ConfirmOperation(inames, "instances", operation)):
195 1c5945b6 Iustin Pop
      return 1
196 cb573a31 Iustin Pop
    jex = JobExecutor(verbose=multi_on, cl=cl, opts=opts)
197 1c5945b6 Iustin Pop
    for name in inames:
198 1c5945b6 Iustin Pop
      op = fn(name, opts)
199 1c5945b6 Iustin Pop
      jex.QueueJob(name, op)
200 b4e68848 Iustin Pop
    results = jex.WaitOrShow(not opts.submit_only)
201 b4e68848 Iustin Pop
    rcode = compat.all(row[0] for row in results)
202 b4e68848 Iustin Pop
    return int(not rcode)
203 1c5945b6 Iustin Pop
  return realfn
204 1c5945b6 Iustin Pop
205 1c5945b6 Iustin Pop
206 a8083063 Iustin Pop
def ListInstances(opts, args):
207 f5abe9bd Oleksiy Mishchenko
  """List instances and their properties.
208 a8083063 Iustin Pop

209 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
210 7232c04c Iustin Pop
  @type args: list
211 7232c04c Iustin Pop
  @param args: should be an empty list
212 7232c04c Iustin Pop
  @rtype: int
213 7232c04c Iustin Pop
  @return: the desired exit code
214 7232c04c Iustin Pop

215 a8083063 Iustin Pop
  """
216 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
217 a8083063 Iustin Pop
218 b82c5ff5 Michael Hanselmann
  fmtoverride = dict.fromkeys(["tags", "disk.sizes", "nic.macs", "nic.ips",
219 b82c5ff5 Michael Hanselmann
                               "nic.modes", "nic.links", "nic.bridges",
220 fab9573b Michael Hanselmann
                               "snodes", "snodes.group", "snodes.group.uuid"],
221 b82c5ff5 Michael Hanselmann
                              (lambda value: ",".join(str(item)
222 b82c5ff5 Michael Hanselmann
                                                      for item in value),
223 b82c5ff5 Michael Hanselmann
                               False))
224 a8083063 Iustin Pop
225 b82c5ff5 Michael Hanselmann
  return GenericList(constants.QR_INSTANCE, selected_fields, args, opts.units,
226 b82c5ff5 Michael Hanselmann
                     opts.separator, not opts.no_headers,
227 87e87959 Michael Hanselmann
                     format_override=fmtoverride, verbose=opts.verbose,
228 87e87959 Michael Hanselmann
                     force_filter=opts.force_filter)
229 b82c5ff5 Michael Hanselmann
230 b82c5ff5 Michael Hanselmann
231 b82c5ff5 Michael Hanselmann
def ListInstanceFields(opts, args):
232 b82c5ff5 Michael Hanselmann
  """List instance fields.
233 b82c5ff5 Michael Hanselmann

234 b82c5ff5 Michael Hanselmann
  @param opts: the command line options selected by the user
235 b82c5ff5 Michael Hanselmann
  @type args: list
236 b82c5ff5 Michael Hanselmann
  @param args: fields to list, or empty for all
237 b82c5ff5 Michael Hanselmann
  @rtype: int
238 b82c5ff5 Michael Hanselmann
  @return: the desired exit code
239 b82c5ff5 Michael Hanselmann

240 b82c5ff5 Michael Hanselmann
  """
241 b82c5ff5 Michael Hanselmann
  return GenericListFields(constants.QR_INSTANCE, args, opts.separator,
242 b82c5ff5 Michael Hanselmann
                           not opts.no_headers)
243 a8083063 Iustin Pop
244 a8083063 Iustin Pop
245 a8083063 Iustin Pop
def AddInstance(opts, args):
246 a8083063 Iustin Pop
  """Add an instance to the cluster.
247 a8083063 Iustin Pop

248 d77490c5 Iustin Pop
  This is just a wrapper over GenericInstanceCreate.
249 a8083063 Iustin Pop

250 a8083063 Iustin Pop
  """
251 d77490c5 Iustin Pop
  return GenericInstanceCreate(constants.INSTANCE_CREATE, opts, args)
252 a8083063 Iustin Pop
253 a8083063 Iustin Pop
254 0d0e9090 René Nussbaumer
def BatchCreate(opts, args):
255 7232c04c Iustin Pop
  """Create instances using a definition file.
256 7232c04c Iustin Pop

257 7232c04c Iustin Pop
  This function reads a json file with instances defined
258 7232c04c Iustin Pop
  in the form::
259 7232c04c Iustin Pop

260 7232c04c Iustin Pop
    {"instance-name":{
261 9939547b Iustin Pop
      "disk_size": [20480],
262 7232c04c Iustin Pop
      "template": "drbd",
263 7232c04c Iustin Pop
      "backend": {
264 7232c04c Iustin Pop
        "memory": 512,
265 7232c04c Iustin Pop
        "vcpus": 1 },
266 9939547b Iustin Pop
      "os": "debootstrap",
267 7232c04c Iustin Pop
      "primary_node": "firstnode",
268 7232c04c Iustin Pop
      "secondary_node": "secondnode",
269 7232c04c Iustin Pop
      "iallocator": "dumb"}
270 7232c04c Iustin Pop
    }
271 7232c04c Iustin Pop

272 7232c04c Iustin Pop
  Note that I{primary_node} and I{secondary_node} have precedence over
273 7232c04c Iustin Pop
  I{iallocator}.
274 7232c04c Iustin Pop

275 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
276 7232c04c Iustin Pop
  @type args: list
277 7232c04c Iustin Pop
  @param args: should contain one element, the json filename
278 7232c04c Iustin Pop
  @rtype: int
279 7232c04c Iustin Pop
  @return: the desired exit code
280 0d0e9090 René Nussbaumer

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

411 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
412 7232c04c Iustin Pop
  @type args: list
413 7232c04c Iustin Pop
  @param args: should contain only one element, the name of the
414 7232c04c Iustin Pop
      instance to be reinstalled
415 7232c04c Iustin Pop
  @rtype: int
416 7232c04c Iustin Pop
  @return: the desired exit code
417 fe7b0351 Michael Hanselmann

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

495 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
496 7232c04c Iustin Pop
  @type args: list
497 7232c04c Iustin Pop
  @param args: should contain only one element, the name of
498 7232c04c Iustin Pop
      the instance to be removed
499 7232c04c Iustin Pop
  @rtype: int
500 7232c04c Iustin Pop
  @return: the desired exit code
501 a8083063 Iustin Pop

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

526 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
527 7232c04c Iustin Pop
  @type args: list
528 7232c04c Iustin Pop
  @param args: should contain two elements, the old and the
529 7232c04c Iustin Pop
      new instance names
530 7232c04c Iustin Pop
  @rtype: int
531 7232c04c Iustin Pop
  @return: the desired exit code
532 decd5f45 Iustin Pop

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

554 a8083063 Iustin Pop
  This serves two purposes:
555 7232c04c Iustin Pop
    - it allows (as long as the instance is not running)
556 7232c04c Iustin Pop
      mounting the disks and modifying them from the node
557 a8083063 Iustin Pop
    - it repairs inactive secondary drbds
558 a8083063 Iustin Pop

559 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
560 7232c04c Iustin Pop
  @type args: list
561 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
562 7232c04c Iustin Pop
  @rtype: int
563 7232c04c Iustin Pop
  @return: the desired exit code
564 7232c04c Iustin Pop

565 a8083063 Iustin Pop
  """
566 a8083063 Iustin Pop
  instance_name = args[0]
567 83f5d475 Iustin Pop
  op = opcodes.OpInstanceActivateDisks(instance_name=instance_name,
568 b4ec07f8 Iustin Pop
                                       ignore_size=opts.ignore_size)
569 6340bb0a Iustin Pop
  disks_info = SubmitOrSend(op, opts)
570 a8083063 Iustin Pop
  for host, iname, nname in disks_info:
571 3a24c527 Iustin Pop
    ToStdout("%s:%s:%s", host, iname, nname)
572 a8083063 Iustin Pop
  return 0
573 a8083063 Iustin Pop
574 a8083063 Iustin Pop
575 a8083063 Iustin Pop
def DeactivateDisks(opts, args):
576 bd315bfa Iustin Pop
  """Deactivate an instance's disks.
577 a8083063 Iustin Pop

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

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

587 a8083063 Iustin Pop
  """
588 a8083063 Iustin Pop
  instance_name = args[0]
589 c9c41373 Iustin Pop
  op = opcodes.OpInstanceDeactivateDisks(instance_name=instance_name,
590 c9c41373 Iustin Pop
                                         force=opts.force)
591 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
592 a8083063 Iustin Pop
  return 0
593 a8083063 Iustin Pop
594 a8083063 Iustin Pop
595 bd315bfa Iustin Pop
def RecreateDisks(opts, args):
596 bd315bfa Iustin Pop
  """Recreate an instance's disks.
597 bd315bfa Iustin Pop

598 bd315bfa Iustin Pop
  @param opts: the command line options selected by the user
599 bd315bfa Iustin Pop
  @type args: list
600 bd315bfa Iustin Pop
  @param args: should contain only one element, the instance name
601 bd315bfa Iustin Pop
  @rtype: int
602 bd315bfa Iustin Pop
  @return: the desired exit code
603 bd315bfa Iustin Pop

604 bd315bfa Iustin Pop
  """
605 bd315bfa Iustin Pop
  instance_name = args[0]
606 735e1318 Michael Hanselmann
607 735e1318 Michael Hanselmann
  disks = []
608 735e1318 Michael Hanselmann
609 bd315bfa Iustin Pop
  if opts.disks:
610 735e1318 Michael Hanselmann
    for didx, ddict in opts.disks:
611 735e1318 Michael Hanselmann
      didx = int(didx)
612 735e1318 Michael Hanselmann
613 735e1318 Michael Hanselmann
      if not ht.TDict(ddict):
614 735e1318 Michael Hanselmann
        msg = "Invalid disk/%d value: expected dict, got %s" % (didx, ddict)
615 735e1318 Michael Hanselmann
        raise errors.OpPrereqError(msg)
616 735e1318 Michael Hanselmann
617 735e1318 Michael Hanselmann
      if constants.IDISK_SIZE in ddict:
618 735e1318 Michael Hanselmann
        try:
619 735e1318 Michael Hanselmann
          ddict[constants.IDISK_SIZE] = \
620 735e1318 Michael Hanselmann
            utils.ParseUnit(ddict[constants.IDISK_SIZE])
621 735e1318 Michael Hanselmann
        except ValueError, err:
622 735e1318 Michael Hanselmann
          raise errors.OpPrereqError("Invalid disk size for disk %d: %s" %
623 735e1318 Michael Hanselmann
                                     (didx, err))
624 735e1318 Michael Hanselmann
625 735e1318 Michael Hanselmann
      disks.append((didx, ddict))
626 735e1318 Michael Hanselmann
627 735e1318 Michael Hanselmann
    # TODO: Verify modifyable parameters (already done in
628 735e1318 Michael Hanselmann
    # LUInstanceRecreateDisks, but it'd be nice to have in the client)
629 bd315bfa Iustin Pop
630 c8a96ae7 Iustin Pop
  if opts.node:
631 c8a96ae7 Iustin Pop
    pnode, snode = SplitNodeOption(opts.node)
632 c8a96ae7 Iustin Pop
    nodes = [pnode]
633 c8a96ae7 Iustin Pop
    if snode is not None:
634 c8a96ae7 Iustin Pop
      nodes.append(snode)
635 c8a96ae7 Iustin Pop
  else:
636 c8a96ae7 Iustin Pop
    nodes = []
637 c8a96ae7 Iustin Pop
638 6b273e78 Iustin Pop
  op = opcodes.OpInstanceRecreateDisks(instance_name=instance_name,
639 735e1318 Michael Hanselmann
                                       disks=disks, nodes=nodes)
640 bd315bfa Iustin Pop
  SubmitOrSend(op, opts)
641 735e1318 Michael Hanselmann
642 bd315bfa Iustin Pop
  return 0
643 bd315bfa Iustin Pop
644 bd315bfa Iustin Pop
645 c6e911bc Iustin Pop
def GrowDisk(opts, args):
646 7232c04c Iustin Pop
  """Grow an instance's disks.
647 c6e911bc Iustin Pop

648 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
649 7232c04c Iustin Pop
  @type args: list
650 30a83755 Guido Trotter
  @param args: should contain three elements, the target instance name,
651 30a83755 Guido Trotter
      the target disk id, and the target growth
652 7232c04c Iustin Pop
  @rtype: int
653 7232c04c Iustin Pop
  @return: the desired exit code
654 c6e911bc Iustin Pop

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

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

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

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

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

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

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

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

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

722 a8083063 Iustin Pop
  """
723 ee3e37a7 Iustin Pop
  return opcodes.OpInstanceShutdown(instance_name=name,
724 b44bd844 Michael Hanselmann
                                    timeout=opts.timeout,
725 885a0fc4 Iustin Pop
                                    ignore_offline_nodes=opts.ignore_offline,
726 885a0fc4 Iustin Pop
                                    no_remember=opts.no_remember)
727 a8083063 Iustin Pop
728 a8083063 Iustin Pop
729 a8083063 Iustin Pop
def ReplaceDisks(opts, args):
730 a8083063 Iustin Pop
  """Replace the disks of an instance
731 a8083063 Iustin Pop

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

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

779 a8083063 Iustin Pop
  The failover is done by shutting it down on its present node and
780 a8083063 Iustin Pop
  starting it on the secondary.
781 a8083063 Iustin Pop

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

788 a8083063 Iustin Pop
  """
789 a76f0c4a Iustin Pop
  cl = GetClient()
790 80de0e3f Iustin Pop
  instance_name = args[0]
791 80de0e3f Iustin Pop
  force = opts.force
792 1b7761fd Apollon Oikonomopoulos
  iallocator = opts.iallocator
793 1b7761fd Apollon Oikonomopoulos
  target_node = opts.dst_node
794 1b7761fd Apollon Oikonomopoulos
795 1b7761fd Apollon Oikonomopoulos
  if iallocator and target_node:
796 1b7761fd Apollon Oikonomopoulos
    raise errors.OpPrereqError("Specify either an iallocator (-I), or a target"
797 1b7761fd Apollon Oikonomopoulos
                               " node (-n) but not both", errors.ECODE_INVAL)
798 a8083063 Iustin Pop
799 80de0e3f Iustin Pop
  if not force:
800 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
801 a76f0c4a Iustin Pop
802 80de0e3f Iustin Pop
    usertext = ("Failover will happen to image %s."
803 80de0e3f Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
804 80de0e3f Iustin Pop
                (instance_name,))
805 80de0e3f Iustin Pop
    if not AskUser(usertext):
806 80de0e3f Iustin Pop
      return 1
807 a8083063 Iustin Pop
808 019dbee1 Iustin Pop
  op = opcodes.OpInstanceFailover(instance_name=instance_name,
809 17c3f802 Guido Trotter
                                  ignore_consistency=opts.ignore_consistency,
810 1b7761fd Apollon Oikonomopoulos
                                  shutdown_timeout=opts.shutdown_timeout,
811 1b7761fd Apollon Oikonomopoulos
                                  iallocator=iallocator,
812 b6aaf437 René Nussbaumer
                                  target_node=target_node,
813 b6aaf437 René Nussbaumer
                                  ignore_ipolicy=opts.ignore_ipolicy)
814 a76f0c4a Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
815 80de0e3f Iustin Pop
  return 0
816 a8083063 Iustin Pop
817 a8083063 Iustin Pop
818 53c776b5 Iustin Pop
def MigrateInstance(opts, args):
819 53c776b5 Iustin Pop
  """Migrate an instance.
820 53c776b5 Iustin Pop

821 53c776b5 Iustin Pop
  The migrate is done without shutdown.
822 53c776b5 Iustin Pop

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

829 53c776b5 Iustin Pop
  """
830 a76f0c4a Iustin Pop
  cl = GetClient()
831 53c776b5 Iustin Pop
  instance_name = args[0]
832 53c776b5 Iustin Pop
  force = opts.force
833 1b7761fd Apollon Oikonomopoulos
  iallocator = opts.iallocator
834 1b7761fd Apollon Oikonomopoulos
  target_node = opts.dst_node
835 1b7761fd Apollon Oikonomopoulos
836 1b7761fd Apollon Oikonomopoulos
  if iallocator and target_node:
837 1b7761fd Apollon Oikonomopoulos
    raise errors.OpPrereqError("Specify either an iallocator (-I), or a target"
838 1b7761fd Apollon Oikonomopoulos
                               " node (-n) but not both", errors.ECODE_INVAL)
839 53c776b5 Iustin Pop
840 53c776b5 Iustin Pop
  if not force:
841 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
842 a76f0c4a Iustin Pop
843 53c776b5 Iustin Pop
    if opts.cleanup:
844 53c776b5 Iustin Pop
      usertext = ("Instance %s will be recovered from a failed migration."
845 53c776b5 Iustin Pop
                  " Note that the migration procedure (including cleanup)" %
846 53c776b5 Iustin Pop
                  (instance_name,))
847 53c776b5 Iustin Pop
    else:
848 53c776b5 Iustin Pop
      usertext = ("Instance %s will be migrated. Note that migration" %
849 53c776b5 Iustin Pop
                  (instance_name,))
850 cf29cfb6 Iustin Pop
    usertext += (" might impact the instance if anything goes wrong"
851 cf29cfb6 Iustin Pop
                 " (e.g. due to bugs in the hypervisor). Continue?")
852 53c776b5 Iustin Pop
    if not AskUser(usertext):
853 53c776b5 Iustin Pop
      return 1
854 53c776b5 Iustin Pop
855 e71b9ef4 Iustin Pop
  # this should be removed once --non-live is deprecated
856 783a6c0b Iustin Pop
  if not opts.live and opts.migration_mode is not None:
857 e71b9ef4 Iustin Pop
    raise errors.OpPrereqError("Only one of the --non-live and "
858 783a6c0b Iustin Pop
                               "--migration-mode options can be passed",
859 e71b9ef4 Iustin Pop
                               errors.ECODE_INVAL)
860 e71b9ef4 Iustin Pop
  if not opts.live: # --non-live passed
861 8c35561f Iustin Pop
    mode = constants.HT_MIGRATION_NONLIVE
862 e71b9ef4 Iustin Pop
  else:
863 8c35561f Iustin Pop
    mode = opts.migration_mode
864 e71b9ef4 Iustin Pop
865 75c866c2 Iustin Pop
  op = opcodes.OpInstanceMigrate(instance_name=instance_name, mode=mode,
866 1b7761fd Apollon Oikonomopoulos
                                 cleanup=opts.cleanup, iallocator=iallocator,
867 e9c487be René Nussbaumer
                                 target_node=target_node,
868 3ed23330 René Nussbaumer
                                 allow_failover=opts.allow_failover,
869 8c0b16f6 Guido Trotter
                                 allow_runtime_changes=opts.allow_runtime_chgs,
870 3ed23330 René Nussbaumer
                                 ignore_ipolicy=opts.ignore_ipolicy)
871 400ca2f7 Iustin Pop
  SubmitOpCode(op, cl=cl, opts=opts)
872 53c776b5 Iustin Pop
  return 0
873 53c776b5 Iustin Pop
874 53c776b5 Iustin Pop
875 fbf5a861 Iustin Pop
def MoveInstance(opts, args):
876 fbf5a861 Iustin Pop
  """Move an instance.
877 fbf5a861 Iustin Pop

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

884 fbf5a861 Iustin Pop
  """
885 fbf5a861 Iustin Pop
  cl = GetClient()
886 fbf5a861 Iustin Pop
  instance_name = args[0]
887 fbf5a861 Iustin Pop
  force = opts.force
888 fbf5a861 Iustin Pop
889 fbf5a861 Iustin Pop
  if not force:
890 fbf5a861 Iustin Pop
    usertext = ("Instance %s will be moved."
891 fbf5a861 Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
892 fbf5a861 Iustin Pop
                (instance_name,))
893 fbf5a861 Iustin Pop
    if not AskUser(usertext):
894 fbf5a861 Iustin Pop
      return 1
895 fbf5a861 Iustin Pop
896 0091b480 Iustin Pop
  op = opcodes.OpInstanceMove(instance_name=instance_name,
897 17c3f802 Guido Trotter
                              target_node=opts.node,
898 bb851c63 Iustin Pop
                              shutdown_timeout=opts.shutdown_timeout,
899 92cf62e3 René Nussbaumer
                              ignore_consistency=opts.ignore_consistency,
900 92cf62e3 René Nussbaumer
                              ignore_ipolicy=opts.ignore_ipolicy)
901 fbf5a861 Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
902 fbf5a861 Iustin Pop
  return 0
903 fbf5a861 Iustin Pop
904 fbf5a861 Iustin Pop
905 a8083063 Iustin Pop
def ConnectToInstanceConsole(opts, args):
906 a8083063 Iustin Pop
  """Connect to the console of an instance.
907 a8083063 Iustin Pop

908 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
909 7232c04c Iustin Pop
  @type args: list
910 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
911 7232c04c Iustin Pop
  @rtype: int
912 7232c04c Iustin Pop
  @return: the desired exit code
913 a8083063 Iustin Pop

914 a8083063 Iustin Pop
  """
915 a8083063 Iustin Pop
  instance_name = args[0]
916 a8083063 Iustin Pop
917 25ce3ec4 Michael Hanselmann
  cl = GetClient()
918 25ce3ec4 Michael Hanselmann
  try:
919 25ce3ec4 Michael Hanselmann
    cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
920 d6f46b6a Michael Hanselmann
    ((console_data, oper_state), ) = \
921 d6f46b6a Michael Hanselmann
      cl.QueryInstances([instance_name], ["console", "oper_state"], False)
922 25ce3ec4 Michael Hanselmann
  finally:
923 25ce3ec4 Michael Hanselmann
    # Ensure client connection is closed while external commands are run
924 25ce3ec4 Michael Hanselmann
    cl.Close()
925 25ce3ec4 Michael Hanselmann
926 25ce3ec4 Michael Hanselmann
  del cl
927 25ce3ec4 Michael Hanselmann
928 d6f46b6a Michael Hanselmann
  if not console_data:
929 d6f46b6a Michael Hanselmann
    if oper_state:
930 d6f46b6a Michael Hanselmann
      # Instance is running
931 d6f46b6a Michael Hanselmann
      raise errors.OpExecError("Console information for instance %s is"
932 d6f46b6a Michael Hanselmann
                               " unavailable" % instance_name)
933 d6f46b6a Michael Hanselmann
    else:
934 d6f46b6a Michael Hanselmann
      raise errors.OpExecError("Instance %s is not running, can't get console" %
935 d6f46b6a Michael Hanselmann
                               instance_name)
936 d6f46b6a Michael Hanselmann
937 25ce3ec4 Michael Hanselmann
  return _DoConsole(objects.InstanceConsole.FromDict(console_data),
938 25ce3ec4 Michael Hanselmann
                    opts.show_command, cluster_name)
939 25ce3ec4 Michael Hanselmann
940 25ce3ec4 Michael Hanselmann
941 25ce3ec4 Michael Hanselmann
def _DoConsole(console, show_command, cluster_name, feedback_fn=ToStdout,
942 25ce3ec4 Michael Hanselmann
               _runcmd_fn=utils.RunCmd):
943 cc0dec7b Iustin Pop
  """Acts based on the result of L{opcodes.OpInstanceConsole}.
944 25ce3ec4 Michael Hanselmann

945 25ce3ec4 Michael Hanselmann
  @type console: L{objects.InstanceConsole}
946 25ce3ec4 Michael Hanselmann
  @param console: Console object
947 25ce3ec4 Michael Hanselmann
  @type show_command: bool
948 25ce3ec4 Michael Hanselmann
  @param show_command: Whether to just display commands
949 25ce3ec4 Michael Hanselmann
  @type cluster_name: string
950 25ce3ec4 Michael Hanselmann
  @param cluster_name: Cluster name as retrieved from master daemon
951 25ce3ec4 Michael Hanselmann

952 25ce3ec4 Michael Hanselmann
  """
953 25ce3ec4 Michael Hanselmann
  assert console.Validate()
954 25ce3ec4 Michael Hanselmann
955 25ce3ec4 Michael Hanselmann
  if console.kind == constants.CONS_MESSAGE:
956 25ce3ec4 Michael Hanselmann
    feedback_fn(console.message)
957 25ce3ec4 Michael Hanselmann
  elif console.kind == constants.CONS_VNC:
958 25ce3ec4 Michael Hanselmann
    feedback_fn("Instance %s has VNC listening on %s:%s (display %s),"
959 25ce3ec4 Michael Hanselmann
                " URL <vnc://%s:%s/>",
960 25ce3ec4 Michael Hanselmann
                console.instance, console.host, console.port,
961 25ce3ec4 Michael Hanselmann
                console.display, console.host, console.port)
962 4d2cdb5a Andrea Spadaccini
  elif console.kind == constants.CONS_SPICE:
963 4d2cdb5a Andrea Spadaccini
    feedback_fn("Instance %s has SPICE listening on %s:%s", console.instance,
964 4d2cdb5a Andrea Spadaccini
                console.host, console.port)
965 25ce3ec4 Michael Hanselmann
  elif console.kind == constants.CONS_SSH:
966 25ce3ec4 Michael Hanselmann
    # Convert to string if not already one
967 25ce3ec4 Michael Hanselmann
    if isinstance(console.command, basestring):
968 25ce3ec4 Michael Hanselmann
      cmd = console.command
969 25ce3ec4 Michael Hanselmann
    else:
970 25ce3ec4 Michael Hanselmann
      cmd = utils.ShellQuoteArgs(console.command)
971 25ce3ec4 Michael Hanselmann
972 25ce3ec4 Michael Hanselmann
    srun = ssh.SshRunner(cluster_name=cluster_name)
973 25ce3ec4 Michael Hanselmann
    ssh_cmd = srun.BuildCmd(console.host, console.user, cmd,
974 25ce3ec4 Michael Hanselmann
                            batch=True, quiet=False, tty=True)
975 25ce3ec4 Michael Hanselmann
976 25ce3ec4 Michael Hanselmann
    if show_command:
977 25ce3ec4 Michael Hanselmann
      feedback_fn(utils.ShellQuoteArgs(ssh_cmd))
978 25ce3ec4 Michael Hanselmann
    else:
979 25ce3ec4 Michael Hanselmann
      result = _runcmd_fn(ssh_cmd, interactive=True)
980 25ce3ec4 Michael Hanselmann
      if result.failed:
981 25ce3ec4 Michael Hanselmann
        logging.error("Console command \"%s\" failed with reason '%s' and"
982 25ce3ec4 Michael Hanselmann
                      " output %r", result.cmd, result.fail_reason,
983 25ce3ec4 Michael Hanselmann
                      result.output)
984 25ce3ec4 Michael Hanselmann
        raise errors.OpExecError("Connection to console of instance %s failed,"
985 25ce3ec4 Michael Hanselmann
                                 " please check cluster configuration" %
986 25ce3ec4 Michael Hanselmann
                                 console.instance)
987 51c6e7b5 Michael Hanselmann
  else:
988 25ce3ec4 Michael Hanselmann
    raise errors.GenericError("Unknown console type '%s'" % console.kind)
989 678aa6d3 Michael Hanselmann
990 678aa6d3 Michael Hanselmann
  return constants.EXIT_SUCCESS
991 a8083063 Iustin Pop
992 a8083063 Iustin Pop
993 e2736e40 Guido Trotter
def _FormatLogicalID(dev_type, logical_id, roman):
994 19708787 Iustin Pop
  """Formats the logical_id of a disk.
995 19708787 Iustin Pop

996 19708787 Iustin Pop
  """
997 19708787 Iustin Pop
  if dev_type == constants.LD_DRBD8:
998 19708787 Iustin Pop
    node_a, node_b, port, minor_a, minor_b, key = logical_id
999 19708787 Iustin Pop
    data = [
1000 e2736e40 Guido Trotter
      ("nodeA", "%s, minor=%s" % (node_a, compat.TryToRoman(minor_a,
1001 e2736e40 Guido Trotter
                                                            convert=roman))),
1002 e2736e40 Guido Trotter
      ("nodeB", "%s, minor=%s" % (node_b, compat.TryToRoman(minor_b,
1003 e2736e40 Guido Trotter
                                                            convert=roman))),
1004 e2736e40 Guido Trotter
      ("port", compat.TryToRoman(port, convert=roman)),
1005 19708787 Iustin Pop
      ("auth key", key),
1006 19708787 Iustin Pop
      ]
1007 19708787 Iustin Pop
  elif dev_type == constants.LD_LV:
1008 19708787 Iustin Pop
    vg_name, lv_name = logical_id
1009 19708787 Iustin Pop
    data = ["%s/%s" % (vg_name, lv_name)]
1010 19708787 Iustin Pop
  else:
1011 19708787 Iustin Pop
    data = [str(logical_id)]
1012 19708787 Iustin Pop
1013 19708787 Iustin Pop
  return data
1014 19708787 Iustin Pop
1015 19708787 Iustin Pop
1016 f965260c Michael Hanselmann
def _FormatBlockDevInfo(idx, top_level, dev, roman):
1017 a8083063 Iustin Pop
  """Show block device information.
1018 a8083063 Iustin Pop

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

1022 19708787 Iustin Pop
  @type idx: int
1023 19708787 Iustin Pop
  @param idx: the index of the current disk
1024 19708787 Iustin Pop
  @type top_level: boolean
1025 19708787 Iustin Pop
  @param top_level: if this a top-level disk?
1026 7232c04c Iustin Pop
  @type dev: dict
1027 7232c04c Iustin Pop
  @param dev: dictionary with disk information
1028 e2736e40 Guido Trotter
  @type roman: boolean
1029 e2736e40 Guido Trotter
  @param roman: whether to try to use roman integers
1030 19708787 Iustin Pop
  @return: a list of either strings, tuples or lists
1031 19708787 Iustin Pop
      (which should be formatted at a higher indent level)
1032 7232c04c Iustin Pop

1033 a8083063 Iustin Pop
  """
1034 19708787 Iustin Pop
  def helper(dtype, status):
1035 7232c04c Iustin Pop
    """Format one line for physical device status.
1036 7232c04c Iustin Pop

1037 7232c04c Iustin Pop
    @type dtype: str
1038 7232c04c Iustin Pop
    @param dtype: a constant from the L{constants.LDS_BLOCK} set
1039 7232c04c Iustin Pop
    @type status: tuple
1040 7232c04c Iustin Pop
    @param status: a tuple as returned from L{backend.FindBlockDevice}
1041 19708787 Iustin Pop
    @return: the string representing the status
1042 7232c04c Iustin Pop

1043 7232c04c Iustin Pop
    """
1044 a8083063 Iustin Pop
    if not status:
1045 19708787 Iustin Pop
      return "not active"
1046 19708787 Iustin Pop
    txt = ""
1047 f208978a Michael Hanselmann
    (path, major, minor, syncp, estt, degr, ldisk_status) = status
1048 19708787 Iustin Pop
    if major is None:
1049 19708787 Iustin Pop
      major_string = "N/A"
1050 a8083063 Iustin Pop
    else:
1051 e2736e40 Guido Trotter
      major_string = str(compat.TryToRoman(major, convert=roman))
1052 fd38ef95 Manuel Franceschini
1053 19708787 Iustin Pop
    if minor is None:
1054 19708787 Iustin Pop
      minor_string = "N/A"
1055 19708787 Iustin Pop
    else:
1056 e2736e40 Guido Trotter
      minor_string = str(compat.TryToRoman(minor, convert=roman))
1057 19708787 Iustin Pop
1058 19708787 Iustin Pop
    txt += ("%s (%s:%s)" % (path, major_string, minor_string))
1059 19708787 Iustin Pop
    if dtype in (constants.LD_DRBD8, ):
1060 19708787 Iustin Pop
      if syncp is not None:
1061 19708787 Iustin Pop
        sync_text = "*RECOVERING* %5.2f%%," % syncp
1062 19708787 Iustin Pop
        if estt:
1063 e2736e40 Guido Trotter
          sync_text += " ETA %ss" % compat.TryToRoman(estt, convert=roman)
1064 9db6dbce Iustin Pop
        else:
1065 19708787 Iustin Pop
          sync_text += " ETA unknown"
1066 19708787 Iustin Pop
      else:
1067 19708787 Iustin Pop
        sync_text = "in sync"
1068 19708787 Iustin Pop
      if degr:
1069 19708787 Iustin Pop
        degr_text = "*DEGRADED*"
1070 19708787 Iustin Pop
      else:
1071 19708787 Iustin Pop
        degr_text = "ok"
1072 f208978a Michael Hanselmann
      if ldisk_status == constants.LDS_FAULTY:
1073 19708787 Iustin Pop
        ldisk_text = " *MISSING DISK*"
1074 f208978a Michael Hanselmann
      elif ldisk_status == constants.LDS_UNKNOWN:
1075 f208978a Michael Hanselmann
        ldisk_text = " *UNCERTAIN STATE*"
1076 19708787 Iustin Pop
      else:
1077 19708787 Iustin Pop
        ldisk_text = ""
1078 19708787 Iustin Pop
      txt += (" %s, status %s%s" % (sync_text, degr_text, ldisk_text))
1079 19708787 Iustin Pop
    elif dtype == constants.LD_LV:
1080 f208978a Michael Hanselmann
      if ldisk_status == constants.LDS_FAULTY:
1081 19708787 Iustin Pop
        ldisk_text = " *FAILED* (failed drive?)"
1082 19708787 Iustin Pop
      else:
1083 19708787 Iustin Pop
        ldisk_text = ""
1084 19708787 Iustin Pop
      txt += ldisk_text
1085 19708787 Iustin Pop
    return txt
1086 19708787 Iustin Pop
1087 19708787 Iustin Pop
  # the header
1088 19708787 Iustin Pop
  if top_level:
1089 19708787 Iustin Pop
    if dev["iv_name"] is not None:
1090 19708787 Iustin Pop
      txt = dev["iv_name"]
1091 19708787 Iustin Pop
    else:
1092 e2736e40 Guido Trotter
      txt = "disk %s" % compat.TryToRoman(idx, convert=roman)
1093 a8083063 Iustin Pop
  else:
1094 e2736e40 Guido Trotter
    txt = "child %s" % compat.TryToRoman(idx, convert=roman)
1095 c98162a7 Iustin Pop
  if isinstance(dev["size"], int):
1096 c98162a7 Iustin Pop
    nice_size = utils.FormatUnit(dev["size"], "h")
1097 c98162a7 Iustin Pop
  else:
1098 c98162a7 Iustin Pop
    nice_size = dev["size"]
1099 c98162a7 Iustin Pop
  d1 = ["- %s: %s, size %s" % (txt, dev["dev_type"], nice_size)]
1100 19708787 Iustin Pop
  data = []
1101 19708787 Iustin Pop
  if top_level:
1102 19708787 Iustin Pop
    data.append(("access mode", dev["mode"]))
1103 a8083063 Iustin Pop
  if dev["logical_id"] is not None:
1104 19708787 Iustin Pop
    try:
1105 e2736e40 Guido Trotter
      l_id = _FormatLogicalID(dev["dev_type"], dev["logical_id"], roman)
1106 19708787 Iustin Pop
    except ValueError:
1107 19708787 Iustin Pop
      l_id = [str(dev["logical_id"])]
1108 19708787 Iustin Pop
    if len(l_id) == 1:
1109 19708787 Iustin Pop
      data.append(("logical_id", l_id[0]))
1110 19708787 Iustin Pop
    else:
1111 19708787 Iustin Pop
      data.extend(l_id)
1112 a8083063 Iustin Pop
  elif dev["physical_id"] is not None:
1113 19708787 Iustin Pop
    data.append("physical_id:")
1114 19708787 Iustin Pop
    data.append([dev["physical_id"]])
1115 f965260c Michael Hanselmann
1116 f965260c Michael Hanselmann
  if dev["pstatus"]:
1117 19708787 Iustin Pop
    data.append(("on primary", helper(dev["dev_type"], dev["pstatus"])))
1118 f965260c Michael Hanselmann
1119 f965260c Michael Hanselmann
  if dev["sstatus"]:
1120 19708787 Iustin Pop
    data.append(("on secondary", helper(dev["dev_type"], dev["sstatus"])))
1121 a8083063 Iustin Pop
1122 a8083063 Iustin Pop
  if dev["children"]:
1123 19708787 Iustin Pop
    data.append("child devices:")
1124 19708787 Iustin Pop
    for c_idx, child in enumerate(dev["children"]):
1125 f965260c Michael Hanselmann
      data.append(_FormatBlockDevInfo(c_idx, False, child, roman))
1126 19708787 Iustin Pop
  d1.append(data)
1127 19708787 Iustin Pop
  return d1
1128 a8083063 Iustin Pop
1129 a8083063 Iustin Pop
1130 19708787 Iustin Pop
def _FormatList(buf, data, indent_level):
1131 19708787 Iustin Pop
  """Formats a list of data at a given indent level.
1132 19708787 Iustin Pop

1133 19708787 Iustin Pop
  If the element of the list is:
1134 19708787 Iustin Pop
    - a string, it is simply formatted as is
1135 19708787 Iustin Pop
    - a tuple, it will be split into key, value and the all the
1136 19708787 Iustin Pop
      values in a list will be aligned all at the same start column
1137 19708787 Iustin Pop
    - a list, will be recursively formatted
1138 19708787 Iustin Pop

1139 19708787 Iustin Pop
  @type buf: StringIO
1140 19708787 Iustin Pop
  @param buf: the buffer into which we write the output
1141 19708787 Iustin Pop
  @param data: the list to format
1142 19708787 Iustin Pop
  @type indent_level: int
1143 19708787 Iustin Pop
  @param indent_level: the indent level to format at
1144 19708787 Iustin Pop

1145 19708787 Iustin Pop
  """
1146 19708787 Iustin Pop
  max_tlen = max([len(elem[0]) for elem in data
1147 19708787 Iustin Pop
                 if isinstance(elem, tuple)] or [0])
1148 19708787 Iustin Pop
  for elem in data:
1149 19708787 Iustin Pop
    if isinstance(elem, basestring):
1150 e687ec01 Michael Hanselmann
      buf.write("%*s%s\n" % (2 * indent_level, "", elem))
1151 19708787 Iustin Pop
    elif isinstance(elem, tuple):
1152 19708787 Iustin Pop
      key, value = elem
1153 19708787 Iustin Pop
      spacer = "%*s" % (max_tlen - len(key), "")
1154 e687ec01 Michael Hanselmann
      buf.write("%*s%s:%s %s\n" % (2 * indent_level, "", key, spacer, value))
1155 19708787 Iustin Pop
    elif isinstance(elem, list):
1156 e687ec01 Michael Hanselmann
      _FormatList(buf, elem, indent_level + 1)
1157 19708787 Iustin Pop
1158 98825740 Michael Hanselmann
1159 a8083063 Iustin Pop
def ShowInstanceConfig(opts, args):
1160 a8083063 Iustin Pop
  """Compute instance run-time status.
1161 a8083063 Iustin Pop

1162 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1163 7232c04c Iustin Pop
  @type args: list
1164 7232c04c Iustin Pop
  @param args: either an empty list, and then we query all
1165 7232c04c Iustin Pop
      instances, or should contain a list of instance names
1166 7232c04c Iustin Pop
  @rtype: int
1167 7232c04c Iustin Pop
  @return: the desired exit code
1168 7232c04c Iustin Pop

1169 a8083063 Iustin Pop
  """
1170 220cde0b Guido Trotter
  if not args and not opts.show_all:
1171 220cde0b Guido Trotter
    ToStderr("No instance selected."
1172 220cde0b Guido Trotter
             " Please pass in --all if you want to query all instances.\n"
1173 220cde0b Guido Trotter
             "Note that this can take a long time on a big cluster.")
1174 220cde0b Guido Trotter
    return 1
1175 220cde0b Guido Trotter
  elif args and opts.show_all:
1176 220cde0b Guido Trotter
    ToStderr("Cannot use --all if you specify instance names.")
1177 220cde0b Guido Trotter
    return 1
1178 220cde0b Guido Trotter
1179 a8083063 Iustin Pop
  retcode = 0
1180 5c097318 Iustin Pop
  op = opcodes.OpInstanceQueryData(instances=args, static=opts.static,
1181 5c097318 Iustin Pop
                                   use_locking=not opts.static)
1182 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
1183 a8083063 Iustin Pop
  if not result:
1184 3a24c527 Iustin Pop
    ToStdout("No instances.")
1185 a8083063 Iustin Pop
    return 1
1186 a8083063 Iustin Pop
1187 a8083063 Iustin Pop
  buf = StringIO()
1188 a8083063 Iustin Pop
  retcode = 0
1189 a8083063 Iustin Pop
  for instance_name in result:
1190 a8083063 Iustin Pop
    instance = result[instance_name]
1191 a8083063 Iustin Pop
    buf.write("Instance name: %s\n" % instance["name"])
1192 033d58b0 Iustin Pop
    buf.write("UUID: %s\n" % instance["uuid"])
1193 e2736e40 Guido Trotter
    buf.write("Serial number: %s\n" %
1194 e2736e40 Guido Trotter
              compat.TryToRoman(instance["serial_no"],
1195 e2736e40 Guido Trotter
                                convert=opts.roman_integers))
1196 90f72445 Iustin Pop
    buf.write("Creation time: %s\n" % utils.FormatTime(instance["ctime"]))
1197 90f72445 Iustin Pop
    buf.write("Modification time: %s\n" % utils.FormatTime(instance["mtime"]))
1198 57821cac Iustin Pop
    buf.write("State: configured to be %s" % instance["config_state"])
1199 f965260c Michael Hanselmann
    if instance["run_state"]:
1200 57821cac Iustin Pop
      buf.write(", actual state is %s" % instance["run_state"])
1201 57821cac Iustin Pop
    buf.write("\n")
1202 57821cac Iustin Pop
    ##buf.write("Considered for memory checks in cluster verify: %s\n" %
1203 57821cac Iustin Pop
    ##          instance["auto_balance"])
1204 a8083063 Iustin Pop
    buf.write("  Nodes:\n")
1205 a8083063 Iustin Pop
    buf.write("    - primary: %s\n" % instance["pnode"])
1206 1f864b60 Iustin Pop
    buf.write("    - secondaries: %s\n" % utils.CommaJoin(instance["snodes"]))
1207 a8083063 Iustin Pop
    buf.write("  Operating system: %s\n" % instance["os"])
1208 acd19189 René Nussbaumer
    FormatParameterDict(buf, instance["os_instance"], instance["os_actual"],
1209 acd19189 René Nussbaumer
                        level=2)
1210 e687ec01 Michael Hanselmann
    if "network_port" in instance:
1211 e2736e40 Guido Trotter
      buf.write("  Allocated network port: %s\n" %
1212 e2736e40 Guido Trotter
                compat.TryToRoman(instance["network_port"],
1213 e2736e40 Guido Trotter
                                  convert=opts.roman_integers))
1214 24838135 Iustin Pop
    buf.write("  Hypervisor: %s\n" % instance["hypervisor"])
1215 dfff41f8 Guido Trotter
1216 dfff41f8 Guido Trotter
    # custom VNC console information
1217 dfff41f8 Guido Trotter
    vnc_bind_address = instance["hv_actual"].get(constants.HV_VNC_BIND_ADDRESS,
1218 dfff41f8 Guido Trotter
                                                 None)
1219 dfff41f8 Guido Trotter
    if vnc_bind_address:
1220 dfff41f8 Guido Trotter
      port = instance["network_port"]
1221 dfff41f8 Guido Trotter
      display = int(port) - constants.VNC_BASE_PORT
1222 9769bb78 Manuel Franceschini
      if display > 0 and vnc_bind_address == constants.IP4_ADDRESS_ANY:
1223 dfff41f8 Guido Trotter
        vnc_console_port = "%s:%s (display %s)" % (instance["pnode"],
1224 dfff41f8 Guido Trotter
                                                   port,
1225 dfff41f8 Guido Trotter
                                                   display)
1226 8b312c1d Manuel Franceschini
      elif display > 0 and netutils.IP4Address.IsValid(vnc_bind_address):
1227 dfff41f8 Guido Trotter
        vnc_console_port = ("%s:%s (node %s) (display %s)" %
1228 dfff41f8 Guido Trotter
                             (vnc_bind_address, port,
1229 dfff41f8 Guido Trotter
                              instance["pnode"], display))
1230 a8340917 Iustin Pop
      else:
1231 dfff41f8 Guido Trotter
        # vnc bind address is a file
1232 dfff41f8 Guido Trotter
        vnc_console_port = "%s:%s" % (instance["pnode"],
1233 dfff41f8 Guido Trotter
                                      vnc_bind_address)
1234 24838135 Iustin Pop
      buf.write("    - console connection: vnc to %s\n" % vnc_console_port)
1235 24838135 Iustin Pop
1236 acd19189 René Nussbaumer
    FormatParameterDict(buf, instance["hv_instance"], instance["hv_actual"],
1237 acd19189 René Nussbaumer
                        level=2)
1238 a8083063 Iustin Pop
    buf.write("  Hardware:\n")
1239 e2736e40 Guido Trotter
    buf.write("    - VCPUs: %s\n" %
1240 e2736e40 Guido Trotter
              compat.TryToRoman(instance["be_actual"][constants.BE_VCPUS],
1241 e2736e40 Guido Trotter
                                convert=opts.roman_integers))
1242 b5ef2316 Guido Trotter
    buf.write("    - maxmem: %sMiB\n" %
1243 b5ef2316 Guido Trotter
              compat.TryToRoman(instance["be_actual"][constants.BE_MAXMEM],
1244 b5ef2316 Guido Trotter
                                convert=opts.roman_integers))
1245 b5ef2316 Guido Trotter
    buf.write("    - minmem: %sMiB\n" %
1246 b5ef2316 Guido Trotter
              compat.TryToRoman(instance["be_actual"][constants.BE_MINMEM],
1247 b5ef2316 Guido Trotter
                                convert=opts.roman_integers))
1248 b5ef2316 Guido Trotter
    # deprecated "memory" value, kept for one version for compatibility
1249 b5ef2316 Guido Trotter
    # TODO(ganeti 2.7) remove.
1250 e2736e40 Guido Trotter
    buf.write("    - memory: %sMiB\n" %
1251 b5ef2316 Guido Trotter
              compat.TryToRoman(instance["be_actual"][constants.BE_MAXMEM],
1252 e2736e40 Guido Trotter
                                convert=opts.roman_integers))
1253 11dc66f3 Bernardo Dal Seno
    buf.write("    - %s: %s\n" %
1254 11dc66f3 Bernardo Dal Seno
              (constants.BE_ALWAYS_FAILOVER,
1255 11dc66f3 Bernardo Dal Seno
               instance["be_actual"][constants.BE_ALWAYS_FAILOVER]))
1256 d2acfe27 Iustin Pop
    buf.write("    - NICs:\n")
1257 14ea9302 Guido Trotter
    for idx, (ip, mac, mode, link) in enumerate(instance["nics"]):
1258 0b13832c Guido Trotter
      buf.write("      - nic/%d: MAC: %s, IP: %s, mode: %s, link: %s\n" %
1259 0b13832c Guido Trotter
                (idx, mac, ip, mode, link))
1260 b577dac4 Michael Hanselmann
    buf.write("  Disk template: %s\n" % instance["disk_template"])
1261 19708787 Iustin Pop
    buf.write("  Disks:\n")
1262 a8083063 Iustin Pop
1263 19708787 Iustin Pop
    for idx, device in enumerate(instance["disks"]):
1264 f965260c Michael Hanselmann
      _FormatList(buf, _FormatBlockDevInfo(idx, True, device,
1265 e2736e40 Guido Trotter
                  opts.roman_integers), 2)
1266 a8083063 Iustin Pop
1267 d0c8c01d Iustin Pop
  ToStdout(buf.getvalue().rstrip("\n"))
1268 a8083063 Iustin Pop
  return retcode
1269 a8083063 Iustin Pop
1270 a8083063 Iustin Pop
1271 a71f835e Michael Hanselmann
def _ConvertNicDiskModifications(mods):
1272 a71f835e Michael Hanselmann
  """Converts NIC/disk modifications from CLI to opcode.
1273 a71f835e Michael Hanselmann

1274 a71f835e Michael Hanselmann
  When L{opcodes.OpInstanceSetParams} was changed to support adding/removing
1275 a71f835e Michael Hanselmann
  disks at arbitrary indices, its parameter format changed. This function
1276 a71f835e Michael Hanselmann
  converts legacy requests (e.g. "--net add" or "--disk add:size=4G") to the
1277 a71f835e Michael Hanselmann
  newer format and adds support for new-style requests (e.g. "--new 4:add").
1278 a71f835e Michael Hanselmann

1279 a71f835e Michael Hanselmann
  @type mods: list of tuples
1280 a71f835e Michael Hanselmann
  @param mods: Modifications as given by command line parser
1281 a71f835e Michael Hanselmann
  @rtype: list of tuples
1282 a71f835e Michael Hanselmann
  @return: Modifications as understood by L{opcodes.OpInstanceSetParams}
1283 a71f835e Michael Hanselmann

1284 a71f835e Michael Hanselmann
  """
1285 a71f835e Michael Hanselmann
  result = []
1286 a71f835e Michael Hanselmann
1287 a71f835e Michael Hanselmann
  for (idx, params) in mods:
1288 a71f835e Michael Hanselmann
    if idx == constants.DDM_ADD:
1289 a71f835e Michael Hanselmann
      # Add item as last item (legacy interface)
1290 a71f835e Michael Hanselmann
      action = constants.DDM_ADD
1291 a71f835e Michael Hanselmann
      idxno = -1
1292 a71f835e Michael Hanselmann
    elif idx == constants.DDM_REMOVE:
1293 a71f835e Michael Hanselmann
      # Remove last item (legacy interface)
1294 a71f835e Michael Hanselmann
      action = constants.DDM_REMOVE
1295 a71f835e Michael Hanselmann
      idxno = -1
1296 a71f835e Michael Hanselmann
    else:
1297 a71f835e Michael Hanselmann
      # Modifications and adding/removing at arbitrary indices
1298 a71f835e Michael Hanselmann
      try:
1299 a71f835e Michael Hanselmann
        idxno = int(idx)
1300 a71f835e Michael Hanselmann
      except (TypeError, ValueError):
1301 a71f835e Michael Hanselmann
        raise errors.OpPrereqError("Non-numeric index '%s'" % idx,
1302 a71f835e Michael Hanselmann
                                   errors.ECODE_INVAL)
1303 a71f835e Michael Hanselmann
1304 a71f835e Michael Hanselmann
      add = params.pop(constants.DDM_ADD, _MISSING)
1305 a71f835e Michael Hanselmann
      remove = params.pop(constants.DDM_REMOVE, _MISSING)
1306 a71f835e Michael Hanselmann
1307 a71f835e Michael Hanselmann
      if not (add is _MISSING or remove is _MISSING):
1308 a71f835e Michael Hanselmann
        raise errors.OpPrereqError("Cannot add and remove at the same time",
1309 a71f835e Michael Hanselmann
                                   errors.ECODE_INVAL)
1310 a71f835e Michael Hanselmann
      elif add is not _MISSING:
1311 a71f835e Michael Hanselmann
        action = constants.DDM_ADD
1312 a71f835e Michael Hanselmann
      elif remove is not _MISSING:
1313 a71f835e Michael Hanselmann
        action = constants.DDM_REMOVE
1314 a71f835e Michael Hanselmann
      else:
1315 a71f835e Michael Hanselmann
        action = constants.DDM_MODIFY
1316 a71f835e Michael Hanselmann
1317 a71f835e Michael Hanselmann
      assert not (constants.DDMS_VALUES_WITH_MODIFY & set(params.keys()))
1318 a71f835e Michael Hanselmann
1319 a71f835e Michael Hanselmann
    if action == constants.DDM_REMOVE and params:
1320 a71f835e Michael Hanselmann
      raise errors.OpPrereqError("Not accepting parameters on removal",
1321 a71f835e Michael Hanselmann
                                 errors.ECODE_INVAL)
1322 a71f835e Michael Hanselmann
1323 a71f835e Michael Hanselmann
    result.append((action, idxno, params))
1324 a71f835e Michael Hanselmann
1325 a71f835e Michael Hanselmann
  return result
1326 a71f835e Michael Hanselmann
1327 a71f835e Michael Hanselmann
1328 a71f835e Michael Hanselmann
def _ParseDiskSizes(mods):
1329 a71f835e Michael Hanselmann
  """Parses disk sizes in parameters.
1330 a71f835e Michael Hanselmann

1331 a71f835e Michael Hanselmann
  """
1332 a71f835e Michael Hanselmann
  for (action, _, params) in mods:
1333 a71f835e Michael Hanselmann
    if params and constants.IDISK_SIZE in params:
1334 a71f835e Michael Hanselmann
      params[constants.IDISK_SIZE] = \
1335 a71f835e Michael Hanselmann
        utils.ParseUnit(params[constants.IDISK_SIZE])
1336 a71f835e Michael Hanselmann
    elif action == constants.DDM_ADD:
1337 a71f835e Michael Hanselmann
      raise errors.OpPrereqError("Missing required parameter 'size'",
1338 a71f835e Michael Hanselmann
                                 errors.ECODE_INVAL)
1339 a71f835e Michael Hanselmann
1340 a71f835e Michael Hanselmann
  return mods
1341 a71f835e Michael Hanselmann
1342 a71f835e Michael Hanselmann
1343 7767bbf5 Manuel Franceschini
def SetInstanceParams(opts, args):
1344 a8083063 Iustin Pop
  """Modifies an instance.
1345 a8083063 Iustin Pop

1346 a8083063 Iustin Pop
  All parameters take effect only at the next restart of the instance.
1347 a8083063 Iustin Pop

1348 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1349 7232c04c Iustin Pop
  @type args: list
1350 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
1351 7232c04c Iustin Pop
  @rtype: int
1352 7232c04c Iustin Pop
  @return: the desired exit code
1353 a8083063 Iustin Pop

1354 a8083063 Iustin Pop
  """
1355 e29e9550 Iustin Pop
  if not (opts.nics or opts.disks or opts.disk_template or
1356 57de31c0 Agata Murawska
          opts.hvparams or opts.beparams or opts.os or opts.osparams or
1357 2c0af7da Guido Trotter
          opts.offline_inst or opts.online_inst or opts.runtime_mem):
1358 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
1359 a8083063 Iustin Pop
    return 1
1360 a8083063 Iustin Pop
1361 467ae11e Guido Trotter
  for param in opts.beparams:
1362 e9d622bc Guido Trotter
    if isinstance(opts.beparams[param], basestring):
1363 e9d622bc Guido Trotter
      if opts.beparams[param].lower() == "default":
1364 e9d622bc Guido Trotter
        opts.beparams[param] = constants.VALUE_DEFAULT
1365 a5728081 Guido Trotter
1366 b2e233a5 Guido Trotter
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_COMPAT,
1367 a5728081 Guido Trotter
                      allowed_values=[constants.VALUE_DEFAULT])
1368 467ae11e Guido Trotter
1369 48f212d7 Iustin Pop
  for param in opts.hvparams:
1370 48f212d7 Iustin Pop
    if isinstance(opts.hvparams[param], basestring):
1371 48f212d7 Iustin Pop
      if opts.hvparams[param].lower() == "default":
1372 48f212d7 Iustin Pop
        opts.hvparams[param] = constants.VALUE_DEFAULT
1373 a5728081 Guido Trotter
1374 48f212d7 Iustin Pop
  utils.ForceDictType(opts.hvparams, constants.HVS_PARAMETER_TYPES,
1375 a5728081 Guido Trotter
                      allowed_values=[constants.VALUE_DEFAULT])
1376 61be6ba4 Iustin Pop
1377 a71f835e Michael Hanselmann
  nics = _ConvertNicDiskModifications(opts.nics)
1378 a71f835e Michael Hanselmann
  disks = _ParseDiskSizes(_ConvertNicDiskModifications(opts.disks))
1379 24991749 Iustin Pop
1380 e29e9550 Iustin Pop
  if (opts.disk_template and
1381 3429a076 Apollon Oikonomopoulos
      opts.disk_template in constants.DTS_INT_MIRROR and
1382 e29e9550 Iustin Pop
      not opts.node):
1383 e29e9550 Iustin Pop
    ToStderr("Changing the disk template to a mirrored one requires"
1384 e29e9550 Iustin Pop
             " specifying a secondary node")
1385 e29e9550 Iustin Pop
    return 1
1386 e29e9550 Iustin Pop
1387 3016bc1f Michael Hanselmann
  if opts.offline_inst:
1388 3016bc1f Michael Hanselmann
    offline = True
1389 3016bc1f Michael Hanselmann
  elif opts.online_inst:
1390 3016bc1f Michael Hanselmann
    offline = False
1391 3016bc1f Michael Hanselmann
  else:
1392 3016bc1f Michael Hanselmann
    offline = None
1393 3016bc1f Michael Hanselmann
1394 9a3cc7ae Iustin Pop
  op = opcodes.OpInstanceSetParams(instance_name=args[0],
1395 a71f835e Michael Hanselmann
                                   nics=nics,
1396 a71f835e Michael Hanselmann
                                   disks=disks,
1397 e29e9550 Iustin Pop
                                   disk_template=opts.disk_template,
1398 e29e9550 Iustin Pop
                                   remote_node=opts.node,
1399 48f212d7 Iustin Pop
                                   hvparams=opts.hvparams,
1400 338e51e8 Iustin Pop
                                   beparams=opts.beparams,
1401 2c0af7da Guido Trotter
                                   runtime_mem=opts.runtime_mem,
1402 96b39bcc Iustin Pop
                                   os_name=opts.os,
1403 1052d622 Iustin Pop
                                   osparams=opts.osparams,
1404 96b39bcc Iustin Pop
                                   force_variant=opts.force_variant,
1405 456798ab Iustin Pop
                                   force=opts.force,
1406 57de31c0 Agata Murawska
                                   wait_for_sync=opts.wait_for_sync,
1407 3016bc1f Michael Hanselmann
                                   offline=offline,
1408 1559e1e7 René Nussbaumer
                                   ignore_ipolicy=opts.ignore_ipolicy)
1409 31a853d2 Iustin Pop
1410 6340bb0a Iustin Pop
  # even if here we process the result, we allow submit only
1411 6340bb0a Iustin Pop
  result = SubmitOrSend(op, opts)
1412 a8083063 Iustin Pop
1413 a8083063 Iustin Pop
  if result:
1414 3a24c527 Iustin Pop
    ToStdout("Modified instance %s", args[0])
1415 a8083063 Iustin Pop
    for param, data in result:
1416 3a24c527 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
1417 e29e9550 Iustin Pop
    ToStdout("Please don't forget that most parameters take effect"
1418 3a24c527 Iustin Pop
             " only at the next start of the instance.")
1419 a8083063 Iustin Pop
  return 0
1420 a8083063 Iustin Pop
1421 a8083063 Iustin Pop
1422 bd2a5569 Michael Hanselmann
def ChangeGroup(opts, args):
1423 bd2a5569 Michael Hanselmann
  """Moves an instance to another group.
1424 bd2a5569 Michael Hanselmann

1425 bd2a5569 Michael Hanselmann
  """
1426 bd2a5569 Michael Hanselmann
  (instance_name, ) = args
1427 bd2a5569 Michael Hanselmann
1428 bd2a5569 Michael Hanselmann
  cl = GetClient()
1429 bd2a5569 Michael Hanselmann
1430 bd2a5569 Michael Hanselmann
  op = opcodes.OpInstanceChangeGroup(instance_name=instance_name,
1431 bd2a5569 Michael Hanselmann
                                     iallocator=opts.iallocator,
1432 bd2a5569 Michael Hanselmann
                                     target_groups=opts.to,
1433 bd2a5569 Michael Hanselmann
                                     early_release=opts.early_release)
1434 bd2a5569 Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
1435 bd2a5569 Michael Hanselmann
1436 bd2a5569 Michael Hanselmann
  # Keep track of submitted jobs
1437 bd2a5569 Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
1438 bd2a5569 Michael Hanselmann
1439 bd2a5569 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
1440 bd2a5569 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
1441 bd2a5569 Michael Hanselmann
1442 bd2a5569 Michael Hanselmann
  results = jex.GetResults()
1443 bd2a5569 Michael Hanselmann
  bad_cnt = len([row for row in results if not row[0]])
1444 bd2a5569 Michael Hanselmann
  if bad_cnt == 0:
1445 bd2a5569 Michael Hanselmann
    ToStdout("Instance '%s' changed group successfully.", instance_name)
1446 bd2a5569 Michael Hanselmann
    rcode = constants.EXIT_SUCCESS
1447 bd2a5569 Michael Hanselmann
  else:
1448 bd2a5569 Michael Hanselmann
    ToStdout("There were %s errors while changing group of instance '%s'.",
1449 bd2a5569 Michael Hanselmann
             bad_cnt, instance_name)
1450 bd2a5569 Michael Hanselmann
    rcode = constants.EXIT_FAILURE
1451 bd2a5569 Michael Hanselmann
1452 bd2a5569 Michael Hanselmann
  return rcode
1453 bd2a5569 Michael Hanselmann
1454 bd2a5569 Michael Hanselmann
1455 312ac745 Iustin Pop
# multi-instance selection options
1456 c38c44ad Michael Hanselmann
m_force_multi = cli_option("--force-multiple", dest="force_multi",
1457 c38c44ad Michael Hanselmann
                           help="Do not ask for confirmation when more than"
1458 c38c44ad Michael Hanselmann
                           " one instance is affected",
1459 c38c44ad Michael Hanselmann
                           action="store_true", default=False)
1460 804a1e8e Iustin Pop
1461 c38c44ad Michael Hanselmann
m_pri_node_opt = cli_option("--primary", dest="multi_mode",
1462 c38c44ad Michael Hanselmann
                            help="Filter by nodes (primary only)",
1463 c20efaa8 Michael Hanselmann
                            const=_EXPAND_NODES_PRI, action="store_const")
1464 312ac745 Iustin Pop
1465 c38c44ad Michael Hanselmann
m_sec_node_opt = cli_option("--secondary", dest="multi_mode",
1466 c38c44ad Michael Hanselmann
                            help="Filter by nodes (secondary only)",
1467 c20efaa8 Michael Hanselmann
                            const=_EXPAND_NODES_SEC, action="store_const")
1468 312ac745 Iustin Pop
1469 c38c44ad Michael Hanselmann
m_node_opt = cli_option("--node", dest="multi_mode",
1470 c38c44ad Michael Hanselmann
                        help="Filter by nodes (primary and secondary)",
1471 c20efaa8 Michael Hanselmann
                        const=_EXPAND_NODES_BOTH, action="store_const")
1472 312ac745 Iustin Pop
1473 c38c44ad Michael Hanselmann
m_clust_opt = cli_option("--all", dest="multi_mode",
1474 c38c44ad Michael Hanselmann
                         help="Select all instances in the cluster",
1475 c20efaa8 Michael Hanselmann
                         const=_EXPAND_CLUSTER, action="store_const")
1476 312ac745 Iustin Pop
1477 c38c44ad Michael Hanselmann
m_inst_opt = cli_option("--instance", dest="multi_mode",
1478 c38c44ad Michael Hanselmann
                        help="Filter by instance name [default]",
1479 c20efaa8 Michael Hanselmann
                        const=_EXPAND_INSTANCES, action="store_const")
1480 312ac745 Iustin Pop
1481 39dfd93e René Nussbaumer
m_node_tags_opt = cli_option("--node-tags", dest="multi_mode",
1482 39dfd93e René Nussbaumer
                             help="Filter by node tag",
1483 c20efaa8 Michael Hanselmann
                             const=_EXPAND_NODES_BOTH_BY_TAGS,
1484 39dfd93e René Nussbaumer
                             action="store_const")
1485 39dfd93e René Nussbaumer
1486 39dfd93e René Nussbaumer
m_pri_node_tags_opt = cli_option("--pri-node-tags", dest="multi_mode",
1487 39dfd93e René Nussbaumer
                                 help="Filter by primary node tag",
1488 c20efaa8 Michael Hanselmann
                                 const=_EXPAND_NODES_PRI_BY_TAGS,
1489 39dfd93e René Nussbaumer
                                 action="store_const")
1490 39dfd93e René Nussbaumer
1491 39dfd93e René Nussbaumer
m_sec_node_tags_opt = cli_option("--sec-node-tags", dest="multi_mode",
1492 39dfd93e René Nussbaumer
                                 help="Filter by secondary node tag",
1493 c20efaa8 Michael Hanselmann
                                 const=_EXPAND_NODES_SEC_BY_TAGS,
1494 39dfd93e René Nussbaumer
                                 action="store_const")
1495 39dfd93e René Nussbaumer
1496 39dfd93e René Nussbaumer
m_inst_tags_opt = cli_option("--tags", dest="multi_mode",
1497 39dfd93e René Nussbaumer
                             help="Filter by instance tag",
1498 c20efaa8 Michael Hanselmann
                             const=_EXPAND_INSTANCES_BY_TAGS,
1499 39dfd93e René Nussbaumer
                             action="store_const")
1500 312ac745 Iustin Pop
1501 a8083063 Iustin Pop
# this is defined separately due to readability only
1502 a8083063 Iustin Pop
add_opts = [
1503 064c21f8 Iustin Pop
  NOSTART_OPT,
1504 064c21f8 Iustin Pop
  OS_OPT,
1505 06073e85 Guido Trotter
  FORCE_VARIANT_OPT,
1506 25a8792c Iustin Pop
  NO_INSTALL_OPT,
1507 10889e0c René Nussbaumer
  IGNORE_IPOLICY_OPT,
1508 a8083063 Iustin Pop
  ]
1509 a8083063 Iustin Pop
1510 a8083063 Iustin Pop
commands = {
1511 d0c8c01d Iustin Pop
  "add": (
1512 eb28ecf6 Guido Trotter
    AddInstance, [ArgHost(min=1, max=1)], COMMON_CREATE_OPTS + add_opts,
1513 6ea815cf Iustin Pop
    "[...] -t disk-type -n node[:secondary-node] -o os-type <name>",
1514 6ea815cf Iustin Pop
    "Creates and adds a new instance to the cluster"),
1515 d0c8c01d Iustin Pop
  "batch-create": (
1516 aa06f8c6 Michael Hanselmann
    BatchCreate, [ArgFile(min=1, max=1)], [DRY_RUN_OPT, PRIORITY_OPT],
1517 6ea815cf Iustin Pop
    "<instances.json>",
1518 6ea815cf Iustin Pop
    "Create a bunch of instances based on specs in the file."),
1519 d0c8c01d Iustin Pop
  "console": (
1520 6ea815cf Iustin Pop
    ConnectToInstanceConsole, ARGS_ONE_INSTANCE,
1521 aa06f8c6 Michael Hanselmann
    [SHOWCMD_OPT, PRIORITY_OPT],
1522 6ea815cf Iustin Pop
    "[--show-cmd] <instance>", "Opens a console on the specified instance"),
1523 d0c8c01d Iustin Pop
  "failover": (
1524 6ea815cf Iustin Pop
    FailoverInstance, ARGS_ONE_INSTANCE,
1525 db5a8a2d Iustin Pop
    [FORCE_OPT, IGNORE_CONSIST_OPT, SUBMIT_OPT, SHUTDOWN_TIMEOUT_OPT,
1526 b6aaf437 René Nussbaumer
     DRY_RUN_OPT, PRIORITY_OPT, DST_NODE_OPT, IALLOCATOR_OPT,
1527 b6aaf437 René Nussbaumer
     IGNORE_IPOLICY_OPT],
1528 a6a3efe4 Iustin Pop
    "[-f] <instance>", "Stops the instance, changes its primary node and"
1529 a6a3efe4 Iustin Pop
    " (if it was originally running) starts it on the new node"
1530 a6a3efe4 Iustin Pop
    " (the secondary for mirrored instances or any node"
1531 a6a3efe4 Iustin Pop
    " for shared storage)."),
1532 d0c8c01d Iustin Pop
  "migrate": (
1533 6ea815cf Iustin Pop
    MigrateInstance, ARGS_ONE_INSTANCE,
1534 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, NONLIVE_OPT, MIGRATION_MODE_OPT, CLEANUP_OPT, DRY_RUN_OPT,
1535 3ed23330 René Nussbaumer
     PRIORITY_OPT, DST_NODE_OPT, IALLOCATOR_OPT, ALLOW_FAILOVER_OPT,
1536 8c0b16f6 Guido Trotter
     IGNORE_IPOLICY_OPT, NORUNTIME_CHGS_OPT],
1537 6ea815cf Iustin Pop
    "[-f] <instance>", "Migrate instance to its secondary node"
1538 1b7761fd Apollon Oikonomopoulos
    " (only for mirrored instances)"),
1539 d0c8c01d Iustin Pop
  "move": (
1540 6ea815cf Iustin Pop
    MoveInstance, ARGS_ONE_INSTANCE,
1541 db5a8a2d Iustin Pop
    [FORCE_OPT, SUBMIT_OPT, SINGLE_NODE_OPT, SHUTDOWN_TIMEOUT_OPT,
1542 92cf62e3 René Nussbaumer
     DRY_RUN_OPT, PRIORITY_OPT, IGNORE_CONSIST_OPT, IGNORE_IPOLICY_OPT],
1543 6ea815cf Iustin Pop
    "[-f] <instance>", "Move instance to an arbitrary node"
1544 6ea815cf Iustin Pop
    " (only for instances of type file and lv)"),
1545 d0c8c01d Iustin Pop
  "info": (
1546 6ea815cf Iustin Pop
    ShowInstanceConfig, ARGS_MANY_INSTANCES,
1547 aa06f8c6 Michael Hanselmann
    [STATIC_OPT, ALL_OPT, ROMAN_OPT, PRIORITY_OPT],
1548 6ea815cf Iustin Pop
    "[-s] {--all | <instance>...}",
1549 6ea815cf Iustin Pop
    "Show information on the specified instance(s)"),
1550 d0c8c01d Iustin Pop
  "list": (
1551 6ea815cf Iustin Pop
    ListInstances, ARGS_MANY_INSTANCES,
1552 87e87959 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, VERBOSE_OPT,
1553 87e87959 Michael Hanselmann
     FORCE_FILTER_OPT],
1554 6ea815cf Iustin Pop
    "[<instance>...]",
1555 b82c5ff5 Michael Hanselmann
    "Lists the instances and their status. The available fields can be shown"
1556 b82c5ff5 Michael Hanselmann
    " using the \"list-fields\" command (see the man page for details)."
1557 b82c5ff5 Michael Hanselmann
    " The default field list is (in order): %s." %
1558 b82c5ff5 Michael Hanselmann
    utils.CommaJoin(_LIST_DEF_FIELDS),
1559 6ea815cf Iustin Pop
    ),
1560 b82c5ff5 Michael Hanselmann
  "list-fields": (
1561 b82c5ff5 Michael Hanselmann
    ListInstanceFields, [ArgUnknown()],
1562 b82c5ff5 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT],
1563 b82c5ff5 Michael Hanselmann
    "[fields...]",
1564 b82c5ff5 Michael Hanselmann
    "Lists all available fields for instances"),
1565 d0c8c01d Iustin Pop
  "reinstall": (
1566 3e54ace7 Iustin Pop
    ReinstallInstance, [ArgInstance()],
1567 06073e85 Guido Trotter
    [FORCE_OPT, OS_OPT, FORCE_VARIANT_OPT, m_force_multi, m_node_opt,
1568 39dfd93e René Nussbaumer
     m_pri_node_opt, m_sec_node_opt, m_clust_opt, m_inst_opt, m_node_tags_opt,
1569 39dfd93e René Nussbaumer
     m_pri_node_tags_opt, m_sec_node_tags_opt, m_inst_tags_opt, SELECT_OS_OPT,
1570 8d8c4eff Michael Hanselmann
     SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT, OSPARAMS_OPT],
1571 6ea815cf Iustin Pop
    "[-f] <instance>", "Reinstall a stopped instance"),
1572 d0c8c01d Iustin Pop
  "remove": (
1573 6ea815cf Iustin Pop
    RemoveInstance, ARGS_ONE_INSTANCE,
1574 db5a8a2d Iustin Pop
    [FORCE_OPT, SHUTDOWN_TIMEOUT_OPT, IGNORE_FAILURES_OPT, SUBMIT_OPT,
1575 aa06f8c6 Michael Hanselmann
     DRY_RUN_OPT, PRIORITY_OPT],
1576 6ea815cf Iustin Pop
    "[-f] <instance>", "Shuts down the instance and removes it"),
1577 d0c8c01d Iustin Pop
  "rename": (
1578 6ea815cf Iustin Pop
    RenameInstance,
1579 6ea815cf Iustin Pop
    [ArgInstance(min=1, max=1), ArgHost(min=1, max=1)],
1580 aa06f8c6 Michael Hanselmann
    [NOIPCHECK_OPT, NONAMECHECK_OPT, SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1581 6ea815cf Iustin Pop
    "<instance> <new_name>", "Rename the instance"),
1582 d0c8c01d Iustin Pop
  "replace-disks": (
1583 6ea815cf Iustin Pop
    ReplaceDisks, ARGS_ONE_INSTANCE,
1584 7ea7bcf6 Iustin Pop
    [AUTO_REPLACE_OPT, DISKIDX_OPT, IALLOCATOR_OPT, EARLY_RELEASE_OPT,
1585 db5a8a2d Iustin Pop
     NEW_SECONDARY_OPT, ON_PRIMARY_OPT, ON_SECONDARY_OPT, SUBMIT_OPT,
1586 893e8f49 René Nussbaumer
     DRY_RUN_OPT, PRIORITY_OPT, IGNORE_IPOLICY_OPT],
1587 6ea815cf Iustin Pop
    "[-s|-p|-n NODE|-I NAME] <instance>",
1588 6ea815cf Iustin Pop
    "Replaces all disks for the instance"),
1589 d0c8c01d Iustin Pop
  "modify": (
1590 6ea815cf Iustin Pop
    SetInstanceParams, ARGS_ONE_INSTANCE,
1591 e29e9550 Iustin Pop
    [BACKEND_OPT, DISK_OPT, FORCE_OPT, HVOPTS_OPT, NET_OPT, SUBMIT_OPT,
1592 1052d622 Iustin Pop
     DISK_TEMPLATE_OPT, SINGLE_NODE_OPT, OS_OPT, FORCE_VARIANT_OPT,
1593 57de31c0 Agata Murawska
     OSPARAMS_OPT, DRY_RUN_OPT, PRIORITY_OPT, NWSYNC_OPT, OFFLINE_INST_OPT,
1594 2c0af7da Guido Trotter
     ONLINE_INST_OPT, IGNORE_IPOLICY_OPT, RUNTIME_MEM_OPT],
1595 6ea815cf Iustin Pop
    "<instance>", "Alters the parameters of an instance"),
1596 d0c8c01d Iustin Pop
  "shutdown": (
1597 1c5945b6 Iustin Pop
    GenericManyOps("shutdown", _ShutdownInstance), [ArgInstance()],
1598 064c21f8 Iustin Pop
    [m_node_opt, m_pri_node_opt, m_sec_node_opt, m_clust_opt,
1599 39dfd93e René Nussbaumer
     m_node_tags_opt, m_pri_node_tags_opt, m_sec_node_tags_opt,
1600 db5a8a2d Iustin Pop
     m_inst_tags_opt, m_inst_opt, m_force_multi, TIMEOUT_OPT, SUBMIT_OPT,
1601 885a0fc4 Iustin Pop
     DRY_RUN_OPT, PRIORITY_OPT, IGNORE_OFFLINE_OPT, NO_REMEMBER_OPT],
1602 6ea815cf Iustin Pop
    "<instance>", "Stops an instance"),
1603 d0c8c01d Iustin Pop
  "startup": (
1604 1c5945b6 Iustin Pop
    GenericManyOps("startup", _StartupInstance), [ArgInstance()],
1605 39dfd93e René Nussbaumer
    [FORCE_OPT, m_force_multi, m_node_opt, m_pri_node_opt, m_sec_node_opt,
1606 39dfd93e René Nussbaumer
     m_node_tags_opt, m_pri_node_tags_opt, m_sec_node_tags_opt,
1607 39dfd93e René Nussbaumer
     m_inst_tags_opt, m_clust_opt, m_inst_opt, SUBMIT_OPT, HVOPTS_OPT,
1608 885a0fc4 Iustin Pop
     BACKEND_OPT, DRY_RUN_OPT, PRIORITY_OPT, IGNORE_OFFLINE_OPT,
1609 323f9095 Stephen Shirley
     NO_REMEMBER_OPT, STARTUP_PAUSED_OPT],
1610 6ea815cf Iustin Pop
    "<instance>", "Starts an instance"),
1611 d0c8c01d Iustin Pop
  "reboot": (
1612 1c5945b6 Iustin Pop
    GenericManyOps("reboot", _RebootInstance), [ArgInstance()],
1613 064c21f8 Iustin Pop
    [m_force_multi, REBOOT_TYPE_OPT, IGNORE_SECONDARIES_OPT, m_node_opt,
1614 17c3f802 Guido Trotter
     m_pri_node_opt, m_sec_node_opt, m_clust_opt, m_inst_opt, SUBMIT_OPT,
1615 39dfd93e René Nussbaumer
     m_node_tags_opt, m_pri_node_tags_opt, m_sec_node_tags_opt,
1616 aa06f8c6 Michael Hanselmann
     m_inst_tags_opt, SHUTDOWN_TIMEOUT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1617 6ea815cf Iustin Pop
    "<instance>", "Reboots an instance"),
1618 d0c8c01d Iustin Pop
  "activate-disks": (
1619 db5a8a2d Iustin Pop
    ActivateDisks, ARGS_ONE_INSTANCE,
1620 aa06f8c6 Michael Hanselmann
    [SUBMIT_OPT, IGNORE_SIZE_OPT, PRIORITY_OPT],
1621 6ea815cf Iustin Pop
    "<instance>", "Activate an instance's disks"),
1622 d0c8c01d Iustin Pop
  "deactivate-disks": (
1623 aa06f8c6 Michael Hanselmann
    DeactivateDisks, ARGS_ONE_INSTANCE,
1624 c9c41373 Iustin Pop
    [FORCE_OPT, SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1625 c9c41373 Iustin Pop
    "[-f] <instance>", "Deactivate an instance's disks"),
1626 d0c8c01d Iustin Pop
  "recreate-disks": (
1627 aa06f8c6 Michael Hanselmann
    RecreateDisks, ARGS_ONE_INSTANCE,
1628 735e1318 Michael Hanselmann
    [SUBMIT_OPT, DISK_OPT, NODE_PLACEMENT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1629 6ea815cf Iustin Pop
    "<instance>", "Recreate an instance's disks"),
1630 d0c8c01d Iustin Pop
  "grow-disk": (
1631 6ea815cf Iustin Pop
    GrowDisk,
1632 6ea815cf Iustin Pop
    [ArgInstance(min=1, max=1), ArgUnknown(min=1, max=1),
1633 6ea815cf Iustin Pop
     ArgUnknown(min=1, max=1)],
1634 aa06f8c6 Michael Hanselmann
    [SUBMIT_OPT, NWSYNC_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1635 6ea815cf Iustin Pop
    "<instance> <disk> <size>", "Grow an instance's disk"),
1636 bd2a5569 Michael Hanselmann
  "change-group": (
1637 bd2a5569 Michael Hanselmann
    ChangeGroup, ARGS_ONE_INSTANCE,
1638 bd2a5569 Michael Hanselmann
    [TO_GROUP_OPT, IALLOCATOR_OPT, EARLY_RELEASE_OPT],
1639 bd2a5569 Michael Hanselmann
    "[-I <iallocator>] [--to <group>]", "Change group of instance"),
1640 d0c8c01d Iustin Pop
  "list-tags": (
1641 aa06f8c6 Michael Hanselmann
    ListTags, ARGS_ONE_INSTANCE, [PRIORITY_OPT],
1642 6ea815cf Iustin Pop
    "<instance_name>", "List the tags of the given instance"),
1643 d0c8c01d Iustin Pop
  "add-tags": (
1644 6ea815cf Iustin Pop
    AddTags, [ArgInstance(min=1, max=1), ArgUnknown()],
1645 aa06f8c6 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT],
1646 6ea815cf Iustin Pop
    "<instance_name> tag...", "Add tags to the given instance"),
1647 d0c8c01d Iustin Pop
  "remove-tags": (
1648 6ea815cf Iustin Pop
    RemoveTags, [ArgInstance(min=1, max=1), ArgUnknown()],
1649 aa06f8c6 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT],
1650 6ea815cf Iustin Pop
    "<instance_name> tag...", "Remove tags from given instance"),
1651 a8083063 Iustin Pop
  }
1652 a8083063 Iustin Pop
1653 7232c04c Iustin Pop
#: dictionary with aliases for commands
1654 dbfd89dd Guido Trotter
aliases = {
1655 d0c8c01d Iustin Pop
  "start": "startup",
1656 d0c8c01d Iustin Pop
  "stop": "shutdown",
1657 dbfd89dd Guido Trotter
  }
1658 dbfd89dd Guido Trotter
1659 a8005e17 Michael Hanselmann
1660 e792102d Michael Hanselmann
def Main():
1661 e792102d Michael Hanselmann
  return GenericMain(commands, aliases=aliases,
1662 ef9fa5b9 René Nussbaumer
                     override={"tag_type": constants.TAG_INSTANCE},
1663 ef9fa5b9 René Nussbaumer
                     env_override=_ENV_OVERRIDE)