Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_instance.py @ 5c3d5dfd

History | View | Annotate | Download (58.8 kB)

1 e792102d Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 ef8270dc Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 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 83d4ba5e René Nussbaumer
import copy
29 312ac745 Iustin Pop
import itertools
30 0d0e9090 René Nussbaumer
import simplejson
31 25ce3ec4 Michael Hanselmann
import logging
32 a8083063 Iustin Pop
from cStringIO import StringIO
33 a8083063 Iustin Pop
34 a8083063 Iustin Pop
from ganeti.cli import *
35 a8083063 Iustin Pop
from ganeti import opcodes
36 a8083063 Iustin Pop
from ganeti import constants
37 e2736e40 Guido Trotter
from ganeti import compat
38 a8083063 Iustin Pop
from ganeti import utils
39 312ac745 Iustin Pop
from ganeti import errors
40 a744b676 Manuel Franceschini
from ganeti import netutils
41 25ce3ec4 Michael Hanselmann
from ganeti import ssh
42 25ce3ec4 Michael Hanselmann
from ganeti import objects
43 735e1318 Michael Hanselmann
from ganeti import ht
44 312ac745 Iustin Pop
45 312ac745 Iustin Pop
46 c20efaa8 Michael Hanselmann
_EXPAND_CLUSTER = "cluster"
47 c20efaa8 Michael Hanselmann
_EXPAND_NODES_BOTH = "nodes"
48 c20efaa8 Michael Hanselmann
_EXPAND_NODES_PRI = "nodes-pri"
49 c20efaa8 Michael Hanselmann
_EXPAND_NODES_SEC = "nodes-sec"
50 c20efaa8 Michael Hanselmann
_EXPAND_NODES_BOTH_BY_TAGS = "nodes-by-tags"
51 c20efaa8 Michael Hanselmann
_EXPAND_NODES_PRI_BY_TAGS = "nodes-pri-by-tags"
52 c20efaa8 Michael Hanselmann
_EXPAND_NODES_SEC_BY_TAGS = "nodes-sec-by-tags"
53 c20efaa8 Michael Hanselmann
_EXPAND_INSTANCES = "instances"
54 c20efaa8 Michael Hanselmann
_EXPAND_INSTANCES_BY_TAGS = "instances-by-tags"
55 c20efaa8 Michael Hanselmann
56 c20efaa8 Michael Hanselmann
_EXPAND_NODES_TAGS_MODES = frozenset([
57 c20efaa8 Michael Hanselmann
  _EXPAND_NODES_BOTH_BY_TAGS,
58 c20efaa8 Michael Hanselmann
  _EXPAND_NODES_PRI_BY_TAGS,
59 c20efaa8 Michael Hanselmann
  _EXPAND_NODES_SEC_BY_TAGS,
60 c20efaa8 Michael Hanselmann
  ])
61 312ac745 Iustin Pop
62 7c0d6283 Michael Hanselmann
63 7232c04c Iustin Pop
#: default list of options for L{ListInstances}
64 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
65 e69d05fd Iustin Pop
  "name", "hypervisor", "os", "pnode", "status", "oper_ram",
66 48c4dfa8 Iustin Pop
  ]
67 48c4dfa8 Iustin Pop
68 bdb7d4e8 Michael Hanselmann
69 a71f835e Michael Hanselmann
_MISSING = object()
70 ef9fa5b9 René Nussbaumer
_ENV_OVERRIDE = frozenset(["list"])
71 ef9fa5b9 René Nussbaumer
72 ef9fa5b9 René Nussbaumer
73 479636a3 Iustin Pop
def _ExpandMultiNames(mode, names, client=None):
74 312ac745 Iustin Pop
  """Expand the given names using the passed mode.
75 312ac745 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

711 579d4337 Alexander Schreiber
  """
712 90ab1a95 Iustin Pop
  return opcodes.OpInstanceReboot(instance_name=name,
713 579d4337 Alexander Schreiber
                                  reboot_type=opts.reboot_type,
714 17c3f802 Guido Trotter
                                  ignore_secondaries=opts.ignore_secondaries,
715 4d98c565 Guido Trotter
                                  shutdown_timeout=opts.shutdown_timeout)
716 a8083063 Iustin Pop
717 7c0d6283 Michael Hanselmann
718 1c5945b6 Iustin Pop
def _ShutdownInstance(name, opts):
719 a8083063 Iustin Pop
  """Shutdown an instance.
720 a8083063 Iustin Pop

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

724 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
725 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
726 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
727 a8083063 Iustin Pop

728 a8083063 Iustin Pop
  """
729 ee3e37a7 Iustin Pop
  return opcodes.OpInstanceShutdown(instance_name=name,
730 b44bd844 Michael Hanselmann
                                    timeout=opts.timeout,
731 885a0fc4 Iustin Pop
                                    ignore_offline_nodes=opts.ignore_offline,
732 885a0fc4 Iustin Pop
                                    no_remember=opts.no_remember)
733 a8083063 Iustin Pop
734 a8083063 Iustin Pop
735 a8083063 Iustin Pop
def ReplaceDisks(opts, args):
736 a8083063 Iustin Pop
  """Replace the disks of an instance
737 a8083063 Iustin Pop

738 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
739 7232c04c Iustin Pop
  @type args: list
740 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
741 7232c04c Iustin Pop
  @rtype: int
742 7232c04c Iustin Pop
  @return: the desired exit code
743 a8083063 Iustin Pop

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

785 a8083063 Iustin Pop
  The failover is done by shutting it down on its present node and
786 a8083063 Iustin Pop
  starting it on the secondary.
787 a8083063 Iustin Pop

788 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
789 7232c04c Iustin Pop
  @type args: list
790 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
791 7232c04c Iustin Pop
  @rtype: int
792 7232c04c Iustin Pop
  @return: the desired exit code
793 a8083063 Iustin Pop

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

827 53c776b5 Iustin Pop
  The migrate is done without shutdown.
828 53c776b5 Iustin Pop

829 2f907a8c Iustin Pop
  @param opts: the command line options selected by the user
830 2f907a8c Iustin Pop
  @type args: list
831 2f907a8c Iustin Pop
  @param args: should contain only one element, the instance name
832 2f907a8c Iustin Pop
  @rtype: int
833 2f907a8c Iustin Pop
  @return: the desired exit code
834 53c776b5 Iustin Pop

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

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

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

914 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
915 7232c04c Iustin Pop
  @type args: list
916 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
917 7232c04c Iustin Pop
  @rtype: int
918 7232c04c Iustin Pop
  @return: the desired exit code
919 a8083063 Iustin Pop

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

951 25ce3ec4 Michael Hanselmann
  @type console: L{objects.InstanceConsole}
952 25ce3ec4 Michael Hanselmann
  @param console: Console object
953 25ce3ec4 Michael Hanselmann
  @type show_command: bool
954 25ce3ec4 Michael Hanselmann
  @param show_command: Whether to just display commands
955 25ce3ec4 Michael Hanselmann
  @type cluster_name: string
956 25ce3ec4 Michael Hanselmann
  @param cluster_name: Cluster name as retrieved from master daemon
957 25ce3ec4 Michael Hanselmann

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

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

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

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

1039 a8083063 Iustin Pop
  """
1040 19708787 Iustin Pop
  def helper(dtype, status):
1041 7232c04c Iustin Pop
    """Format one line for physical device status.
1042 7232c04c Iustin Pop

1043 7232c04c Iustin Pop
    @type dtype: str
1044 7232c04c Iustin Pop
    @param dtype: a constant from the L{constants.LDS_BLOCK} set
1045 7232c04c Iustin Pop
    @type status: tuple
1046 7232c04c Iustin Pop
    @param status: a tuple as returned from L{backend.FindBlockDevice}
1047 19708787 Iustin Pop
    @return: the string representing the status
1048 7232c04c Iustin Pop

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

1139 19708787 Iustin Pop
  If the element of the list is:
1140 19708787 Iustin Pop
    - a string, it is simply formatted as is
1141 19708787 Iustin Pop
    - a tuple, it will be split into key, value and the all the
1142 19708787 Iustin Pop
      values in a list will be aligned all at the same start column
1143 19708787 Iustin Pop
    - a list, will be recursively formatted
1144 19708787 Iustin Pop

1145 19708787 Iustin Pop
  @type buf: StringIO
1146 19708787 Iustin Pop
  @param buf: the buffer into which we write the output
1147 19708787 Iustin Pop
  @param data: the list to format
1148 19708787 Iustin Pop
  @type indent_level: int
1149 19708787 Iustin Pop
  @param indent_level: the indent level to format at
1150 19708787 Iustin Pop

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

1168 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1169 7232c04c Iustin Pop
  @type args: list
1170 7232c04c Iustin Pop
  @param args: either an empty list, and then we query all
1171 7232c04c Iustin Pop
      instances, or should contain a list of instance names
1172 7232c04c Iustin Pop
  @rtype: int
1173 7232c04c Iustin Pop
  @return: the desired exit code
1174 7232c04c Iustin Pop

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

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

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

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

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

1349 a8083063 Iustin Pop
  All parameters take effect only at the next restart of the instance.
1350 a8083063 Iustin Pop

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

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

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