Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_instance.py @ 57dc299a

History | View | Annotate | Download (55.9 kB)

1 e792102d Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 60472d29 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 7260cfbe Iustin Pop
"""Instance related commands"""
22 a8083063 Iustin Pop
23 b459a848 Andrea Spadaccini
# pylint: disable=W0401,W0614,C0103
24 2f79bd34 Iustin Pop
# W0401: Wildcard import ganeti.cli
25 2f79bd34 Iustin Pop
# W0614: Unused import %s from wildcard import (since we need cli)
26 7260cfbe Iustin Pop
# C0103: Invalid name gnt-instance
27 2f79bd34 Iustin Pop
28 312ac745 Iustin Pop
import itertools
29 0d0e9090 René Nussbaumer
import simplejson
30 25ce3ec4 Michael Hanselmann
import logging
31 a8083063 Iustin Pop
from cStringIO import StringIO
32 a8083063 Iustin Pop
33 a8083063 Iustin Pop
from ganeti.cli import *
34 a8083063 Iustin Pop
from ganeti import opcodes
35 a8083063 Iustin Pop
from ganeti import constants
36 e2736e40 Guido Trotter
from ganeti import compat
37 a8083063 Iustin Pop
from ganeti import utils
38 312ac745 Iustin Pop
from ganeti import errors
39 a744b676 Manuel Franceschini
from ganeti import netutils
40 25ce3ec4 Michael Hanselmann
from ganeti import ssh
41 25ce3ec4 Michael Hanselmann
from ganeti import objects
42 312ac745 Iustin Pop
43 312ac745 Iustin Pop
44 c20efaa8 Michael Hanselmann
_EXPAND_CLUSTER = "cluster"
45 c20efaa8 Michael Hanselmann
_EXPAND_NODES_BOTH = "nodes"
46 c20efaa8 Michael Hanselmann
_EXPAND_NODES_PRI = "nodes-pri"
47 c20efaa8 Michael Hanselmann
_EXPAND_NODES_SEC = "nodes-sec"
48 c20efaa8 Michael Hanselmann
_EXPAND_NODES_BOTH_BY_TAGS = "nodes-by-tags"
49 c20efaa8 Michael Hanselmann
_EXPAND_NODES_PRI_BY_TAGS = "nodes-pri-by-tags"
50 c20efaa8 Michael Hanselmann
_EXPAND_NODES_SEC_BY_TAGS = "nodes-sec-by-tags"
51 c20efaa8 Michael Hanselmann
_EXPAND_INSTANCES = "instances"
52 c20efaa8 Michael Hanselmann
_EXPAND_INSTANCES_BY_TAGS = "instances-by-tags"
53 c20efaa8 Michael Hanselmann
54 c20efaa8 Michael Hanselmann
_EXPAND_NODES_TAGS_MODES = frozenset([
55 c20efaa8 Michael Hanselmann
  _EXPAND_NODES_BOTH_BY_TAGS,
56 c20efaa8 Michael Hanselmann
  _EXPAND_NODES_PRI_BY_TAGS,
57 c20efaa8 Michael Hanselmann
  _EXPAND_NODES_SEC_BY_TAGS,
58 c20efaa8 Michael Hanselmann
  ])
59 312ac745 Iustin Pop
60 7c0d6283 Michael Hanselmann
61 7232c04c Iustin Pop
#: default list of options for L{ListInstances}
62 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
63 e69d05fd Iustin Pop
  "name", "hypervisor", "os", "pnode", "status", "oper_ram",
64 48c4dfa8 Iustin Pop
  ]
65 48c4dfa8 Iustin Pop
66 bdb7d4e8 Michael Hanselmann
67 ef9fa5b9 René Nussbaumer
_ENV_OVERRIDE = frozenset(["list"])
68 ef9fa5b9 René Nussbaumer
69 ef9fa5b9 René Nussbaumer
70 479636a3 Iustin Pop
def _ExpandMultiNames(mode, names, client=None):
71 312ac745 Iustin Pop
  """Expand the given names using the passed mode.
72 312ac745 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

246 d77490c5 Iustin Pop
  This is just a wrapper over GenericInstanceCreate.
247 a8083063 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

602 bd315bfa Iustin Pop
  """
603 bd315bfa Iustin Pop
  instance_name = args[0]
604 bd315bfa Iustin Pop
  if opts.disks:
605 bd315bfa Iustin Pop
    try:
606 bd315bfa Iustin Pop
      opts.disks = [int(v) for v in opts.disks.split(",")]
607 bd315bfa Iustin Pop
    except (ValueError, TypeError), err:
608 bd315bfa Iustin Pop
      ToStderr("Invalid disks value: %s" % str(err))
609 bd315bfa Iustin Pop
      return 1
610 bd315bfa Iustin Pop
  else:
611 bd315bfa Iustin Pop
    opts.disks = []
612 bd315bfa Iustin Pop
613 c8a96ae7 Iustin Pop
  if opts.node:
614 c8a96ae7 Iustin Pop
    pnode, snode = SplitNodeOption(opts.node)
615 c8a96ae7 Iustin Pop
    nodes = [pnode]
616 c8a96ae7 Iustin Pop
    if snode is not None:
617 c8a96ae7 Iustin Pop
      nodes.append(snode)
618 c8a96ae7 Iustin Pop
  else:
619 c8a96ae7 Iustin Pop
    nodes = []
620 c8a96ae7 Iustin Pop
621 6b273e78 Iustin Pop
  op = opcodes.OpInstanceRecreateDisks(instance_name=instance_name,
622 c8a96ae7 Iustin Pop
                                       disks=opts.disks,
623 c8a96ae7 Iustin Pop
                                       nodes=nodes)
624 bd315bfa Iustin Pop
  SubmitOrSend(op, opts)
625 bd315bfa Iustin Pop
  return 0
626 bd315bfa Iustin Pop
627 bd315bfa Iustin Pop
628 c6e911bc Iustin Pop
def GrowDisk(opts, args):
629 7232c04c Iustin Pop
  """Grow an instance's disks.
630 c6e911bc Iustin Pop

631 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
632 7232c04c Iustin Pop
  @type args: list
633 30a83755 Guido Trotter
  @param args: should contain three elements, the target instance name,
634 30a83755 Guido Trotter
      the target disk id, and the target growth
635 7232c04c Iustin Pop
  @rtype: int
636 7232c04c Iustin Pop
  @return: the desired exit code
637 c6e911bc Iustin Pop

638 c6e911bc Iustin Pop
  """
639 c6e911bc Iustin Pop
  instance = args[0]
640 c6e911bc Iustin Pop
  disk = args[1]
641 ad24e046 Iustin Pop
  try:
642 ad24e046 Iustin Pop
    disk = int(disk)
643 691744c4 Iustin Pop
  except (TypeError, ValueError), err:
644 debac808 Iustin Pop
    raise errors.OpPrereqError("Invalid disk index: %s" % str(err),
645 debac808 Iustin Pop
                               errors.ECODE_INVAL)
646 c6e911bc Iustin Pop
  amount = utils.ParseUnit(args[2])
647 60472d29 Iustin Pop
  op = opcodes.OpInstanceGrowDisk(instance_name=instance,
648 60472d29 Iustin Pop
                                  disk=disk, amount=amount,
649 60472d29 Iustin Pop
                                  wait_for_sync=opts.wait_for_sync)
650 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
651 c6e911bc Iustin Pop
  return 0
652 c6e911bc Iustin Pop
653 c6e911bc Iustin Pop
654 1c5945b6 Iustin Pop
def _StartupInstance(name, opts):
655 7232c04c Iustin Pop
  """Startup instances.
656 a8083063 Iustin Pop

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

660 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
661 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
662 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
663 a8083063 Iustin Pop

664 a8083063 Iustin Pop
  """
665 c873d91c Iustin Pop
  op = opcodes.OpInstanceStartup(instance_name=name,
666 b44bd844 Michael Hanselmann
                                 force=opts.force,
667 885a0fc4 Iustin Pop
                                 ignore_offline_nodes=opts.ignore_offline,
668 323f9095 Stephen Shirley
                                 no_remember=opts.no_remember,
669 323f9095 Stephen Shirley
                                 startup_paused=opts.startup_paused)
670 1c5945b6 Iustin Pop
  # do not add these parameters to the opcode unless they're defined
671 1c5945b6 Iustin Pop
  if opts.hvparams:
672 1c5945b6 Iustin Pop
    op.hvparams = opts.hvparams
673 1c5945b6 Iustin Pop
  if opts.beparams:
674 1c5945b6 Iustin Pop
    op.beparams = opts.beparams
675 1c5945b6 Iustin Pop
  return op
676 a8083063 Iustin Pop
677 7c0d6283 Michael Hanselmann
678 1c5945b6 Iustin Pop
def _RebootInstance(name, opts):
679 7232c04c Iustin Pop
  """Reboot instance(s).
680 7232c04c Iustin Pop

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

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

688 579d4337 Alexander Schreiber
  """
689 90ab1a95 Iustin Pop
  return opcodes.OpInstanceReboot(instance_name=name,
690 579d4337 Alexander Schreiber
                                  reboot_type=opts.reboot_type,
691 17c3f802 Guido Trotter
                                  ignore_secondaries=opts.ignore_secondaries,
692 4d98c565 Guido Trotter
                                  shutdown_timeout=opts.shutdown_timeout)
693 a8083063 Iustin Pop
694 7c0d6283 Michael Hanselmann
695 1c5945b6 Iustin Pop
def _ShutdownInstance(name, opts):
696 a8083063 Iustin Pop
  """Shutdown an instance.
697 a8083063 Iustin Pop

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

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

705 a8083063 Iustin Pop
  """
706 ee3e37a7 Iustin Pop
  return opcodes.OpInstanceShutdown(instance_name=name,
707 b44bd844 Michael Hanselmann
                                    timeout=opts.timeout,
708 885a0fc4 Iustin Pop
                                    ignore_offline_nodes=opts.ignore_offline,
709 885a0fc4 Iustin Pop
                                    no_remember=opts.no_remember)
710 a8083063 Iustin Pop
711 a8083063 Iustin Pop
712 a8083063 Iustin Pop
def ReplaceDisks(opts, args):
713 a8083063 Iustin Pop
  """Replace the disks of an instance
714 a8083063 Iustin Pop

715 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
716 7232c04c Iustin Pop
  @type args: list
717 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
718 7232c04c Iustin Pop
  @rtype: int
719 7232c04c Iustin Pop
  @return: the desired exit code
720 a8083063 Iustin Pop

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

761 a8083063 Iustin Pop
  The failover is done by shutting it down on its present node and
762 a8083063 Iustin Pop
  starting it on the secondary.
763 a8083063 Iustin Pop

764 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
765 7232c04c Iustin Pop
  @type args: list
766 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
767 7232c04c Iustin Pop
  @rtype: int
768 7232c04c Iustin Pop
  @return: the desired exit code
769 a8083063 Iustin Pop

770 a8083063 Iustin Pop
  """
771 a76f0c4a Iustin Pop
  cl = GetClient()
772 80de0e3f Iustin Pop
  instance_name = args[0]
773 80de0e3f Iustin Pop
  force = opts.force
774 1b7761fd Apollon Oikonomopoulos
  iallocator = opts.iallocator
775 1b7761fd Apollon Oikonomopoulos
  target_node = opts.dst_node
776 1b7761fd Apollon Oikonomopoulos
777 1b7761fd Apollon Oikonomopoulos
  if iallocator and target_node:
778 1b7761fd Apollon Oikonomopoulos
    raise errors.OpPrereqError("Specify either an iallocator (-I), or a target"
779 1b7761fd Apollon Oikonomopoulos
                               " node (-n) but not both", errors.ECODE_INVAL)
780 a8083063 Iustin Pop
781 80de0e3f Iustin Pop
  if not force:
782 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
783 a76f0c4a Iustin Pop
784 80de0e3f Iustin Pop
    usertext = ("Failover will happen to image %s."
785 80de0e3f Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
786 80de0e3f Iustin Pop
                (instance_name,))
787 80de0e3f Iustin Pop
    if not AskUser(usertext):
788 80de0e3f Iustin Pop
      return 1
789 a8083063 Iustin Pop
790 019dbee1 Iustin Pop
  op = opcodes.OpInstanceFailover(instance_name=instance_name,
791 17c3f802 Guido Trotter
                                  ignore_consistency=opts.ignore_consistency,
792 1b7761fd Apollon Oikonomopoulos
                                  shutdown_timeout=opts.shutdown_timeout,
793 1b7761fd Apollon Oikonomopoulos
                                  iallocator=iallocator,
794 b6aaf437 René Nussbaumer
                                  target_node=target_node,
795 b6aaf437 René Nussbaumer
                                  ignore_ipolicy=opts.ignore_ipolicy)
796 a76f0c4a Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
797 80de0e3f Iustin Pop
  return 0
798 a8083063 Iustin Pop
799 a8083063 Iustin Pop
800 53c776b5 Iustin Pop
def MigrateInstance(opts, args):
801 53c776b5 Iustin Pop
  """Migrate an instance.
802 53c776b5 Iustin Pop

803 53c776b5 Iustin Pop
  The migrate is done without shutdown.
804 53c776b5 Iustin Pop

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

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

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

865 fbf5a861 Iustin Pop
  """
866 fbf5a861 Iustin Pop
  cl = GetClient()
867 fbf5a861 Iustin Pop
  instance_name = args[0]
868 fbf5a861 Iustin Pop
  force = opts.force
869 fbf5a861 Iustin Pop
870 fbf5a861 Iustin Pop
  if not force:
871 fbf5a861 Iustin Pop
    usertext = ("Instance %s will be moved."
872 fbf5a861 Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
873 fbf5a861 Iustin Pop
                (instance_name,))
874 fbf5a861 Iustin Pop
    if not AskUser(usertext):
875 fbf5a861 Iustin Pop
      return 1
876 fbf5a861 Iustin Pop
877 0091b480 Iustin Pop
  op = opcodes.OpInstanceMove(instance_name=instance_name,
878 17c3f802 Guido Trotter
                              target_node=opts.node,
879 bb851c63 Iustin Pop
                              shutdown_timeout=opts.shutdown_timeout,
880 92cf62e3 René Nussbaumer
                              ignore_consistency=opts.ignore_consistency,
881 92cf62e3 René Nussbaumer
                              ignore_ipolicy=opts.ignore_ipolicy)
882 fbf5a861 Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
883 fbf5a861 Iustin Pop
  return 0
884 fbf5a861 Iustin Pop
885 fbf5a861 Iustin Pop
886 a8083063 Iustin Pop
def ConnectToInstanceConsole(opts, args):
887 a8083063 Iustin Pop
  """Connect to the console of an instance.
888 a8083063 Iustin Pop

889 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
890 7232c04c Iustin Pop
  @type args: list
891 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
892 7232c04c Iustin Pop
  @rtype: int
893 7232c04c Iustin Pop
  @return: the desired exit code
894 a8083063 Iustin Pop

895 a8083063 Iustin Pop
  """
896 a8083063 Iustin Pop
  instance_name = args[0]
897 a8083063 Iustin Pop
898 25ce3ec4 Michael Hanselmann
  cl = GetClient()
899 25ce3ec4 Michael Hanselmann
  try:
900 25ce3ec4 Michael Hanselmann
    cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
901 d6f46b6a Michael Hanselmann
    ((console_data, oper_state), ) = \
902 d6f46b6a Michael Hanselmann
      cl.QueryInstances([instance_name], ["console", "oper_state"], False)
903 25ce3ec4 Michael Hanselmann
  finally:
904 25ce3ec4 Michael Hanselmann
    # Ensure client connection is closed while external commands are run
905 25ce3ec4 Michael Hanselmann
    cl.Close()
906 25ce3ec4 Michael Hanselmann
907 25ce3ec4 Michael Hanselmann
  del cl
908 25ce3ec4 Michael Hanselmann
909 d6f46b6a Michael Hanselmann
  if not console_data:
910 d6f46b6a Michael Hanselmann
    if oper_state:
911 d6f46b6a Michael Hanselmann
      # Instance is running
912 d6f46b6a Michael Hanselmann
      raise errors.OpExecError("Console information for instance %s is"
913 d6f46b6a Michael Hanselmann
                               " unavailable" % instance_name)
914 d6f46b6a Michael Hanselmann
    else:
915 d6f46b6a Michael Hanselmann
      raise errors.OpExecError("Instance %s is not running, can't get console" %
916 d6f46b6a Michael Hanselmann
                               instance_name)
917 d6f46b6a Michael Hanselmann
918 25ce3ec4 Michael Hanselmann
  return _DoConsole(objects.InstanceConsole.FromDict(console_data),
919 25ce3ec4 Michael Hanselmann
                    opts.show_command, cluster_name)
920 25ce3ec4 Michael Hanselmann
921 25ce3ec4 Michael Hanselmann
922 25ce3ec4 Michael Hanselmann
def _DoConsole(console, show_command, cluster_name, feedback_fn=ToStdout,
923 25ce3ec4 Michael Hanselmann
               _runcmd_fn=utils.RunCmd):
924 cc0dec7b Iustin Pop
  """Acts based on the result of L{opcodes.OpInstanceConsole}.
925 25ce3ec4 Michael Hanselmann

926 25ce3ec4 Michael Hanselmann
  @type console: L{objects.InstanceConsole}
927 25ce3ec4 Michael Hanselmann
  @param console: Console object
928 25ce3ec4 Michael Hanselmann
  @type show_command: bool
929 25ce3ec4 Michael Hanselmann
  @param show_command: Whether to just display commands
930 25ce3ec4 Michael Hanselmann
  @type cluster_name: string
931 25ce3ec4 Michael Hanselmann
  @param cluster_name: Cluster name as retrieved from master daemon
932 25ce3ec4 Michael Hanselmann

933 25ce3ec4 Michael Hanselmann
  """
934 25ce3ec4 Michael Hanselmann
  assert console.Validate()
935 25ce3ec4 Michael Hanselmann
936 25ce3ec4 Michael Hanselmann
  if console.kind == constants.CONS_MESSAGE:
937 25ce3ec4 Michael Hanselmann
    feedback_fn(console.message)
938 25ce3ec4 Michael Hanselmann
  elif console.kind == constants.CONS_VNC:
939 25ce3ec4 Michael Hanselmann
    feedback_fn("Instance %s has VNC listening on %s:%s (display %s),"
940 25ce3ec4 Michael Hanselmann
                " URL <vnc://%s:%s/>",
941 25ce3ec4 Michael Hanselmann
                console.instance, console.host, console.port,
942 25ce3ec4 Michael Hanselmann
                console.display, console.host, console.port)
943 4d2cdb5a Andrea Spadaccini
  elif console.kind == constants.CONS_SPICE:
944 4d2cdb5a Andrea Spadaccini
    feedback_fn("Instance %s has SPICE listening on %s:%s", console.instance,
945 4d2cdb5a Andrea Spadaccini
                console.host, console.port)
946 25ce3ec4 Michael Hanselmann
  elif console.kind == constants.CONS_SSH:
947 25ce3ec4 Michael Hanselmann
    # Convert to string if not already one
948 25ce3ec4 Michael Hanselmann
    if isinstance(console.command, basestring):
949 25ce3ec4 Michael Hanselmann
      cmd = console.command
950 25ce3ec4 Michael Hanselmann
    else:
951 25ce3ec4 Michael Hanselmann
      cmd = utils.ShellQuoteArgs(console.command)
952 25ce3ec4 Michael Hanselmann
953 25ce3ec4 Michael Hanselmann
    srun = ssh.SshRunner(cluster_name=cluster_name)
954 25ce3ec4 Michael Hanselmann
    ssh_cmd = srun.BuildCmd(console.host, console.user, cmd,
955 25ce3ec4 Michael Hanselmann
                            batch=True, quiet=False, tty=True)
956 25ce3ec4 Michael Hanselmann
957 25ce3ec4 Michael Hanselmann
    if show_command:
958 25ce3ec4 Michael Hanselmann
      feedback_fn(utils.ShellQuoteArgs(ssh_cmd))
959 25ce3ec4 Michael Hanselmann
    else:
960 25ce3ec4 Michael Hanselmann
      result = _runcmd_fn(ssh_cmd, interactive=True)
961 25ce3ec4 Michael Hanselmann
      if result.failed:
962 25ce3ec4 Michael Hanselmann
        logging.error("Console command \"%s\" failed with reason '%s' and"
963 25ce3ec4 Michael Hanselmann
                      " output %r", result.cmd, result.fail_reason,
964 25ce3ec4 Michael Hanselmann
                      result.output)
965 25ce3ec4 Michael Hanselmann
        raise errors.OpExecError("Connection to console of instance %s failed,"
966 25ce3ec4 Michael Hanselmann
                                 " please check cluster configuration" %
967 25ce3ec4 Michael Hanselmann
                                 console.instance)
968 51c6e7b5 Michael Hanselmann
  else:
969 25ce3ec4 Michael Hanselmann
    raise errors.GenericError("Unknown console type '%s'" % console.kind)
970 678aa6d3 Michael Hanselmann
971 678aa6d3 Michael Hanselmann
  return constants.EXIT_SUCCESS
972 a8083063 Iustin Pop
973 a8083063 Iustin Pop
974 e2736e40 Guido Trotter
def _FormatLogicalID(dev_type, logical_id, roman):
975 19708787 Iustin Pop
  """Formats the logical_id of a disk.
976 19708787 Iustin Pop

977 19708787 Iustin Pop
  """
978 19708787 Iustin Pop
  if dev_type == constants.LD_DRBD8:
979 19708787 Iustin Pop
    node_a, node_b, port, minor_a, minor_b, key = logical_id
980 19708787 Iustin Pop
    data = [
981 e2736e40 Guido Trotter
      ("nodeA", "%s, minor=%s" % (node_a, compat.TryToRoman(minor_a,
982 e2736e40 Guido Trotter
                                                            convert=roman))),
983 e2736e40 Guido Trotter
      ("nodeB", "%s, minor=%s" % (node_b, compat.TryToRoman(minor_b,
984 e2736e40 Guido Trotter
                                                            convert=roman))),
985 e2736e40 Guido Trotter
      ("port", compat.TryToRoman(port, convert=roman)),
986 19708787 Iustin Pop
      ("auth key", key),
987 19708787 Iustin Pop
      ]
988 19708787 Iustin Pop
  elif dev_type == constants.LD_LV:
989 19708787 Iustin Pop
    vg_name, lv_name = logical_id
990 19708787 Iustin Pop
    data = ["%s/%s" % (vg_name, lv_name)]
991 19708787 Iustin Pop
  else:
992 19708787 Iustin Pop
    data = [str(logical_id)]
993 19708787 Iustin Pop
994 19708787 Iustin Pop
  return data
995 19708787 Iustin Pop
996 19708787 Iustin Pop
997 f965260c Michael Hanselmann
def _FormatBlockDevInfo(idx, top_level, dev, roman):
998 a8083063 Iustin Pop
  """Show block device information.
999 a8083063 Iustin Pop

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

1003 19708787 Iustin Pop
  @type idx: int
1004 19708787 Iustin Pop
  @param idx: the index of the current disk
1005 19708787 Iustin Pop
  @type top_level: boolean
1006 19708787 Iustin Pop
  @param top_level: if this a top-level disk?
1007 7232c04c Iustin Pop
  @type dev: dict
1008 7232c04c Iustin Pop
  @param dev: dictionary with disk information
1009 e2736e40 Guido Trotter
  @type roman: boolean
1010 e2736e40 Guido Trotter
  @param roman: whether to try to use roman integers
1011 19708787 Iustin Pop
  @return: a list of either strings, tuples or lists
1012 19708787 Iustin Pop
      (which should be formatted at a higher indent level)
1013 7232c04c Iustin Pop

1014 a8083063 Iustin Pop
  """
1015 19708787 Iustin Pop
  def helper(dtype, status):
1016 7232c04c Iustin Pop
    """Format one line for physical device status.
1017 7232c04c Iustin Pop

1018 7232c04c Iustin Pop
    @type dtype: str
1019 7232c04c Iustin Pop
    @param dtype: a constant from the L{constants.LDS_BLOCK} set
1020 7232c04c Iustin Pop
    @type status: tuple
1021 7232c04c Iustin Pop
    @param status: a tuple as returned from L{backend.FindBlockDevice}
1022 19708787 Iustin Pop
    @return: the string representing the status
1023 7232c04c Iustin Pop

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

1114 19708787 Iustin Pop
  If the element of the list is:
1115 19708787 Iustin Pop
    - a string, it is simply formatted as is
1116 19708787 Iustin Pop
    - a tuple, it will be split into key, value and the all the
1117 19708787 Iustin Pop
      values in a list will be aligned all at the same start column
1118 19708787 Iustin Pop
    - a list, will be recursively formatted
1119 19708787 Iustin Pop

1120 19708787 Iustin Pop
  @type buf: StringIO
1121 19708787 Iustin Pop
  @param buf: the buffer into which we write the output
1122 19708787 Iustin Pop
  @param data: the list to format
1123 19708787 Iustin Pop
  @type indent_level: int
1124 19708787 Iustin Pop
  @param indent_level: the indent level to format at
1125 19708787 Iustin Pop

1126 19708787 Iustin Pop
  """
1127 19708787 Iustin Pop
  max_tlen = max([len(elem[0]) for elem in data
1128 19708787 Iustin Pop
                 if isinstance(elem, tuple)] or [0])
1129 19708787 Iustin Pop
  for elem in data:
1130 19708787 Iustin Pop
    if isinstance(elem, basestring):
1131 e687ec01 Michael Hanselmann
      buf.write("%*s%s\n" % (2 * indent_level, "", elem))
1132 19708787 Iustin Pop
    elif isinstance(elem, tuple):
1133 19708787 Iustin Pop
      key, value = elem
1134 19708787 Iustin Pop
      spacer = "%*s" % (max_tlen - len(key), "")
1135 e687ec01 Michael Hanselmann
      buf.write("%*s%s:%s %s\n" % (2 * indent_level, "", key, spacer, value))
1136 19708787 Iustin Pop
    elif isinstance(elem, list):
1137 e687ec01 Michael Hanselmann
      _FormatList(buf, elem, indent_level + 1)
1138 19708787 Iustin Pop
1139 98825740 Michael Hanselmann
1140 a8083063 Iustin Pop
def ShowInstanceConfig(opts, args):
1141 a8083063 Iustin Pop
  """Compute instance run-time status.
1142 a8083063 Iustin Pop

1143 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1144 7232c04c Iustin Pop
  @type args: list
1145 7232c04c Iustin Pop
  @param args: either an empty list, and then we query all
1146 7232c04c Iustin Pop
      instances, or should contain a list of instance names
1147 7232c04c Iustin Pop
  @rtype: int
1148 7232c04c Iustin Pop
  @return: the desired exit code
1149 7232c04c Iustin Pop

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

1255 a8083063 Iustin Pop
  All parameters take effect only at the next restart of the instance.
1256 a8083063 Iustin Pop

1257 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1258 7232c04c Iustin Pop
  @type args: list
1259 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
1260 7232c04c Iustin Pop
  @rtype: int
1261 7232c04c Iustin Pop
  @return: the desired exit code
1262 a8083063 Iustin Pop

1263 a8083063 Iustin Pop
  """
1264 e29e9550 Iustin Pop
  if not (opts.nics or opts.disks or opts.disk_template or
1265 57de31c0 Agata Murawska
          opts.hvparams or opts.beparams or opts.os or opts.osparams or
1266 57de31c0 Agata Murawska
          opts.offline_inst or opts.online_inst):
1267 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
1268 a8083063 Iustin Pop
    return 1
1269 a8083063 Iustin Pop
1270 467ae11e Guido Trotter
  for param in opts.beparams:
1271 e9d622bc Guido Trotter
    if isinstance(opts.beparams[param], basestring):
1272 e9d622bc Guido Trotter
      if opts.beparams[param].lower() == "default":
1273 e9d622bc Guido Trotter
        opts.beparams[param] = constants.VALUE_DEFAULT
1274 a5728081 Guido Trotter
1275 b2e233a5 Guido Trotter
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_COMPAT,
1276 a5728081 Guido Trotter
                      allowed_values=[constants.VALUE_DEFAULT])
1277 467ae11e Guido Trotter
1278 48f212d7 Iustin Pop
  for param in opts.hvparams:
1279 48f212d7 Iustin Pop
    if isinstance(opts.hvparams[param], basestring):
1280 48f212d7 Iustin Pop
      if opts.hvparams[param].lower() == "default":
1281 48f212d7 Iustin Pop
        opts.hvparams[param] = constants.VALUE_DEFAULT
1282 a5728081 Guido Trotter
1283 48f212d7 Iustin Pop
  utils.ForceDictType(opts.hvparams, constants.HVS_PARAMETER_TYPES,
1284 a5728081 Guido Trotter
                      allowed_values=[constants.VALUE_DEFAULT])
1285 61be6ba4 Iustin Pop
1286 24991749 Iustin Pop
  for idx, (nic_op, nic_dict) in enumerate(opts.nics):
1287 24991749 Iustin Pop
    try:
1288 24991749 Iustin Pop
      nic_op = int(nic_op)
1289 24991749 Iustin Pop
      opts.nics[idx] = (nic_op, nic_dict)
1290 691744c4 Iustin Pop
    except (TypeError, ValueError):
1291 24991749 Iustin Pop
      pass
1292 24991749 Iustin Pop
1293 24991749 Iustin Pop
  for idx, (disk_op, disk_dict) in enumerate(opts.disks):
1294 24991749 Iustin Pop
    try:
1295 24991749 Iustin Pop
      disk_op = int(disk_op)
1296 24991749 Iustin Pop
      opts.disks[idx] = (disk_op, disk_dict)
1297 691744c4 Iustin Pop
    except (TypeError, ValueError):
1298 24991749 Iustin Pop
      pass
1299 24991749 Iustin Pop
    if disk_op == constants.DDM_ADD:
1300 d0c8c01d Iustin Pop
      if "size" not in disk_dict:
1301 debac808 Iustin Pop
        raise errors.OpPrereqError("Missing required parameter 'size'",
1302 debac808 Iustin Pop
                                   errors.ECODE_INVAL)
1303 d0c8c01d Iustin Pop
      disk_dict["size"] = utils.ParseUnit(disk_dict["size"])
1304 24991749 Iustin Pop
1305 e29e9550 Iustin Pop
  if (opts.disk_template and
1306 3429a076 Apollon Oikonomopoulos
      opts.disk_template in constants.DTS_INT_MIRROR and
1307 e29e9550 Iustin Pop
      not opts.node):
1308 e29e9550 Iustin Pop
    ToStderr("Changing the disk template to a mirrored one requires"
1309 e29e9550 Iustin Pop
             " specifying a secondary node")
1310 e29e9550 Iustin Pop
    return 1
1311 e29e9550 Iustin Pop
1312 9a3cc7ae Iustin Pop
  op = opcodes.OpInstanceSetParams(instance_name=args[0],
1313 24991749 Iustin Pop
                                   nics=opts.nics,
1314 24991749 Iustin Pop
                                   disks=opts.disks,
1315 e29e9550 Iustin Pop
                                   disk_template=opts.disk_template,
1316 e29e9550 Iustin Pop
                                   remote_node=opts.node,
1317 48f212d7 Iustin Pop
                                   hvparams=opts.hvparams,
1318 338e51e8 Iustin Pop
                                   beparams=opts.beparams,
1319 96b39bcc Iustin Pop
                                   os_name=opts.os,
1320 1052d622 Iustin Pop
                                   osparams=opts.osparams,
1321 96b39bcc Iustin Pop
                                   force_variant=opts.force_variant,
1322 456798ab Iustin Pop
                                   force=opts.force,
1323 57de31c0 Agata Murawska
                                   wait_for_sync=opts.wait_for_sync,
1324 57de31c0 Agata Murawska
                                   offline_inst=opts.offline_inst,
1325 1559e1e7 René Nussbaumer
                                   online_inst=opts.online_inst,
1326 1559e1e7 René Nussbaumer
                                   ignore_ipolicy=opts.ignore_ipolicy)
1327 31a853d2 Iustin Pop
1328 6340bb0a Iustin Pop
  # even if here we process the result, we allow submit only
1329 6340bb0a Iustin Pop
  result = SubmitOrSend(op, opts)
1330 a8083063 Iustin Pop
1331 a8083063 Iustin Pop
  if result:
1332 3a24c527 Iustin Pop
    ToStdout("Modified instance %s", args[0])
1333 a8083063 Iustin Pop
    for param, data in result:
1334 3a24c527 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
1335 e29e9550 Iustin Pop
    ToStdout("Please don't forget that most parameters take effect"
1336 3a24c527 Iustin Pop
             " only at the next start of the instance.")
1337 a8083063 Iustin Pop
  return 0
1338 a8083063 Iustin Pop
1339 a8083063 Iustin Pop
1340 bd2a5569 Michael Hanselmann
def ChangeGroup(opts, args):
1341 bd2a5569 Michael Hanselmann
  """Moves an instance to another group.
1342 bd2a5569 Michael Hanselmann

1343 bd2a5569 Michael Hanselmann
  """
1344 bd2a5569 Michael Hanselmann
  (instance_name, ) = args
1345 bd2a5569 Michael Hanselmann
1346 bd2a5569 Michael Hanselmann
  cl = GetClient()
1347 bd2a5569 Michael Hanselmann
1348 bd2a5569 Michael Hanselmann
  op = opcodes.OpInstanceChangeGroup(instance_name=instance_name,
1349 bd2a5569 Michael Hanselmann
                                     iallocator=opts.iallocator,
1350 bd2a5569 Michael Hanselmann
                                     target_groups=opts.to,
1351 bd2a5569 Michael Hanselmann
                                     early_release=opts.early_release)
1352 bd2a5569 Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
1353 bd2a5569 Michael Hanselmann
1354 bd2a5569 Michael Hanselmann
  # Keep track of submitted jobs
1355 bd2a5569 Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
1356 bd2a5569 Michael Hanselmann
1357 bd2a5569 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
1358 bd2a5569 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
1359 bd2a5569 Michael Hanselmann
1360 bd2a5569 Michael Hanselmann
  results = jex.GetResults()
1361 bd2a5569 Michael Hanselmann
  bad_cnt = len([row for row in results if not row[0]])
1362 bd2a5569 Michael Hanselmann
  if bad_cnt == 0:
1363 bd2a5569 Michael Hanselmann
    ToStdout("Instance '%s' changed group successfully.", instance_name)
1364 bd2a5569 Michael Hanselmann
    rcode = constants.EXIT_SUCCESS
1365 bd2a5569 Michael Hanselmann
  else:
1366 bd2a5569 Michael Hanselmann
    ToStdout("There were %s errors while changing group of instance '%s'.",
1367 bd2a5569 Michael Hanselmann
             bad_cnt, instance_name)
1368 bd2a5569 Michael Hanselmann
    rcode = constants.EXIT_FAILURE
1369 bd2a5569 Michael Hanselmann
1370 bd2a5569 Michael Hanselmann
  return rcode
1371 bd2a5569 Michael Hanselmann
1372 bd2a5569 Michael Hanselmann
1373 312ac745 Iustin Pop
# multi-instance selection options
1374 c38c44ad Michael Hanselmann
m_force_multi = cli_option("--force-multiple", dest="force_multi",
1375 c38c44ad Michael Hanselmann
                           help="Do not ask for confirmation when more than"
1376 c38c44ad Michael Hanselmann
                           " one instance is affected",
1377 c38c44ad Michael Hanselmann
                           action="store_true", default=False)
1378 804a1e8e Iustin Pop
1379 c38c44ad Michael Hanselmann
m_pri_node_opt = cli_option("--primary", dest="multi_mode",
1380 c38c44ad Michael Hanselmann
                            help="Filter by nodes (primary only)",
1381 c20efaa8 Michael Hanselmann
                            const=_EXPAND_NODES_PRI, action="store_const")
1382 312ac745 Iustin Pop
1383 c38c44ad Michael Hanselmann
m_sec_node_opt = cli_option("--secondary", dest="multi_mode",
1384 c38c44ad Michael Hanselmann
                            help="Filter by nodes (secondary only)",
1385 c20efaa8 Michael Hanselmann
                            const=_EXPAND_NODES_SEC, action="store_const")
1386 312ac745 Iustin Pop
1387 c38c44ad Michael Hanselmann
m_node_opt = cli_option("--node", dest="multi_mode",
1388 c38c44ad Michael Hanselmann
                        help="Filter by nodes (primary and secondary)",
1389 c20efaa8 Michael Hanselmann
                        const=_EXPAND_NODES_BOTH, action="store_const")
1390 312ac745 Iustin Pop
1391 c38c44ad Michael Hanselmann
m_clust_opt = cli_option("--all", dest="multi_mode",
1392 c38c44ad Michael Hanselmann
                         help="Select all instances in the cluster",
1393 c20efaa8 Michael Hanselmann
                         const=_EXPAND_CLUSTER, action="store_const")
1394 312ac745 Iustin Pop
1395 c38c44ad Michael Hanselmann
m_inst_opt = cli_option("--instance", dest="multi_mode",
1396 c38c44ad Michael Hanselmann
                        help="Filter by instance name [default]",
1397 c20efaa8 Michael Hanselmann
                        const=_EXPAND_INSTANCES, action="store_const")
1398 312ac745 Iustin Pop
1399 39dfd93e René Nussbaumer
m_node_tags_opt = cli_option("--node-tags", dest="multi_mode",
1400 39dfd93e René Nussbaumer
                             help="Filter by node tag",
1401 c20efaa8 Michael Hanselmann
                             const=_EXPAND_NODES_BOTH_BY_TAGS,
1402 39dfd93e René Nussbaumer
                             action="store_const")
1403 39dfd93e René Nussbaumer
1404 39dfd93e René Nussbaumer
m_pri_node_tags_opt = cli_option("--pri-node-tags", dest="multi_mode",
1405 39dfd93e René Nussbaumer
                                 help="Filter by primary node tag",
1406 c20efaa8 Michael Hanselmann
                                 const=_EXPAND_NODES_PRI_BY_TAGS,
1407 39dfd93e René Nussbaumer
                                 action="store_const")
1408 39dfd93e René Nussbaumer
1409 39dfd93e René Nussbaumer
m_sec_node_tags_opt = cli_option("--sec-node-tags", dest="multi_mode",
1410 39dfd93e René Nussbaumer
                                 help="Filter by secondary node tag",
1411 c20efaa8 Michael Hanselmann
                                 const=_EXPAND_NODES_SEC_BY_TAGS,
1412 39dfd93e René Nussbaumer
                                 action="store_const")
1413 39dfd93e René Nussbaumer
1414 39dfd93e René Nussbaumer
m_inst_tags_opt = cli_option("--tags", dest="multi_mode",
1415 39dfd93e René Nussbaumer
                             help="Filter by instance tag",
1416 c20efaa8 Michael Hanselmann
                             const=_EXPAND_INSTANCES_BY_TAGS,
1417 39dfd93e René Nussbaumer
                             action="store_const")
1418 312ac745 Iustin Pop
1419 a8083063 Iustin Pop
# this is defined separately due to readability only
1420 a8083063 Iustin Pop
add_opts = [
1421 064c21f8 Iustin Pop
  NOSTART_OPT,
1422 064c21f8 Iustin Pop
  OS_OPT,
1423 06073e85 Guido Trotter
  FORCE_VARIANT_OPT,
1424 25a8792c Iustin Pop
  NO_INSTALL_OPT,
1425 10889e0c René Nussbaumer
  IGNORE_IPOLICY_OPT,
1426 a8083063 Iustin Pop
  ]
1427 a8083063 Iustin Pop
1428 a8083063 Iustin Pop
commands = {
1429 d0c8c01d Iustin Pop
  "add": (
1430 eb28ecf6 Guido Trotter
    AddInstance, [ArgHost(min=1, max=1)], COMMON_CREATE_OPTS + add_opts,
1431 6ea815cf Iustin Pop
    "[...] -t disk-type -n node[:secondary-node] -o os-type <name>",
1432 6ea815cf Iustin Pop
    "Creates and adds a new instance to the cluster"),
1433 d0c8c01d Iustin Pop
  "batch-create": (
1434 aa06f8c6 Michael Hanselmann
    BatchCreate, [ArgFile(min=1, max=1)], [DRY_RUN_OPT, PRIORITY_OPT],
1435 6ea815cf Iustin Pop
    "<instances.json>",
1436 6ea815cf Iustin Pop
    "Create a bunch of instances based on specs in the file."),
1437 d0c8c01d Iustin Pop
  "console": (
1438 6ea815cf Iustin Pop
    ConnectToInstanceConsole, ARGS_ONE_INSTANCE,
1439 aa06f8c6 Michael Hanselmann
    [SHOWCMD_OPT, PRIORITY_OPT],
1440 6ea815cf Iustin Pop
    "[--show-cmd] <instance>", "Opens a console on the specified instance"),
1441 d0c8c01d Iustin Pop
  "failover": (
1442 6ea815cf Iustin Pop
    FailoverInstance, ARGS_ONE_INSTANCE,
1443 db5a8a2d Iustin Pop
    [FORCE_OPT, IGNORE_CONSIST_OPT, SUBMIT_OPT, SHUTDOWN_TIMEOUT_OPT,
1444 b6aaf437 René Nussbaumer
     DRY_RUN_OPT, PRIORITY_OPT, DST_NODE_OPT, IALLOCATOR_OPT,
1445 b6aaf437 René Nussbaumer
     IGNORE_IPOLICY_OPT],
1446 a6a3efe4 Iustin Pop
    "[-f] <instance>", "Stops the instance, changes its primary node and"
1447 a6a3efe4 Iustin Pop
    " (if it was originally running) starts it on the new node"
1448 a6a3efe4 Iustin Pop
    " (the secondary for mirrored instances or any node"
1449 a6a3efe4 Iustin Pop
    " for shared storage)."),
1450 d0c8c01d Iustin Pop
  "migrate": (
1451 6ea815cf Iustin Pop
    MigrateInstance, ARGS_ONE_INSTANCE,
1452 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, NONLIVE_OPT, MIGRATION_MODE_OPT, CLEANUP_OPT, DRY_RUN_OPT,
1453 3ed23330 René Nussbaumer
     PRIORITY_OPT, DST_NODE_OPT, IALLOCATOR_OPT, ALLOW_FAILOVER_OPT,
1454 3ed23330 René Nussbaumer
     IGNORE_IPOLICY_OPT],
1455 6ea815cf Iustin Pop
    "[-f] <instance>", "Migrate instance to its secondary node"
1456 1b7761fd Apollon Oikonomopoulos
    " (only for mirrored instances)"),
1457 d0c8c01d Iustin Pop
  "move": (
1458 6ea815cf Iustin Pop
    MoveInstance, ARGS_ONE_INSTANCE,
1459 db5a8a2d Iustin Pop
    [FORCE_OPT, SUBMIT_OPT, SINGLE_NODE_OPT, SHUTDOWN_TIMEOUT_OPT,
1460 92cf62e3 René Nussbaumer
     DRY_RUN_OPT, PRIORITY_OPT, IGNORE_CONSIST_OPT, IGNORE_IPOLICY_OPT],
1461 6ea815cf Iustin Pop
    "[-f] <instance>", "Move instance to an arbitrary node"
1462 6ea815cf Iustin Pop
    " (only for instances of type file and lv)"),
1463 d0c8c01d Iustin Pop
  "info": (
1464 6ea815cf Iustin Pop
    ShowInstanceConfig, ARGS_MANY_INSTANCES,
1465 aa06f8c6 Michael Hanselmann
    [STATIC_OPT, ALL_OPT, ROMAN_OPT, PRIORITY_OPT],
1466 6ea815cf Iustin Pop
    "[-s] {--all | <instance>...}",
1467 6ea815cf Iustin Pop
    "Show information on the specified instance(s)"),
1468 d0c8c01d Iustin Pop
  "list": (
1469 6ea815cf Iustin Pop
    ListInstances, ARGS_MANY_INSTANCES,
1470 87e87959 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, VERBOSE_OPT,
1471 87e87959 Michael Hanselmann
     FORCE_FILTER_OPT],
1472 6ea815cf Iustin Pop
    "[<instance>...]",
1473 b82c5ff5 Michael Hanselmann
    "Lists the instances and their status. The available fields can be shown"
1474 b82c5ff5 Michael Hanselmann
    " using the \"list-fields\" command (see the man page for details)."
1475 b82c5ff5 Michael Hanselmann
    " The default field list is (in order): %s." %
1476 b82c5ff5 Michael Hanselmann
    utils.CommaJoin(_LIST_DEF_FIELDS),
1477 6ea815cf Iustin Pop
    ),
1478 b82c5ff5 Michael Hanselmann
  "list-fields": (
1479 b82c5ff5 Michael Hanselmann
    ListInstanceFields, [ArgUnknown()],
1480 b82c5ff5 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT],
1481 b82c5ff5 Michael Hanselmann
    "[fields...]",
1482 b82c5ff5 Michael Hanselmann
    "Lists all available fields for instances"),
1483 d0c8c01d Iustin Pop
  "reinstall": (
1484 3e54ace7 Iustin Pop
    ReinstallInstance, [ArgInstance()],
1485 06073e85 Guido Trotter
    [FORCE_OPT, OS_OPT, FORCE_VARIANT_OPT, m_force_multi, m_node_opt,
1486 39dfd93e René Nussbaumer
     m_pri_node_opt, m_sec_node_opt, m_clust_opt, m_inst_opt, m_node_tags_opt,
1487 39dfd93e René Nussbaumer
     m_pri_node_tags_opt, m_sec_node_tags_opt, m_inst_tags_opt, SELECT_OS_OPT,
1488 8d8c4eff Michael Hanselmann
     SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT, OSPARAMS_OPT],
1489 6ea815cf Iustin Pop
    "[-f] <instance>", "Reinstall a stopped instance"),
1490 d0c8c01d Iustin Pop
  "remove": (
1491 6ea815cf Iustin Pop
    RemoveInstance, ARGS_ONE_INSTANCE,
1492 db5a8a2d Iustin Pop
    [FORCE_OPT, SHUTDOWN_TIMEOUT_OPT, IGNORE_FAILURES_OPT, SUBMIT_OPT,
1493 aa06f8c6 Michael Hanselmann
     DRY_RUN_OPT, PRIORITY_OPT],
1494 6ea815cf Iustin Pop
    "[-f] <instance>", "Shuts down the instance and removes it"),
1495 d0c8c01d Iustin Pop
  "rename": (
1496 6ea815cf Iustin Pop
    RenameInstance,
1497 6ea815cf Iustin Pop
    [ArgInstance(min=1, max=1), ArgHost(min=1, max=1)],
1498 aa06f8c6 Michael Hanselmann
    [NOIPCHECK_OPT, NONAMECHECK_OPT, SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1499 6ea815cf Iustin Pop
    "<instance> <new_name>", "Rename the instance"),
1500 d0c8c01d Iustin Pop
  "replace-disks": (
1501 6ea815cf Iustin Pop
    ReplaceDisks, ARGS_ONE_INSTANCE,
1502 7ea7bcf6 Iustin Pop
    [AUTO_REPLACE_OPT, DISKIDX_OPT, IALLOCATOR_OPT, EARLY_RELEASE_OPT,
1503 db5a8a2d Iustin Pop
     NEW_SECONDARY_OPT, ON_PRIMARY_OPT, ON_SECONDARY_OPT, SUBMIT_OPT,
1504 aa06f8c6 Michael Hanselmann
     DRY_RUN_OPT, PRIORITY_OPT],
1505 6ea815cf Iustin Pop
    "[-s|-p|-n NODE|-I NAME] <instance>",
1506 6ea815cf Iustin Pop
    "Replaces all disks for the instance"),
1507 d0c8c01d Iustin Pop
  "modify": (
1508 6ea815cf Iustin Pop
    SetInstanceParams, ARGS_ONE_INSTANCE,
1509 e29e9550 Iustin Pop
    [BACKEND_OPT, DISK_OPT, FORCE_OPT, HVOPTS_OPT, NET_OPT, SUBMIT_OPT,
1510 1052d622 Iustin Pop
     DISK_TEMPLATE_OPT, SINGLE_NODE_OPT, OS_OPT, FORCE_VARIANT_OPT,
1511 57de31c0 Agata Murawska
     OSPARAMS_OPT, DRY_RUN_OPT, PRIORITY_OPT, NWSYNC_OPT, OFFLINE_INST_OPT,
1512 1559e1e7 René Nussbaumer
     ONLINE_INST_OPT, IGNORE_IPOLICY_OPT],
1513 6ea815cf Iustin Pop
    "<instance>", "Alters the parameters of an instance"),
1514 d0c8c01d Iustin Pop
  "shutdown": (
1515 1c5945b6 Iustin Pop
    GenericManyOps("shutdown", _ShutdownInstance), [ArgInstance()],
1516 064c21f8 Iustin Pop
    [m_node_opt, m_pri_node_opt, m_sec_node_opt, m_clust_opt,
1517 39dfd93e René Nussbaumer
     m_node_tags_opt, m_pri_node_tags_opt, m_sec_node_tags_opt,
1518 db5a8a2d Iustin Pop
     m_inst_tags_opt, m_inst_opt, m_force_multi, TIMEOUT_OPT, SUBMIT_OPT,
1519 885a0fc4 Iustin Pop
     DRY_RUN_OPT, PRIORITY_OPT, IGNORE_OFFLINE_OPT, NO_REMEMBER_OPT],
1520 6ea815cf Iustin Pop
    "<instance>", "Stops an instance"),
1521 d0c8c01d Iustin Pop
  "startup": (
1522 1c5945b6 Iustin Pop
    GenericManyOps("startup", _StartupInstance), [ArgInstance()],
1523 39dfd93e René Nussbaumer
    [FORCE_OPT, m_force_multi, m_node_opt, m_pri_node_opt, m_sec_node_opt,
1524 39dfd93e René Nussbaumer
     m_node_tags_opt, m_pri_node_tags_opt, m_sec_node_tags_opt,
1525 39dfd93e René Nussbaumer
     m_inst_tags_opt, m_clust_opt, m_inst_opt, SUBMIT_OPT, HVOPTS_OPT,
1526 885a0fc4 Iustin Pop
     BACKEND_OPT, DRY_RUN_OPT, PRIORITY_OPT, IGNORE_OFFLINE_OPT,
1527 323f9095 Stephen Shirley
     NO_REMEMBER_OPT, STARTUP_PAUSED_OPT],
1528 6ea815cf Iustin Pop
    "<instance>", "Starts an instance"),
1529 d0c8c01d Iustin Pop
  "reboot": (
1530 1c5945b6 Iustin Pop
    GenericManyOps("reboot", _RebootInstance), [ArgInstance()],
1531 064c21f8 Iustin Pop
    [m_force_multi, REBOOT_TYPE_OPT, IGNORE_SECONDARIES_OPT, m_node_opt,
1532 17c3f802 Guido Trotter
     m_pri_node_opt, m_sec_node_opt, m_clust_opt, m_inst_opt, SUBMIT_OPT,
1533 39dfd93e René Nussbaumer
     m_node_tags_opt, m_pri_node_tags_opt, m_sec_node_tags_opt,
1534 aa06f8c6 Michael Hanselmann
     m_inst_tags_opt, SHUTDOWN_TIMEOUT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1535 6ea815cf Iustin Pop
    "<instance>", "Reboots an instance"),
1536 d0c8c01d Iustin Pop
  "activate-disks": (
1537 db5a8a2d Iustin Pop
    ActivateDisks, ARGS_ONE_INSTANCE,
1538 aa06f8c6 Michael Hanselmann
    [SUBMIT_OPT, IGNORE_SIZE_OPT, PRIORITY_OPT],
1539 6ea815cf Iustin Pop
    "<instance>", "Activate an instance's disks"),
1540 d0c8c01d Iustin Pop
  "deactivate-disks": (
1541 aa06f8c6 Michael Hanselmann
    DeactivateDisks, ARGS_ONE_INSTANCE,
1542 c9c41373 Iustin Pop
    [FORCE_OPT, SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1543 c9c41373 Iustin Pop
    "[-f] <instance>", "Deactivate an instance's disks"),
1544 d0c8c01d Iustin Pop
  "recreate-disks": (
1545 aa06f8c6 Michael Hanselmann
    RecreateDisks, ARGS_ONE_INSTANCE,
1546 c8a96ae7 Iustin Pop
    [SUBMIT_OPT, DISKIDX_OPT, NODE_PLACEMENT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1547 6ea815cf Iustin Pop
    "<instance>", "Recreate an instance's disks"),
1548 d0c8c01d Iustin Pop
  "grow-disk": (
1549 6ea815cf Iustin Pop
    GrowDisk,
1550 6ea815cf Iustin Pop
    [ArgInstance(min=1, max=1), ArgUnknown(min=1, max=1),
1551 6ea815cf Iustin Pop
     ArgUnknown(min=1, max=1)],
1552 aa06f8c6 Michael Hanselmann
    [SUBMIT_OPT, NWSYNC_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1553 6ea815cf Iustin Pop
    "<instance> <disk> <size>", "Grow an instance's disk"),
1554 bd2a5569 Michael Hanselmann
  "change-group": (
1555 bd2a5569 Michael Hanselmann
    ChangeGroup, ARGS_ONE_INSTANCE,
1556 bd2a5569 Michael Hanselmann
    [TO_GROUP_OPT, IALLOCATOR_OPT, EARLY_RELEASE_OPT],
1557 bd2a5569 Michael Hanselmann
    "[-I <iallocator>] [--to <group>]", "Change group of instance"),
1558 d0c8c01d Iustin Pop
  "list-tags": (
1559 aa06f8c6 Michael Hanselmann
    ListTags, ARGS_ONE_INSTANCE, [PRIORITY_OPT],
1560 6ea815cf Iustin Pop
    "<instance_name>", "List the tags of the given instance"),
1561 d0c8c01d Iustin Pop
  "add-tags": (
1562 6ea815cf Iustin Pop
    AddTags, [ArgInstance(min=1, max=1), ArgUnknown()],
1563 aa06f8c6 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT],
1564 6ea815cf Iustin Pop
    "<instance_name> tag...", "Add tags to the given instance"),
1565 d0c8c01d Iustin Pop
  "remove-tags": (
1566 6ea815cf Iustin Pop
    RemoveTags, [ArgInstance(min=1, max=1), ArgUnknown()],
1567 aa06f8c6 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT],
1568 6ea815cf Iustin Pop
    "<instance_name> tag...", "Remove tags from given instance"),
1569 a8083063 Iustin Pop
  }
1570 a8083063 Iustin Pop
1571 7232c04c Iustin Pop
#: dictionary with aliases for commands
1572 dbfd89dd Guido Trotter
aliases = {
1573 d0c8c01d Iustin Pop
  "start": "startup",
1574 d0c8c01d Iustin Pop
  "stop": "shutdown",
1575 dbfd89dd Guido Trotter
  }
1576 dbfd89dd Guido Trotter
1577 a8005e17 Michael Hanselmann
1578 e792102d Michael Hanselmann
def Main():
1579 e792102d Michael Hanselmann
  return GenericMain(commands, aliases=aliases,
1580 ef9fa5b9 René Nussbaumer
                     override={"tag_type": constants.TAG_INSTANCE},
1581 ef9fa5b9 René Nussbaumer
                     env_override=_ENV_OVERRIDE)