Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_instance.py @ b53874cb

History | View | Annotate | Download (54.7 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 479636a3 Iustin Pop
def _ExpandMultiNames(mode, names, client=None):
68 312ac745 Iustin Pop
  """Expand the given names using the passed mode.
69 312ac745 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

243 d77490c5 Iustin Pop
  This is just a wrapper over GenericInstanceCreate.
244 a8083063 Iustin Pop

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

252 7232c04c Iustin Pop
  This function reads a json file with instances defined
253 7232c04c Iustin Pop
  in the form::
254 7232c04c Iustin Pop

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

267 7232c04c Iustin Pop
  Note that I{primary_node} and I{secondary_node} have precedence over
268 7232c04c Iustin Pop
  I{iallocator}.
269 7232c04c Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

628 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
629 7232c04c Iustin Pop
  @type args: list
630 7232c04c Iustin Pop
  @param args: should contain two elements, the instance name
631 7232c04c Iustin Pop
      whose disks we grow and the disk name, e.g. I{sda}
632 7232c04c Iustin Pop
  @rtype: int
633 7232c04c Iustin Pop
  @return: the desired exit code
634 c6e911bc Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

771 a8083063 Iustin Pop
  """
772 a76f0c4a Iustin Pop
  cl = GetClient()
773 80de0e3f Iustin Pop
  instance_name = args[0]
774 80de0e3f Iustin Pop
  force = opts.force
775 1b7761fd Apollon Oikonomopoulos
  iallocator = opts.iallocator
776 1b7761fd Apollon Oikonomopoulos
  target_node = opts.dst_node
777 1b7761fd Apollon Oikonomopoulos
778 1b7761fd Apollon Oikonomopoulos
  if iallocator and target_node:
779 1b7761fd Apollon Oikonomopoulos
    raise errors.OpPrereqError("Specify either an iallocator (-I), or a target"
780 1b7761fd Apollon Oikonomopoulos
                               " node (-n) but not both", errors.ECODE_INVAL)
781 a8083063 Iustin Pop
782 80de0e3f Iustin Pop
  if not force:
783 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
784 a76f0c4a Iustin Pop
785 80de0e3f Iustin Pop
    usertext = ("Failover will happen to image %s."
786 80de0e3f Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
787 80de0e3f Iustin Pop
                (instance_name,))
788 80de0e3f Iustin Pop
    if not AskUser(usertext):
789 80de0e3f Iustin Pop
      return 1
790 a8083063 Iustin Pop
791 019dbee1 Iustin Pop
  op = opcodes.OpInstanceFailover(instance_name=instance_name,
792 17c3f802 Guido Trotter
                                  ignore_consistency=opts.ignore_consistency,
793 1b7761fd Apollon Oikonomopoulos
                                  shutdown_timeout=opts.shutdown_timeout,
794 1b7761fd Apollon Oikonomopoulos
                                  iallocator=iallocator,
795 1b7761fd Apollon Oikonomopoulos
                                  target_node=target_node)
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 e9c487be René Nussbaumer
                                 allow_failover=opts.allow_failover)
851 400ca2f7 Iustin Pop
  SubmitOpCode(op, cl=cl, opts=opts)
852 53c776b5 Iustin Pop
  return 0
853 53c776b5 Iustin Pop
854 53c776b5 Iustin Pop
855 fbf5a861 Iustin Pop
def MoveInstance(opts, args):
856 fbf5a861 Iustin Pop
  """Move an instance.
857 fbf5a861 Iustin Pop

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

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

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

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

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

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

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

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

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

1009 a8083063 Iustin Pop
  """
1010 19708787 Iustin Pop
  def helper(dtype, status):
1011 7232c04c Iustin Pop
    """Format one line for physical device status.
1012 7232c04c Iustin Pop

1013 7232c04c Iustin Pop
    @type dtype: str
1014 7232c04c Iustin Pop
    @param dtype: a constant from the L{constants.LDS_BLOCK} set
1015 7232c04c Iustin Pop
    @type status: tuple
1016 7232c04c Iustin Pop
    @param status: a tuple as returned from L{backend.FindBlockDevice}
1017 19708787 Iustin Pop
    @return: the string representing the status
1018 7232c04c Iustin Pop

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

1109 19708787 Iustin Pop
  If the element of the list is:
1110 19708787 Iustin Pop
    - a string, it is simply formatted as is
1111 19708787 Iustin Pop
    - a tuple, it will be split into key, value and the all the
1112 19708787 Iustin Pop
      values in a list will be aligned all at the same start column
1113 19708787 Iustin Pop
    - a list, will be recursively formatted
1114 19708787 Iustin Pop

1115 19708787 Iustin Pop
  @type buf: StringIO
1116 19708787 Iustin Pop
  @param buf: the buffer into which we write the output
1117 19708787 Iustin Pop
  @param data: the list to format
1118 19708787 Iustin Pop
  @type indent_level: int
1119 19708787 Iustin Pop
  @param indent_level: the indent level to format at
1120 19708787 Iustin Pop

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

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

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

1239 a8083063 Iustin Pop
  All parameters take effect only at the next restart of the instance.
1240 a8083063 Iustin Pop

1241 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1242 7232c04c Iustin Pop
  @type args: list
1243 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
1244 7232c04c Iustin Pop
  @rtype: int
1245 7232c04c Iustin Pop
  @return: the desired exit code
1246 a8083063 Iustin Pop

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

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