Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_instance.py @ c37bb2c6

History | View | Annotate | Download (52.4 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 7260cfbe Iustin Pop
# pylint: disable-msg=W0401,W0614,C0103
24 2f79bd34 Iustin Pop
# W0401: Wildcard import ganeti.cli
25 2f79bd34 Iustin Pop
# W0614: Unused import %s from wildcard import (since we need cli)
26 7260cfbe Iustin Pop
# C0103: Invalid name gnt-instance
27 2f79bd34 Iustin Pop
28 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 312ac745 Iustin Pop
_SHUTDOWN_CLUSTER = "cluster"
45 312ac745 Iustin Pop
_SHUTDOWN_NODES_BOTH = "nodes"
46 312ac745 Iustin Pop
_SHUTDOWN_NODES_PRI = "nodes-pri"
47 312ac745 Iustin Pop
_SHUTDOWN_NODES_SEC = "nodes-sec"
48 39dfd93e René Nussbaumer
_SHUTDOWN_NODES_BOTH_BY_TAGS = "nodes-by-tags"
49 39dfd93e René Nussbaumer
_SHUTDOWN_NODES_PRI_BY_TAGS = "nodes-pri-by-tags"
50 39dfd93e René Nussbaumer
_SHUTDOWN_NODES_SEC_BY_TAGS = "nodes-sec-by-tags"
51 312ac745 Iustin Pop
_SHUTDOWN_INSTANCES = "instances"
52 39dfd93e René Nussbaumer
_SHUTDOWN_INSTANCES_BY_TAGS = "instances-by-tags"
53 39dfd93e René Nussbaumer
54 39dfd93e René Nussbaumer
_SHUTDOWN_NODES_TAGS_MODES = (
55 39dfd93e René Nussbaumer
    _SHUTDOWN_NODES_BOTH_BY_TAGS,
56 39dfd93e René Nussbaumer
    _SHUTDOWN_NODES_PRI_BY_TAGS,
57 39dfd93e René Nussbaumer
    _SHUTDOWN_NODES_SEC_BY_TAGS)
58 312ac745 Iustin Pop
59 7c0d6283 Michael Hanselmann
60 7232c04c Iustin Pop
#: default list of options for L{ListInstances}
61 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
62 e69d05fd Iustin Pop
  "name", "hypervisor", "os", "pnode", "status", "oper_ram",
63 48c4dfa8 Iustin Pop
  ]
64 48c4dfa8 Iustin Pop
65 bdb7d4e8 Michael Hanselmann
66 479636a3 Iustin Pop
def _ExpandMultiNames(mode, names, client=None):
67 312ac745 Iustin Pop
  """Expand the given names using the passed mode.
68 312ac745 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

280 d77490c5 Iustin Pop
  This is just a wrapper over GenericInstanceCreate.
281 a8083063 Iustin Pop

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

289 7232c04c Iustin Pop
  This function reads a json file with instances defined
290 7232c04c Iustin Pop
  in the form::
291 7232c04c Iustin Pop

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

304 7232c04c Iustin Pop
  Note that I{primary_node} and I{secondary_node} have precedence over
305 7232c04c Iustin Pop
  I{iallocator}.
306 7232c04c Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

613 a8083063 Iustin Pop
  """
614 a8083063 Iustin Pop
  instance_name = args[0]
615 c9c41373 Iustin Pop
  op = opcodes.OpInstanceDeactivateDisks(instance_name=instance_name,
616 c9c41373 Iustin Pop
                                         force=opts.force)
617 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
618 a8083063 Iustin Pop
  return 0
619 a8083063 Iustin Pop
620 a8083063 Iustin Pop
621 bd315bfa Iustin Pop
def RecreateDisks(opts, args):
622 bd315bfa Iustin Pop
  """Recreate an instance's disks.
623 bd315bfa Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

810 53c776b5 Iustin Pop
  The migrate is done without shutdown.
811 53c776b5 Iustin Pop

812 2f907a8c Iustin Pop
  @param opts: the command line options selected by the user
813 2f907a8c Iustin Pop
  @type args: list
814 2f907a8c Iustin Pop
  @param args: should contain only one element, the instance name
815 2f907a8c Iustin Pop
  @rtype: int
816 2f907a8c Iustin Pop
  @return: the desired exit code
817 53c776b5 Iustin Pop

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

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

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

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

891 a8083063 Iustin Pop
  """
892 a8083063 Iustin Pop
  instance_name = args[0]
893 a8083063 Iustin Pop
894 cc0dec7b Iustin Pop
  op = opcodes.OpInstanceConsole(instance_name=instance_name)
895 51c6e7b5 Michael Hanselmann
896 25ce3ec4 Michael Hanselmann
  cl = GetClient()
897 25ce3ec4 Michael Hanselmann
  try:
898 25ce3ec4 Michael Hanselmann
    cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
899 25ce3ec4 Michael Hanselmann
    console_data = SubmitOpCode(op, opts=opts, cl=cl)
900 25ce3ec4 Michael Hanselmann
  finally:
901 25ce3ec4 Michael Hanselmann
    # Ensure client connection is closed while external commands are run
902 25ce3ec4 Michael Hanselmann
    cl.Close()
903 25ce3ec4 Michael Hanselmann
904 25ce3ec4 Michael Hanselmann
  del cl
905 25ce3ec4 Michael Hanselmann
906 25ce3ec4 Michael Hanselmann
  return _DoConsole(objects.InstanceConsole.FromDict(console_data),
907 25ce3ec4 Michael Hanselmann
                    opts.show_command, cluster_name)
908 25ce3ec4 Michael Hanselmann
909 25ce3ec4 Michael Hanselmann
910 25ce3ec4 Michael Hanselmann
def _DoConsole(console, show_command, cluster_name, feedback_fn=ToStdout,
911 25ce3ec4 Michael Hanselmann
               _runcmd_fn=utils.RunCmd):
912 cc0dec7b Iustin Pop
  """Acts based on the result of L{opcodes.OpInstanceConsole}.
913 25ce3ec4 Michael Hanselmann

914 25ce3ec4 Michael Hanselmann
  @type console: L{objects.InstanceConsole}
915 25ce3ec4 Michael Hanselmann
  @param console: Console object
916 25ce3ec4 Michael Hanselmann
  @type show_command: bool
917 25ce3ec4 Michael Hanselmann
  @param show_command: Whether to just display commands
918 25ce3ec4 Michael Hanselmann
  @type cluster_name: string
919 25ce3ec4 Michael Hanselmann
  @param cluster_name: Cluster name as retrieved from master daemon
920 25ce3ec4 Michael Hanselmann

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

962 19708787 Iustin Pop
  """
963 19708787 Iustin Pop
  if dev_type == constants.LD_DRBD8:
964 19708787 Iustin Pop
    node_a, node_b, port, minor_a, minor_b, key = logical_id
965 19708787 Iustin Pop
    data = [
966 e2736e40 Guido Trotter
      ("nodeA", "%s, minor=%s" % (node_a, compat.TryToRoman(minor_a,
967 e2736e40 Guido Trotter
                                                            convert=roman))),
968 e2736e40 Guido Trotter
      ("nodeB", "%s, minor=%s" % (node_b, compat.TryToRoman(minor_b,
969 e2736e40 Guido Trotter
                                                            convert=roman))),
970 e2736e40 Guido Trotter
      ("port", compat.TryToRoman(port, convert=roman)),
971 19708787 Iustin Pop
      ("auth key", key),
972 19708787 Iustin Pop
      ]
973 19708787 Iustin Pop
  elif dev_type == constants.LD_LV:
974 19708787 Iustin Pop
    vg_name, lv_name = logical_id
975 19708787 Iustin Pop
    data = ["%s/%s" % (vg_name, lv_name)]
976 19708787 Iustin Pop
  else:
977 19708787 Iustin Pop
    data = [str(logical_id)]
978 19708787 Iustin Pop
979 19708787 Iustin Pop
  return data
980 19708787 Iustin Pop
981 19708787 Iustin Pop
982 e2736e40 Guido Trotter
def _FormatBlockDevInfo(idx, top_level, dev, static, roman):
983 a8083063 Iustin Pop
  """Show block device information.
984 a8083063 Iustin Pop

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

988 19708787 Iustin Pop
  @type idx: int
989 19708787 Iustin Pop
  @param idx: the index of the current disk
990 19708787 Iustin Pop
  @type top_level: boolean
991 19708787 Iustin Pop
  @param top_level: if this a top-level disk?
992 7232c04c Iustin Pop
  @type dev: dict
993 7232c04c Iustin Pop
  @param dev: dictionary with disk information
994 7232c04c Iustin Pop
  @type static: boolean
995 7232c04c Iustin Pop
  @param static: wheter the device information doesn't contain
996 7232c04c Iustin Pop
      runtime information but only static data
997 e2736e40 Guido Trotter
  @type roman: boolean
998 e2736e40 Guido Trotter
  @param roman: whether to try to use roman integers
999 19708787 Iustin Pop
  @return: a list of either strings, tuples or lists
1000 19708787 Iustin Pop
      (which should be formatted at a higher indent level)
1001 7232c04c Iustin Pop

1002 a8083063 Iustin Pop
  """
1003 19708787 Iustin Pop
  def helper(dtype, status):
1004 7232c04c Iustin Pop
    """Format one line for physical device status.
1005 7232c04c Iustin Pop

1006 7232c04c Iustin Pop
    @type dtype: str
1007 7232c04c Iustin Pop
    @param dtype: a constant from the L{constants.LDS_BLOCK} set
1008 7232c04c Iustin Pop
    @type status: tuple
1009 7232c04c Iustin Pop
    @param status: a tuple as returned from L{backend.FindBlockDevice}
1010 19708787 Iustin Pop
    @return: the string representing the status
1011 7232c04c Iustin Pop

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

1100 19708787 Iustin Pop
  If the element of the list is:
1101 19708787 Iustin Pop
    - a string, it is simply formatted as is
1102 19708787 Iustin Pop
    - a tuple, it will be split into key, value and the all the
1103 19708787 Iustin Pop
      values in a list will be aligned all at the same start column
1104 19708787 Iustin Pop
    - a list, will be recursively formatted
1105 19708787 Iustin Pop

1106 19708787 Iustin Pop
  @type buf: StringIO
1107 19708787 Iustin Pop
  @param buf: the buffer into which we write the output
1108 19708787 Iustin Pop
  @param data: the list to format
1109 19708787 Iustin Pop
  @type indent_level: int
1110 19708787 Iustin Pop
  @param indent_level: the indent level to format at
1111 19708787 Iustin Pop

1112 19708787 Iustin Pop
  """
1113 19708787 Iustin Pop
  max_tlen = max([len(elem[0]) for elem in data
1114 19708787 Iustin Pop
                 if isinstance(elem, tuple)] or [0])
1115 19708787 Iustin Pop
  for elem in data:
1116 19708787 Iustin Pop
    if isinstance(elem, basestring):
1117 19708787 Iustin Pop
      buf.write("%*s%s\n" % (2*indent_level, "", elem))
1118 19708787 Iustin Pop
    elif isinstance(elem, tuple):
1119 19708787 Iustin Pop
      key, value = elem
1120 19708787 Iustin Pop
      spacer = "%*s" % (max_tlen - len(key), "")
1121 19708787 Iustin Pop
      buf.write("%*s%s:%s %s\n" % (2*indent_level, "", key, spacer, value))
1122 19708787 Iustin Pop
    elif isinstance(elem, list):
1123 19708787 Iustin Pop
      _FormatList(buf, elem, indent_level+1)
1124 19708787 Iustin Pop
1125 98825740 Michael Hanselmann
1126 a8083063 Iustin Pop
def ShowInstanceConfig(opts, args):
1127 a8083063 Iustin Pop
  """Compute instance run-time status.
1128 a8083063 Iustin Pop

1129 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1130 7232c04c Iustin Pop
  @type args: list
1131 7232c04c Iustin Pop
  @param args: either an empty list, and then we query all
1132 7232c04c Iustin Pop
      instances, or should contain a list of instance names
1133 7232c04c Iustin Pop
  @rtype: int
1134 7232c04c Iustin Pop
  @return: the desired exit code
1135 7232c04c Iustin Pop

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

1229 a8083063 Iustin Pop
  All parameters take effect only at the next restart of the instance.
1230 a8083063 Iustin Pop

1231 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1232 7232c04c Iustin Pop
  @type args: list
1233 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
1234 7232c04c Iustin Pop
  @rtype: int
1235 7232c04c Iustin Pop
  @return: the desired exit code
1236 a8083063 Iustin Pop

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