Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_instance.py @ 1fa2c40b

History | View | Annotate | Download (56.3 kB)

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

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

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

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

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

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

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

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

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

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

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

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

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

252 d77490c5 Iustin Pop
  This is just a wrapper over GenericInstanceCreate.
253 a8083063 Iustin Pop

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

261 b0a8e8c2 René Nussbaumer
  This function reads a json file with L{opcodes.OpInstanceCreate}
262 b0a8e8c2 René Nussbaumer
  serialisations.
263 7232c04c Iustin Pop

264 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
265 7232c04c Iustin Pop
  @type args: list
266 7232c04c Iustin Pop
  @param args: should contain one element, the json filename
267 7232c04c Iustin Pop
  @rtype: int
268 7232c04c Iustin Pop
  @return: the desired exit code
269 0d0e9090 René Nussbaumer

270 0d0e9090 René Nussbaumer
  """
271 b0a8e8c2 René Nussbaumer
  (json_filename,) = args
272 b0a8e8c2 René Nussbaumer
  cl = GetClient()
273 0d0e9090 René Nussbaumer
274 0d0e9090 René Nussbaumer
  try:
275 13998ef2 Michael Hanselmann
    instance_data = simplejson.loads(utils.ReadFile(json_filename))
276 b459a848 Andrea Spadaccini
  except Exception, err: # pylint: disable=W0703
277 4082e6f9 Iustin Pop
    ToStderr("Can't parse the instance definition file: %s" % str(err))
278 4082e6f9 Iustin Pop
    return 1
279 0d0e9090 René Nussbaumer
280 b0a8e8c2 René Nussbaumer
  if not _INST_DATA_VAL(instance_data):
281 b0a8e8c2 René Nussbaumer
    ToStderr("The instance definition file is not %s" % _INST_DATA_VAL)
282 fe7c59d5 Guido Trotter
    return 1
283 fe7c59d5 Guido Trotter
284 b0a8e8c2 René Nussbaumer
  instances = []
285 b0a8e8c2 René Nussbaumer
  possible_params = set(opcodes.OpInstanceCreate.GetAllSlots())
286 b0a8e8c2 René Nussbaumer
  for (idx, inst) in enumerate(instance_data):
287 b0a8e8c2 René Nussbaumer
    unknown = set(inst.keys()) - possible_params
288 d4dd4b74 Iustin Pop
289 b0a8e8c2 René Nussbaumer
    if unknown:
290 b0a8e8c2 René Nussbaumer
      # TODO: Suggest closest match for more user friendly experience
291 3779121c René Nussbaumer
      raise errors.OpPrereqError("Unknown fields in definition %s: %s" %
292 3779121c René Nussbaumer
                                 (idx, utils.CommaJoin(unknown)),
293 3779121c René Nussbaumer
                                 errors.ECODE_INVAL)
294 0d0e9090 René Nussbaumer
295 3779121c René Nussbaumer
    op = opcodes.OpInstanceCreate(**inst) # pylint: disable=W0142
296 b0a8e8c2 René Nussbaumer
    op.Validate(False)
297 b0a8e8c2 René Nussbaumer
    instances.append(op)
298 0d0e9090 René Nussbaumer
299 b0a8e8c2 René Nussbaumer
  op = opcodes.OpInstanceMultiAlloc(iallocator=opts.iallocator,
300 b0a8e8c2 René Nussbaumer
                                    instances=instances)
301 b0a8e8c2 René Nussbaumer
  result = SubmitOrSend(op, opts, cl=cl)
302 0d0e9090 René Nussbaumer
303 b0a8e8c2 René Nussbaumer
  # Keep track of submitted jobs
304 b0a8e8c2 René Nussbaumer
  jex = JobExecutor(cl=cl, opts=opts)
305 b0a8e8c2 René Nussbaumer
306 b0a8e8c2 René Nussbaumer
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
307 b0a8e8c2 René Nussbaumer
    jex.AddJobId(None, status, job_id)
308 b0a8e8c2 René Nussbaumer
309 b0a8e8c2 René Nussbaumer
  results = jex.GetResults()
310 b0a8e8c2 René Nussbaumer
  bad_cnt = len([row for row in results if not row[0]])
311 b0a8e8c2 René Nussbaumer
  if bad_cnt == 0:
312 b0a8e8c2 René Nussbaumer
    ToStdout("All instances created successfully.")
313 b0a8e8c2 René Nussbaumer
    rcode = constants.EXIT_SUCCESS
314 b0a8e8c2 René Nussbaumer
  else:
315 b0a8e8c2 René Nussbaumer
    ToStdout("There were %s errors during the creation.", bad_cnt)
316 b0a8e8c2 René Nussbaumer
    rcode = constants.EXIT_FAILURE
317 b0a8e8c2 René Nussbaumer
318 b0a8e8c2 René Nussbaumer
  return rcode
319 0d0e9090 René Nussbaumer
320 0d0e9090 René Nussbaumer
321 fe7b0351 Michael Hanselmann
def ReinstallInstance(opts, args):
322 fe7b0351 Michael Hanselmann
  """Reinstall an instance.
323 fe7b0351 Michael Hanselmann

324 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
325 7232c04c Iustin Pop
  @type args: list
326 7232c04c Iustin Pop
  @param args: should contain only one element, the name of the
327 7232c04c Iustin Pop
      instance to be reinstalled
328 7232c04c Iustin Pop
  @rtype: int
329 7232c04c Iustin Pop
  @return: the desired exit code
330 fe7b0351 Michael Hanselmann

331 fe7b0351 Michael Hanselmann
  """
332 55efe6da Iustin Pop
  # first, compute the desired name list
333 55efe6da Iustin Pop
  if opts.multi_mode is None:
334 c20efaa8 Michael Hanselmann
    opts.multi_mode = _EXPAND_INSTANCES
335 55efe6da Iustin Pop
336 55efe6da Iustin Pop
  inames = _ExpandMultiNames(opts.multi_mode, args)
337 55efe6da Iustin Pop
  if not inames:
338 debac808 Iustin Pop
    raise errors.OpPrereqError("Selection filter does not match any instances",
339 debac808 Iustin Pop
                               errors.ECODE_INVAL)
340 fe7b0351 Michael Hanselmann
341 55efe6da Iustin Pop
  # second, if requested, ask for an OS
342 20e23543 Alexander Schreiber
  if opts.select_os is True:
343 da2d02e7 Iustin Pop
    op = opcodes.OpOsDiagnose(output_fields=["name", "variants"], names=[])
344 400ca2f7 Iustin Pop
    result = SubmitOpCode(op, opts=opts)
345 20e23543 Alexander Schreiber
346 20e23543 Alexander Schreiber
    if not result:
347 3a24c527 Iustin Pop
      ToStdout("Can't get the OS list")
348 20e23543 Alexander Schreiber
      return 1
349 20e23543 Alexander Schreiber
350 3a24c527 Iustin Pop
    ToStdout("Available OS templates:")
351 20e23543 Alexander Schreiber
    number = 0
352 20e23543 Alexander Schreiber
    choices = []
353 d22dfef7 Iustin Pop
    for (name, variants) in result:
354 d22dfef7 Iustin Pop
      for entry in CalculateOSNames(name, variants):
355 d22dfef7 Iustin Pop
        ToStdout("%3s: %s", number, entry)
356 d22dfef7 Iustin Pop
        choices.append(("%s" % number, entry, entry))
357 d22dfef7 Iustin Pop
        number += 1
358 20e23543 Alexander Schreiber
359 d0c8c01d Iustin Pop
    choices.append(("x", "exit", "Exit gnt-instance reinstall"))
360 949bdabe Iustin Pop
    selected = AskUser("Enter OS template number (or x to abort):",
361 20e23543 Alexander Schreiber
                       choices)
362 20e23543 Alexander Schreiber
363 d0c8c01d Iustin Pop
    if selected == "exit":
364 55efe6da Iustin Pop
      ToStderr("User aborted reinstall, exiting")
365 20e23543 Alexander Schreiber
      return 1
366 20e23543 Alexander Schreiber
367 2f79bd34 Iustin Pop
    os_name = selected
368 f86426f5 Iustin Pop
    os_msg = "change the OS to '%s'" % selected
369 20e23543 Alexander Schreiber
  else:
370 2f79bd34 Iustin Pop
    os_name = opts.os
371 f86426f5 Iustin Pop
    if opts.os is not None:
372 f86426f5 Iustin Pop
      os_msg = "change the OS to '%s'" % os_name
373 f86426f5 Iustin Pop
    else:
374 f86426f5 Iustin Pop
      os_msg = "keep the same OS"
375 20e23543 Alexander Schreiber
376 297ddce9 Iustin Pop
  # third, get confirmation: multi-reinstall requires --force-multi,
377 297ddce9 Iustin Pop
  # single-reinstall either --force or --force-multi (--force-multi is
378 297ddce9 Iustin Pop
  # a stronger --force)
379 c20efaa8 Michael Hanselmann
  multi_on = opts.multi_mode != _EXPAND_INSTANCES or len(inames) > 1
380 55efe6da Iustin Pop
  if multi_on:
381 f86426f5 Iustin Pop
    warn_msg = ("Note: this will remove *all* data for the"
382 f86426f5 Iustin Pop
                " below instances! It will %s.\n" % os_msg)
383 297ddce9 Iustin Pop
    if not (opts.force_multi or
384 25bd815c René Nussbaumer
            ConfirmOperation(inames, "instances", "reinstall", extra=warn_msg)):
385 fe7b0351 Michael Hanselmann
      return 1
386 55efe6da Iustin Pop
  else:
387 297ddce9 Iustin Pop
    if not (opts.force or opts.force_multi):
388 f86426f5 Iustin Pop
      usertext = ("This will reinstall the instance '%s' (and %s) which"
389 f86426f5 Iustin Pop
                  " removes all data. Continue?") % (inames[0], os_msg)
390 55efe6da Iustin Pop
      if not AskUser(usertext):
391 55efe6da Iustin Pop
        return 1
392 55efe6da Iustin Pop
393 cb573a31 Iustin Pop
  jex = JobExecutor(verbose=multi_on, opts=opts)
394 55efe6da Iustin Pop
  for instance_name in inames:
395 5073fd8f Iustin Pop
    op = opcodes.OpInstanceReinstall(instance_name=instance_name,
396 06073e85 Guido Trotter
                                     os_type=os_name,
397 8d8c4eff Michael Hanselmann
                                     force_variant=opts.force_variant,
398 8d8c4eff Michael Hanselmann
                                     osparams=opts.osparams)
399 55efe6da Iustin Pop
    jex.QueueJob(instance_name, op)
400 fe7b0351 Michael Hanselmann
401 64be07b1 Michael Hanselmann
  results = jex.WaitOrShow(not opts.submit_only)
402 64be07b1 Michael Hanselmann
403 64be07b1 Michael Hanselmann
  if compat.all(map(compat.fst, results)):
404 64be07b1 Michael Hanselmann
    return constants.EXIT_SUCCESS
405 64be07b1 Michael Hanselmann
  else:
406 64be07b1 Michael Hanselmann
    return constants.EXIT_FAILURE
407 fe7b0351 Michael Hanselmann
408 fe7b0351 Michael Hanselmann
409 a8083063 Iustin Pop
def RemoveInstance(opts, args):
410 a8083063 Iustin Pop
  """Remove an instance.
411 a8083063 Iustin Pop

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

419 a8083063 Iustin Pop
  """
420 a8083063 Iustin Pop
  instance_name = args[0]
421 a8083063 Iustin Pop
  force = opts.force
422 a76f0c4a Iustin Pop
  cl = GetClient()
423 a8083063 Iustin Pop
424 a8083063 Iustin Pop
  if not force:
425 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
426 a76f0c4a Iustin Pop
427 a8083063 Iustin Pop
    usertext = ("This will remove the volumes of the instance %s"
428 a8083063 Iustin Pop
                " (including mirrors), thus removing all the data"
429 a8083063 Iustin Pop
                " of the instance. Continue?") % instance_name
430 47988778 Iustin Pop
    if not AskUser(usertext):
431 a8083063 Iustin Pop
      return 1
432 a8083063 Iustin Pop
433 3cd2d4b1 Iustin Pop
  op = opcodes.OpInstanceRemove(instance_name=instance_name,
434 17c3f802 Guido Trotter
                                ignore_failures=opts.ignore_failures,
435 4d98c565 Guido Trotter
                                shutdown_timeout=opts.shutdown_timeout)
436 a76f0c4a Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
437 a8083063 Iustin Pop
  return 0
438 a8083063 Iustin Pop
439 a8083063 Iustin Pop
440 decd5f45 Iustin Pop
def RenameInstance(opts, args):
441 4ab0b9e3 Guido Trotter
  """Rename an instance.
442 decd5f45 Iustin Pop

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 two elements, the old and the
446 7232c04c Iustin Pop
      new instance names
447 7232c04c Iustin Pop
  @rtype: int
448 7232c04c Iustin Pop
  @return: the desired exit code
449 decd5f45 Iustin Pop

450 decd5f45 Iustin Pop
  """
451 90ed09b0 René Nussbaumer
  if not opts.name_check:
452 1b6dddc8 René Nussbaumer
    if not AskUser("As you disabled the check of the DNS entry, please verify"
453 1b6dddc8 René Nussbaumer
                   " that '%s' is a FQDN. Continue?" % args[1]):
454 1b6dddc8 René Nussbaumer
      return 1
455 1b6dddc8 René Nussbaumer
456 5659e2e2 Iustin Pop
  op = opcodes.OpInstanceRename(instance_name=args[0],
457 decd5f45 Iustin Pop
                                new_name=args[1],
458 3fe11ba3 Manuel Franceschini
                                ip_check=opts.ip_check,
459 3fe11ba3 Manuel Franceschini
                                name_check=opts.name_check)
460 6a016df9 Michael Hanselmann
  result = SubmitOrSend(op, opts)
461 6a016df9 Michael Hanselmann
462 48418fea Iustin Pop
  if result:
463 48418fea Iustin Pop
    ToStdout("Instance '%s' renamed to '%s'", args[0], result)
464 6a016df9 Michael Hanselmann
465 decd5f45 Iustin Pop
  return 0
466 decd5f45 Iustin Pop
467 decd5f45 Iustin Pop
468 a8083063 Iustin Pop
def ActivateDisks(opts, args):
469 a8083063 Iustin Pop
  """Activate an instance's disks.
470 a8083063 Iustin Pop

471 a8083063 Iustin Pop
  This serves two purposes:
472 7232c04c Iustin Pop
    - it allows (as long as the instance is not running)
473 7232c04c Iustin Pop
      mounting the disks and modifying them from the node
474 a8083063 Iustin Pop
    - it repairs inactive secondary drbds
475 a8083063 Iustin Pop

476 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
477 7232c04c Iustin Pop
  @type args: list
478 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
479 7232c04c Iustin Pop
  @rtype: int
480 7232c04c Iustin Pop
  @return: the desired exit code
481 7232c04c Iustin Pop

482 a8083063 Iustin Pop
  """
483 a8083063 Iustin Pop
  instance_name = args[0]
484 83f5d475 Iustin Pop
  op = opcodes.OpInstanceActivateDisks(instance_name=instance_name,
485 f30d8165 Iustin Pop
                                       ignore_size=opts.ignore_size,
486 f30d8165 Iustin Pop
                                       wait_for_sync=opts.wait_for_sync)
487 6340bb0a Iustin Pop
  disks_info = SubmitOrSend(op, opts)
488 a8083063 Iustin Pop
  for host, iname, nname in disks_info:
489 3a24c527 Iustin Pop
    ToStdout("%s:%s:%s", host, iname, nname)
490 a8083063 Iustin Pop
  return 0
491 a8083063 Iustin Pop
492 a8083063 Iustin Pop
493 a8083063 Iustin Pop
def DeactivateDisks(opts, args):
494 bd315bfa Iustin Pop
  """Deactivate an instance's disks.
495 a8083063 Iustin Pop

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

499 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
500 7232c04c Iustin Pop
  @type args: list
501 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
502 7232c04c Iustin Pop
  @rtype: int
503 7232c04c Iustin Pop
  @return: the desired exit code
504 7232c04c Iustin Pop

505 a8083063 Iustin Pop
  """
506 a8083063 Iustin Pop
  instance_name = args[0]
507 c9c41373 Iustin Pop
  op = opcodes.OpInstanceDeactivateDisks(instance_name=instance_name,
508 c9c41373 Iustin Pop
                                         force=opts.force)
509 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
510 a8083063 Iustin Pop
  return 0
511 a8083063 Iustin Pop
512 a8083063 Iustin Pop
513 bd315bfa Iustin Pop
def RecreateDisks(opts, args):
514 bd315bfa Iustin Pop
  """Recreate an instance's disks.
515 bd315bfa Iustin Pop

516 bd315bfa Iustin Pop
  @param opts: the command line options selected by the user
517 bd315bfa Iustin Pop
  @type args: list
518 bd315bfa Iustin Pop
  @param args: should contain only one element, the instance name
519 bd315bfa Iustin Pop
  @rtype: int
520 bd315bfa Iustin Pop
  @return: the desired exit code
521 bd315bfa Iustin Pop

522 bd315bfa Iustin Pop
  """
523 bd315bfa Iustin Pop
  instance_name = args[0]
524 735e1318 Michael Hanselmann
525 735e1318 Michael Hanselmann
  disks = []
526 735e1318 Michael Hanselmann
527 bd315bfa Iustin Pop
  if opts.disks:
528 735e1318 Michael Hanselmann
    for didx, ddict in opts.disks:
529 735e1318 Michael Hanselmann
      didx = int(didx)
530 735e1318 Michael Hanselmann
531 735e1318 Michael Hanselmann
      if not ht.TDict(ddict):
532 735e1318 Michael Hanselmann
        msg = "Invalid disk/%d value: expected dict, got %s" % (didx, ddict)
533 2cfbc784 Iustin Pop
        raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
534 735e1318 Michael Hanselmann
535 735e1318 Michael Hanselmann
      if constants.IDISK_SIZE in ddict:
536 735e1318 Michael Hanselmann
        try:
537 735e1318 Michael Hanselmann
          ddict[constants.IDISK_SIZE] = \
538 735e1318 Michael Hanselmann
            utils.ParseUnit(ddict[constants.IDISK_SIZE])
539 735e1318 Michael Hanselmann
        except ValueError, err:
540 735e1318 Michael Hanselmann
          raise errors.OpPrereqError("Invalid disk size for disk %d: %s" %
541 2cfbc784 Iustin Pop
                                     (didx, err), errors.ECODE_INVAL)
542 735e1318 Michael Hanselmann
543 735e1318 Michael Hanselmann
      disks.append((didx, ddict))
544 735e1318 Michael Hanselmann
545 735e1318 Michael Hanselmann
    # TODO: Verify modifyable parameters (already done in
546 735e1318 Michael Hanselmann
    # LUInstanceRecreateDisks, but it'd be nice to have in the client)
547 bd315bfa Iustin Pop
548 c8a96ae7 Iustin Pop
  if opts.node:
549 38db4e7c Adam Ingrassia
    if opts.iallocator:
550 38db4e7c Adam Ingrassia
      msg = "At most one of either --nodes or --iallocator can be passed"
551 38db4e7c Adam Ingrassia
      raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
552 c8a96ae7 Iustin Pop
    pnode, snode = SplitNodeOption(opts.node)
553 c8a96ae7 Iustin Pop
    nodes = [pnode]
554 c8a96ae7 Iustin Pop
    if snode is not None:
555 c8a96ae7 Iustin Pop
      nodes.append(snode)
556 c8a96ae7 Iustin Pop
  else:
557 c8a96ae7 Iustin Pop
    nodes = []
558 c8a96ae7 Iustin Pop
559 6b273e78 Iustin Pop
  op = opcodes.OpInstanceRecreateDisks(instance_name=instance_name,
560 38db4e7c Adam Ingrassia
                                       disks=disks, nodes=nodes,
561 38db4e7c Adam Ingrassia
                                       iallocator=opts.iallocator)
562 bd315bfa Iustin Pop
  SubmitOrSend(op, opts)
563 735e1318 Michael Hanselmann
564 bd315bfa Iustin Pop
  return 0
565 bd315bfa Iustin Pop
566 bd315bfa Iustin Pop
567 c6e911bc Iustin Pop
def GrowDisk(opts, args):
568 7232c04c Iustin Pop
  """Grow an instance's disks.
569 c6e911bc Iustin Pop

570 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
571 7232c04c Iustin Pop
  @type args: list
572 30a83755 Guido Trotter
  @param args: should contain three elements, the target instance name,
573 30a83755 Guido Trotter
      the target disk id, and the target growth
574 7232c04c Iustin Pop
  @rtype: int
575 7232c04c Iustin Pop
  @return: the desired exit code
576 c6e911bc Iustin Pop

577 c6e911bc Iustin Pop
  """
578 c6e911bc Iustin Pop
  instance = args[0]
579 c6e911bc Iustin Pop
  disk = args[1]
580 ad24e046 Iustin Pop
  try:
581 ad24e046 Iustin Pop
    disk = int(disk)
582 691744c4 Iustin Pop
  except (TypeError, ValueError), err:
583 debac808 Iustin Pop
    raise errors.OpPrereqError("Invalid disk index: %s" % str(err),
584 debac808 Iustin Pop
                               errors.ECODE_INVAL)
585 c8bde61e Iustin Pop
  try:
586 c8bde61e Iustin Pop
    amount = utils.ParseUnit(args[2])
587 c8bde61e Iustin Pop
  except errors.UnitParseError:
588 c8bde61e Iustin Pop
    raise errors.OpPrereqError("Can't parse the given amount '%s'" % args[2],
589 c8bde61e Iustin Pop
                               errors.ECODE_INVAL)
590 60472d29 Iustin Pop
  op = opcodes.OpInstanceGrowDisk(instance_name=instance,
591 60472d29 Iustin Pop
                                  disk=disk, amount=amount,
592 ef8270dc Iustin Pop
                                  wait_for_sync=opts.wait_for_sync,
593 ef8270dc Iustin Pop
                                  absolute=opts.absolute)
594 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
595 c6e911bc Iustin Pop
  return 0
596 c6e911bc Iustin Pop
597 c6e911bc Iustin Pop
598 1c5945b6 Iustin Pop
def _StartupInstance(name, opts):
599 7232c04c Iustin Pop
  """Startup instances.
600 a8083063 Iustin Pop

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

604 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
605 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
606 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
607 a8083063 Iustin Pop

608 a8083063 Iustin Pop
  """
609 c873d91c Iustin Pop
  op = opcodes.OpInstanceStartup(instance_name=name,
610 b44bd844 Michael Hanselmann
                                 force=opts.force,
611 885a0fc4 Iustin Pop
                                 ignore_offline_nodes=opts.ignore_offline,
612 323f9095 Stephen Shirley
                                 no_remember=opts.no_remember,
613 323f9095 Stephen Shirley
                                 startup_paused=opts.startup_paused)
614 1c5945b6 Iustin Pop
  # do not add these parameters to the opcode unless they're defined
615 1c5945b6 Iustin Pop
  if opts.hvparams:
616 1c5945b6 Iustin Pop
    op.hvparams = opts.hvparams
617 1c5945b6 Iustin Pop
  if opts.beparams:
618 1c5945b6 Iustin Pop
    op.beparams = opts.beparams
619 1c5945b6 Iustin Pop
  return op
620 a8083063 Iustin Pop
621 7c0d6283 Michael Hanselmann
622 1c5945b6 Iustin Pop
def _RebootInstance(name, opts):
623 7232c04c Iustin Pop
  """Reboot instance(s).
624 7232c04c Iustin Pop

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

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

632 579d4337 Alexander Schreiber
  """
633 90ab1a95 Iustin Pop
  return opcodes.OpInstanceReboot(instance_name=name,
634 579d4337 Alexander Schreiber
                                  reboot_type=opts.reboot_type,
635 17c3f802 Guido Trotter
                                  ignore_secondaries=opts.ignore_secondaries,
636 4d98c565 Guido Trotter
                                  shutdown_timeout=opts.shutdown_timeout)
637 a8083063 Iustin Pop
638 7c0d6283 Michael Hanselmann
639 1c5945b6 Iustin Pop
def _ShutdownInstance(name, opts):
640 a8083063 Iustin Pop
  """Shutdown an instance.
641 a8083063 Iustin Pop

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

645 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
646 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
647 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
648 a8083063 Iustin Pop

649 a8083063 Iustin Pop
  """
650 ee3e37a7 Iustin Pop
  return opcodes.OpInstanceShutdown(instance_name=name,
651 b44bd844 Michael Hanselmann
                                    timeout=opts.timeout,
652 885a0fc4 Iustin Pop
                                    ignore_offline_nodes=opts.ignore_offline,
653 885a0fc4 Iustin Pop
                                    no_remember=opts.no_remember)
654 a8083063 Iustin Pop
655 a8083063 Iustin Pop
656 a8083063 Iustin Pop
def ReplaceDisks(opts, args):
657 a8083063 Iustin Pop
  """Replace the disks of an instance
658 a8083063 Iustin Pop

659 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
660 7232c04c Iustin Pop
  @type args: list
661 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
662 7232c04c Iustin Pop
  @rtype: int
663 7232c04c Iustin Pop
  @return: the desired exit code
664 a8083063 Iustin Pop

665 a8083063 Iustin Pop
  """
666 a14db5ff Iustin Pop
  new_2ndary = opts.dst_node
667 b6e82a65 Iustin Pop
  iallocator = opts.iallocator
668 a9e0c397 Iustin Pop
  if opts.disks is None:
669 54155f52 Iustin Pop
    disks = []
670 a9e0c397 Iustin Pop
  else:
671 54155f52 Iustin Pop
    try:
672 54155f52 Iustin Pop
      disks = [int(i) for i in opts.disks.split(",")]
673 691744c4 Iustin Pop
    except (TypeError, ValueError), err:
674 debac808 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err),
675 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
676 05d47e33 Michael Hanselmann
  cnt = [opts.on_primary, opts.on_secondary, opts.auto,
677 7e9366f7 Iustin Pop
         new_2ndary is not None, iallocator is not None].count(True)
678 7e9366f7 Iustin Pop
  if cnt != 1:
679 d8d838cb Michael Hanselmann
    raise errors.OpPrereqError("One and only one of the -p, -s, -a, -n and -I"
680 debac808 Iustin Pop
                               " options must be passed", errors.ECODE_INVAL)
681 7e9366f7 Iustin Pop
  elif opts.on_primary:
682 a9e0c397 Iustin Pop
    mode = constants.REPLACE_DISK_PRI
683 7e9366f7 Iustin Pop
  elif opts.on_secondary:
684 a9e0c397 Iustin Pop
    mode = constants.REPLACE_DISK_SEC
685 05d47e33 Michael Hanselmann
  elif opts.auto:
686 05d47e33 Michael Hanselmann
    mode = constants.REPLACE_DISK_AUTO
687 05d47e33 Michael Hanselmann
    if disks:
688 05d47e33 Michael Hanselmann
      raise errors.OpPrereqError("Cannot specify disks when using automatic"
689 debac808 Iustin Pop
                                 " mode", errors.ECODE_INVAL)
690 7e9366f7 Iustin Pop
  elif new_2ndary is not None or iallocator is not None:
691 7e9366f7 Iustin Pop
    # replace secondary
692 7e9366f7 Iustin Pop
    mode = constants.REPLACE_DISK_CHG
693 a9e0c397 Iustin Pop
694 668f755d Iustin Pop
  op = opcodes.OpInstanceReplaceDisks(instance_name=args[0], disks=disks,
695 668f755d Iustin Pop
                                      remote_node=new_2ndary, mode=mode,
696 668f755d Iustin Pop
                                      iallocator=iallocator,
697 893e8f49 René Nussbaumer
                                      early_release=opts.early_release,
698 893e8f49 René Nussbaumer
                                      ignore_ipolicy=opts.ignore_ipolicy)
699 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
700 a8083063 Iustin Pop
  return 0
701 a8083063 Iustin Pop
702 a8083063 Iustin Pop
703 a8083063 Iustin Pop
def FailoverInstance(opts, args):
704 a8083063 Iustin Pop
  """Failover an instance.
705 a8083063 Iustin Pop

706 a8083063 Iustin Pop
  The failover is done by shutting it down on its present node and
707 a8083063 Iustin Pop
  starting it on the secondary.
708 a8083063 Iustin Pop

709 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
710 7232c04c Iustin Pop
  @type args: list
711 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
712 7232c04c Iustin Pop
  @rtype: int
713 7232c04c Iustin Pop
  @return: the desired exit code
714 a8083063 Iustin Pop

715 a8083063 Iustin Pop
  """
716 a76f0c4a Iustin Pop
  cl = GetClient()
717 80de0e3f Iustin Pop
  instance_name = args[0]
718 80de0e3f Iustin Pop
  force = opts.force
719 1b7761fd Apollon Oikonomopoulos
  iallocator = opts.iallocator
720 1b7761fd Apollon Oikonomopoulos
  target_node = opts.dst_node
721 1b7761fd Apollon Oikonomopoulos
722 1b7761fd Apollon Oikonomopoulos
  if iallocator and target_node:
723 1b7761fd Apollon Oikonomopoulos
    raise errors.OpPrereqError("Specify either an iallocator (-I), or a target"
724 1b7761fd Apollon Oikonomopoulos
                               " node (-n) but not both", errors.ECODE_INVAL)
725 a8083063 Iustin Pop
726 80de0e3f Iustin Pop
  if not force:
727 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
728 a76f0c4a Iustin Pop
729 80de0e3f Iustin Pop
    usertext = ("Failover will happen to image %s."
730 80de0e3f Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
731 80de0e3f Iustin Pop
                (instance_name,))
732 80de0e3f Iustin Pop
    if not AskUser(usertext):
733 80de0e3f Iustin Pop
      return 1
734 a8083063 Iustin Pop
735 019dbee1 Iustin Pop
  op = opcodes.OpInstanceFailover(instance_name=instance_name,
736 17c3f802 Guido Trotter
                                  ignore_consistency=opts.ignore_consistency,
737 1b7761fd Apollon Oikonomopoulos
                                  shutdown_timeout=opts.shutdown_timeout,
738 1b7761fd Apollon Oikonomopoulos
                                  iallocator=iallocator,
739 b6aaf437 René Nussbaumer
                                  target_node=target_node,
740 b6aaf437 René Nussbaumer
                                  ignore_ipolicy=opts.ignore_ipolicy)
741 a76f0c4a Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
742 80de0e3f Iustin Pop
  return 0
743 a8083063 Iustin Pop
744 a8083063 Iustin Pop
745 53c776b5 Iustin Pop
def MigrateInstance(opts, args):
746 53c776b5 Iustin Pop
  """Migrate an instance.
747 53c776b5 Iustin Pop

748 53c776b5 Iustin Pop
  The migrate is done without shutdown.
749 53c776b5 Iustin Pop

750 2f907a8c Iustin Pop
  @param opts: the command line options selected by the user
751 2f907a8c Iustin Pop
  @type args: list
752 2f907a8c Iustin Pop
  @param args: should contain only one element, the instance name
753 2f907a8c Iustin Pop
  @rtype: int
754 2f907a8c Iustin Pop
  @return: the desired exit code
755 53c776b5 Iustin Pop

756 53c776b5 Iustin Pop
  """
757 a76f0c4a Iustin Pop
  cl = GetClient()
758 53c776b5 Iustin Pop
  instance_name = args[0]
759 53c776b5 Iustin Pop
  force = opts.force
760 1b7761fd Apollon Oikonomopoulos
  iallocator = opts.iallocator
761 1b7761fd Apollon Oikonomopoulos
  target_node = opts.dst_node
762 1b7761fd Apollon Oikonomopoulos
763 1b7761fd Apollon Oikonomopoulos
  if iallocator and target_node:
764 1b7761fd Apollon Oikonomopoulos
    raise errors.OpPrereqError("Specify either an iallocator (-I), or a target"
765 1b7761fd Apollon Oikonomopoulos
                               " node (-n) but not both", errors.ECODE_INVAL)
766 53c776b5 Iustin Pop
767 53c776b5 Iustin Pop
  if not force:
768 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
769 a76f0c4a Iustin Pop
770 53c776b5 Iustin Pop
    if opts.cleanup:
771 53c776b5 Iustin Pop
      usertext = ("Instance %s will be recovered from a failed migration."
772 53c776b5 Iustin Pop
                  " Note that the migration procedure (including cleanup)" %
773 53c776b5 Iustin Pop
                  (instance_name,))
774 53c776b5 Iustin Pop
    else:
775 53c776b5 Iustin Pop
      usertext = ("Instance %s will be migrated. Note that migration" %
776 53c776b5 Iustin Pop
                  (instance_name,))
777 cf29cfb6 Iustin Pop
    usertext += (" might impact the instance if anything goes wrong"
778 cf29cfb6 Iustin Pop
                 " (e.g. due to bugs in the hypervisor). Continue?")
779 53c776b5 Iustin Pop
    if not AskUser(usertext):
780 53c776b5 Iustin Pop
      return 1
781 53c776b5 Iustin Pop
782 e71b9ef4 Iustin Pop
  # this should be removed once --non-live is deprecated
783 783a6c0b Iustin Pop
  if not opts.live and opts.migration_mode is not None:
784 e71b9ef4 Iustin Pop
    raise errors.OpPrereqError("Only one of the --non-live and "
785 783a6c0b Iustin Pop
                               "--migration-mode options can be passed",
786 e71b9ef4 Iustin Pop
                               errors.ECODE_INVAL)
787 e71b9ef4 Iustin Pop
  if not opts.live: # --non-live passed
788 8c35561f Iustin Pop
    mode = constants.HT_MIGRATION_NONLIVE
789 e71b9ef4 Iustin Pop
  else:
790 8c35561f Iustin Pop
    mode = opts.migration_mode
791 e71b9ef4 Iustin Pop
792 75c866c2 Iustin Pop
  op = opcodes.OpInstanceMigrate(instance_name=instance_name, mode=mode,
793 1b7761fd Apollon Oikonomopoulos
                                 cleanup=opts.cleanup, iallocator=iallocator,
794 e9c487be René Nussbaumer
                                 target_node=target_node,
795 3ed23330 René Nussbaumer
                                 allow_failover=opts.allow_failover,
796 8c0b16f6 Guido Trotter
                                 allow_runtime_changes=opts.allow_runtime_chgs,
797 3ed23330 René Nussbaumer
                                 ignore_ipolicy=opts.ignore_ipolicy)
798 f70bb622 Michael Hanselmann
  SubmitOrSend(op, cl=cl, opts=opts)
799 53c776b5 Iustin Pop
  return 0
800 53c776b5 Iustin Pop
801 53c776b5 Iustin Pop
802 fbf5a861 Iustin Pop
def MoveInstance(opts, args):
803 fbf5a861 Iustin Pop
  """Move an instance.
804 fbf5a861 Iustin Pop

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

811 fbf5a861 Iustin Pop
  """
812 fbf5a861 Iustin Pop
  cl = GetClient()
813 fbf5a861 Iustin Pop
  instance_name = args[0]
814 fbf5a861 Iustin Pop
  force = opts.force
815 fbf5a861 Iustin Pop
816 fbf5a861 Iustin Pop
  if not force:
817 fbf5a861 Iustin Pop
    usertext = ("Instance %s will be moved."
818 fbf5a861 Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
819 fbf5a861 Iustin Pop
                (instance_name,))
820 fbf5a861 Iustin Pop
    if not AskUser(usertext):
821 fbf5a861 Iustin Pop
      return 1
822 fbf5a861 Iustin Pop
823 0091b480 Iustin Pop
  op = opcodes.OpInstanceMove(instance_name=instance_name,
824 17c3f802 Guido Trotter
                              target_node=opts.node,
825 bb851c63 Iustin Pop
                              shutdown_timeout=opts.shutdown_timeout,
826 92cf62e3 René Nussbaumer
                              ignore_consistency=opts.ignore_consistency,
827 92cf62e3 René Nussbaumer
                              ignore_ipolicy=opts.ignore_ipolicy)
828 fbf5a861 Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
829 fbf5a861 Iustin Pop
  return 0
830 fbf5a861 Iustin Pop
831 fbf5a861 Iustin Pop
832 a8083063 Iustin Pop
def ConnectToInstanceConsole(opts, args):
833 a8083063 Iustin Pop
  """Connect to the console of an instance.
834 a8083063 Iustin Pop

835 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
836 7232c04c Iustin Pop
  @type args: list
837 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
838 7232c04c Iustin Pop
  @rtype: int
839 7232c04c Iustin Pop
  @return: the desired exit code
840 a8083063 Iustin Pop

841 a8083063 Iustin Pop
  """
842 a8083063 Iustin Pop
  instance_name = args[0]
843 a8083063 Iustin Pop
844 25ce3ec4 Michael Hanselmann
  cl = GetClient()
845 25ce3ec4 Michael Hanselmann
  try:
846 25ce3ec4 Michael Hanselmann
    cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
847 d6f46b6a Michael Hanselmann
    ((console_data, oper_state), ) = \
848 d6f46b6a Michael Hanselmann
      cl.QueryInstances([instance_name], ["console", "oper_state"], False)
849 25ce3ec4 Michael Hanselmann
  finally:
850 25ce3ec4 Michael Hanselmann
    # Ensure client connection is closed while external commands are run
851 25ce3ec4 Michael Hanselmann
    cl.Close()
852 25ce3ec4 Michael Hanselmann
853 25ce3ec4 Michael Hanselmann
  del cl
854 25ce3ec4 Michael Hanselmann
855 d6f46b6a Michael Hanselmann
  if not console_data:
856 d6f46b6a Michael Hanselmann
    if oper_state:
857 d6f46b6a Michael Hanselmann
      # Instance is running
858 d6f46b6a Michael Hanselmann
      raise errors.OpExecError("Console information for instance %s is"
859 d6f46b6a Michael Hanselmann
                               " unavailable" % instance_name)
860 d6f46b6a Michael Hanselmann
    else:
861 d6f46b6a Michael Hanselmann
      raise errors.OpExecError("Instance %s is not running, can't get console" %
862 d6f46b6a Michael Hanselmann
                               instance_name)
863 d6f46b6a Michael Hanselmann
864 25ce3ec4 Michael Hanselmann
  return _DoConsole(objects.InstanceConsole.FromDict(console_data),
865 25ce3ec4 Michael Hanselmann
                    opts.show_command, cluster_name)
866 25ce3ec4 Michael Hanselmann
867 25ce3ec4 Michael Hanselmann
868 25ce3ec4 Michael Hanselmann
def _DoConsole(console, show_command, cluster_name, feedback_fn=ToStdout,
869 25ce3ec4 Michael Hanselmann
               _runcmd_fn=utils.RunCmd):
870 cc0dec7b Iustin Pop
  """Acts based on the result of L{opcodes.OpInstanceConsole}.
871 25ce3ec4 Michael Hanselmann

872 25ce3ec4 Michael Hanselmann
  @type console: L{objects.InstanceConsole}
873 25ce3ec4 Michael Hanselmann
  @param console: Console object
874 25ce3ec4 Michael Hanselmann
  @type show_command: bool
875 25ce3ec4 Michael Hanselmann
  @param show_command: Whether to just display commands
876 25ce3ec4 Michael Hanselmann
  @type cluster_name: string
877 25ce3ec4 Michael Hanselmann
  @param cluster_name: Cluster name as retrieved from master daemon
878 25ce3ec4 Michael Hanselmann

879 25ce3ec4 Michael Hanselmann
  """
880 25ce3ec4 Michael Hanselmann
  assert console.Validate()
881 25ce3ec4 Michael Hanselmann
882 25ce3ec4 Michael Hanselmann
  if console.kind == constants.CONS_MESSAGE:
883 25ce3ec4 Michael Hanselmann
    feedback_fn(console.message)
884 25ce3ec4 Michael Hanselmann
  elif console.kind == constants.CONS_VNC:
885 25ce3ec4 Michael Hanselmann
    feedback_fn("Instance %s has VNC listening on %s:%s (display %s),"
886 25ce3ec4 Michael Hanselmann
                " URL <vnc://%s:%s/>",
887 25ce3ec4 Michael Hanselmann
                console.instance, console.host, console.port,
888 25ce3ec4 Michael Hanselmann
                console.display, console.host, console.port)
889 4d2cdb5a Andrea Spadaccini
  elif console.kind == constants.CONS_SPICE:
890 4d2cdb5a Andrea Spadaccini
    feedback_fn("Instance %s has SPICE listening on %s:%s", console.instance,
891 4d2cdb5a Andrea Spadaccini
                console.host, console.port)
892 25ce3ec4 Michael Hanselmann
  elif console.kind == constants.CONS_SSH:
893 25ce3ec4 Michael Hanselmann
    # Convert to string if not already one
894 25ce3ec4 Michael Hanselmann
    if isinstance(console.command, basestring):
895 25ce3ec4 Michael Hanselmann
      cmd = console.command
896 25ce3ec4 Michael Hanselmann
    else:
897 25ce3ec4 Michael Hanselmann
      cmd = utils.ShellQuoteArgs(console.command)
898 25ce3ec4 Michael Hanselmann
899 25ce3ec4 Michael Hanselmann
    srun = ssh.SshRunner(cluster_name=cluster_name)
900 25ce3ec4 Michael Hanselmann
    ssh_cmd = srun.BuildCmd(console.host, console.user, cmd,
901 25ce3ec4 Michael Hanselmann
                            batch=True, quiet=False, tty=True)
902 25ce3ec4 Michael Hanselmann
903 25ce3ec4 Michael Hanselmann
    if show_command:
904 25ce3ec4 Michael Hanselmann
      feedback_fn(utils.ShellQuoteArgs(ssh_cmd))
905 25ce3ec4 Michael Hanselmann
    else:
906 25ce3ec4 Michael Hanselmann
      result = _runcmd_fn(ssh_cmd, interactive=True)
907 25ce3ec4 Michael Hanselmann
      if result.failed:
908 25ce3ec4 Michael Hanselmann
        logging.error("Console command \"%s\" failed with reason '%s' and"
909 25ce3ec4 Michael Hanselmann
                      " output %r", result.cmd, result.fail_reason,
910 25ce3ec4 Michael Hanselmann
                      result.output)
911 25ce3ec4 Michael Hanselmann
        raise errors.OpExecError("Connection to console of instance %s failed,"
912 25ce3ec4 Michael Hanselmann
                                 " please check cluster configuration" %
913 25ce3ec4 Michael Hanselmann
                                 console.instance)
914 51c6e7b5 Michael Hanselmann
  else:
915 25ce3ec4 Michael Hanselmann
    raise errors.GenericError("Unknown console type '%s'" % console.kind)
916 678aa6d3 Michael Hanselmann
917 678aa6d3 Michael Hanselmann
  return constants.EXIT_SUCCESS
918 a8083063 Iustin Pop
919 a8083063 Iustin Pop
920 e2736e40 Guido Trotter
def _FormatLogicalID(dev_type, logical_id, roman):
921 19708787 Iustin Pop
  """Formats the logical_id of a disk.
922 19708787 Iustin Pop

923 19708787 Iustin Pop
  """
924 19708787 Iustin Pop
  if dev_type == constants.LD_DRBD8:
925 19708787 Iustin Pop
    node_a, node_b, port, minor_a, minor_b, key = logical_id
926 19708787 Iustin Pop
    data = [
927 e2736e40 Guido Trotter
      ("nodeA", "%s, minor=%s" % (node_a, compat.TryToRoman(minor_a,
928 e2736e40 Guido Trotter
                                                            convert=roman))),
929 e2736e40 Guido Trotter
      ("nodeB", "%s, minor=%s" % (node_b, compat.TryToRoman(minor_b,
930 e2736e40 Guido Trotter
                                                            convert=roman))),
931 e2736e40 Guido Trotter
      ("port", compat.TryToRoman(port, convert=roman)),
932 19708787 Iustin Pop
      ("auth key", key),
933 19708787 Iustin Pop
      ]
934 19708787 Iustin Pop
  elif dev_type == constants.LD_LV:
935 19708787 Iustin Pop
    vg_name, lv_name = logical_id
936 19708787 Iustin Pop
    data = ["%s/%s" % (vg_name, lv_name)]
937 19708787 Iustin Pop
  else:
938 19708787 Iustin Pop
    data = [str(logical_id)]
939 19708787 Iustin Pop
940 19708787 Iustin Pop
  return data
941 19708787 Iustin Pop
942 19708787 Iustin Pop
943 f965260c Michael Hanselmann
def _FormatBlockDevInfo(idx, top_level, dev, roman):
944 a8083063 Iustin Pop
  """Show block device information.
945 a8083063 Iustin Pop

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

949 19708787 Iustin Pop
  @type idx: int
950 19708787 Iustin Pop
  @param idx: the index of the current disk
951 19708787 Iustin Pop
  @type top_level: boolean
952 19708787 Iustin Pop
  @param top_level: if this a top-level disk?
953 7232c04c Iustin Pop
  @type dev: dict
954 7232c04c Iustin Pop
  @param dev: dictionary with disk information
955 e2736e40 Guido Trotter
  @type roman: boolean
956 e2736e40 Guido Trotter
  @param roman: whether to try to use roman integers
957 19708787 Iustin Pop
  @return: a list of either strings, tuples or lists
958 19708787 Iustin Pop
      (which should be formatted at a higher indent level)
959 7232c04c Iustin Pop

960 a8083063 Iustin Pop
  """
961 19708787 Iustin Pop
  def helper(dtype, status):
962 7232c04c Iustin Pop
    """Format one line for physical device status.
963 7232c04c Iustin Pop

964 7232c04c Iustin Pop
    @type dtype: str
965 7232c04c Iustin Pop
    @param dtype: a constant from the L{constants.LDS_BLOCK} set
966 7232c04c Iustin Pop
    @type status: tuple
967 7232c04c Iustin Pop
    @param status: a tuple as returned from L{backend.FindBlockDevice}
968 19708787 Iustin Pop
    @return: the string representing the status
969 7232c04c Iustin Pop

970 7232c04c Iustin Pop
    """
971 a8083063 Iustin Pop
    if not status:
972 19708787 Iustin Pop
      return "not active"
973 19708787 Iustin Pop
    txt = ""
974 f208978a Michael Hanselmann
    (path, major, minor, syncp, estt, degr, ldisk_status) = status
975 19708787 Iustin Pop
    if major is None:
976 19708787 Iustin Pop
      major_string = "N/A"
977 a8083063 Iustin Pop
    else:
978 e2736e40 Guido Trotter
      major_string = str(compat.TryToRoman(major, convert=roman))
979 fd38ef95 Manuel Franceschini
980 19708787 Iustin Pop
    if minor is None:
981 19708787 Iustin Pop
      minor_string = "N/A"
982 19708787 Iustin Pop
    else:
983 e2736e40 Guido Trotter
      minor_string = str(compat.TryToRoman(minor, convert=roman))
984 19708787 Iustin Pop
985 19708787 Iustin Pop
    txt += ("%s (%s:%s)" % (path, major_string, minor_string))
986 19708787 Iustin Pop
    if dtype in (constants.LD_DRBD8, ):
987 19708787 Iustin Pop
      if syncp is not None:
988 19708787 Iustin Pop
        sync_text = "*RECOVERING* %5.2f%%," % syncp
989 19708787 Iustin Pop
        if estt:
990 e2736e40 Guido Trotter
          sync_text += " ETA %ss" % compat.TryToRoman(estt, convert=roman)
991 9db6dbce Iustin Pop
        else:
992 19708787 Iustin Pop
          sync_text += " ETA unknown"
993 19708787 Iustin Pop
      else:
994 19708787 Iustin Pop
        sync_text = "in sync"
995 19708787 Iustin Pop
      if degr:
996 19708787 Iustin Pop
        degr_text = "*DEGRADED*"
997 19708787 Iustin Pop
      else:
998 19708787 Iustin Pop
        degr_text = "ok"
999 f208978a Michael Hanselmann
      if ldisk_status == constants.LDS_FAULTY:
1000 19708787 Iustin Pop
        ldisk_text = " *MISSING DISK*"
1001 f208978a Michael Hanselmann
      elif ldisk_status == constants.LDS_UNKNOWN:
1002 f208978a Michael Hanselmann
        ldisk_text = " *UNCERTAIN STATE*"
1003 19708787 Iustin Pop
      else:
1004 19708787 Iustin Pop
        ldisk_text = ""
1005 19708787 Iustin Pop
      txt += (" %s, status %s%s" % (sync_text, degr_text, ldisk_text))
1006 19708787 Iustin Pop
    elif dtype == constants.LD_LV:
1007 f208978a Michael Hanselmann
      if ldisk_status == constants.LDS_FAULTY:
1008 19708787 Iustin Pop
        ldisk_text = " *FAILED* (failed drive?)"
1009 19708787 Iustin Pop
      else:
1010 19708787 Iustin Pop
        ldisk_text = ""
1011 19708787 Iustin Pop
      txt += ldisk_text
1012 19708787 Iustin Pop
    return txt
1013 19708787 Iustin Pop
1014 19708787 Iustin Pop
  # the header
1015 19708787 Iustin Pop
  if top_level:
1016 19708787 Iustin Pop
    if dev["iv_name"] is not None:
1017 19708787 Iustin Pop
      txt = dev["iv_name"]
1018 19708787 Iustin Pop
    else:
1019 e2736e40 Guido Trotter
      txt = "disk %s" % compat.TryToRoman(idx, convert=roman)
1020 a8083063 Iustin Pop
  else:
1021 e2736e40 Guido Trotter
    txt = "child %s" % compat.TryToRoman(idx, convert=roman)
1022 c98162a7 Iustin Pop
  if isinstance(dev["size"], int):
1023 c98162a7 Iustin Pop
    nice_size = utils.FormatUnit(dev["size"], "h")
1024 c98162a7 Iustin Pop
  else:
1025 c98162a7 Iustin Pop
    nice_size = dev["size"]
1026 c98162a7 Iustin Pop
  d1 = ["- %s: %s, size %s" % (txt, dev["dev_type"], nice_size)]
1027 19708787 Iustin Pop
  data = []
1028 19708787 Iustin Pop
  if top_level:
1029 19708787 Iustin Pop
    data.append(("access mode", dev["mode"]))
1030 a8083063 Iustin Pop
  if dev["logical_id"] is not None:
1031 19708787 Iustin Pop
    try:
1032 e2736e40 Guido Trotter
      l_id = _FormatLogicalID(dev["dev_type"], dev["logical_id"], roman)
1033 19708787 Iustin Pop
    except ValueError:
1034 19708787 Iustin Pop
      l_id = [str(dev["logical_id"])]
1035 19708787 Iustin Pop
    if len(l_id) == 1:
1036 19708787 Iustin Pop
      data.append(("logical_id", l_id[0]))
1037 19708787 Iustin Pop
    else:
1038 19708787 Iustin Pop
      data.extend(l_id)
1039 a8083063 Iustin Pop
  elif dev["physical_id"] is not None:
1040 19708787 Iustin Pop
    data.append("physical_id:")
1041 19708787 Iustin Pop
    data.append([dev["physical_id"]])
1042 f965260c Michael Hanselmann
1043 f965260c Michael Hanselmann
  if dev["pstatus"]:
1044 19708787 Iustin Pop
    data.append(("on primary", helper(dev["dev_type"], dev["pstatus"])))
1045 f965260c Michael Hanselmann
1046 f965260c Michael Hanselmann
  if dev["sstatus"]:
1047 19708787 Iustin Pop
    data.append(("on secondary", helper(dev["dev_type"], dev["sstatus"])))
1048 a8083063 Iustin Pop
1049 a8083063 Iustin Pop
  if dev["children"]:
1050 19708787 Iustin Pop
    data.append("child devices:")
1051 19708787 Iustin Pop
    for c_idx, child in enumerate(dev["children"]):
1052 f965260c Michael Hanselmann
      data.append(_FormatBlockDevInfo(c_idx, False, child, roman))
1053 19708787 Iustin Pop
  d1.append(data)
1054 19708787 Iustin Pop
  return d1
1055 a8083063 Iustin Pop
1056 a8083063 Iustin Pop
1057 19708787 Iustin Pop
def _FormatList(buf, data, indent_level):
1058 19708787 Iustin Pop
  """Formats a list of data at a given indent level.
1059 19708787 Iustin Pop

1060 19708787 Iustin Pop
  If the element of the list is:
1061 19708787 Iustin Pop
    - a string, it is simply formatted as is
1062 19708787 Iustin Pop
    - a tuple, it will be split into key, value and the all the
1063 19708787 Iustin Pop
      values in a list will be aligned all at the same start column
1064 19708787 Iustin Pop
    - a list, will be recursively formatted
1065 19708787 Iustin Pop

1066 19708787 Iustin Pop
  @type buf: StringIO
1067 19708787 Iustin Pop
  @param buf: the buffer into which we write the output
1068 19708787 Iustin Pop
  @param data: the list to format
1069 19708787 Iustin Pop
  @type indent_level: int
1070 19708787 Iustin Pop
  @param indent_level: the indent level to format at
1071 19708787 Iustin Pop

1072 19708787 Iustin Pop
  """
1073 19708787 Iustin Pop
  max_tlen = max([len(elem[0]) for elem in data
1074 19708787 Iustin Pop
                 if isinstance(elem, tuple)] or [0])
1075 19708787 Iustin Pop
  for elem in data:
1076 19708787 Iustin Pop
    if isinstance(elem, basestring):
1077 e687ec01 Michael Hanselmann
      buf.write("%*s%s\n" % (2 * indent_level, "", elem))
1078 19708787 Iustin Pop
    elif isinstance(elem, tuple):
1079 19708787 Iustin Pop
      key, value = elem
1080 19708787 Iustin Pop
      spacer = "%*s" % (max_tlen - len(key), "")
1081 e687ec01 Michael Hanselmann
      buf.write("%*s%s:%s %s\n" % (2 * indent_level, "", key, spacer, value))
1082 19708787 Iustin Pop
    elif isinstance(elem, list):
1083 e687ec01 Michael Hanselmann
      _FormatList(buf, elem, indent_level + 1)
1084 19708787 Iustin Pop
1085 98825740 Michael Hanselmann
1086 a8083063 Iustin Pop
def ShowInstanceConfig(opts, args):
1087 a8083063 Iustin Pop
  """Compute instance run-time status.
1088 a8083063 Iustin Pop

1089 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1090 7232c04c Iustin Pop
  @type args: list
1091 7232c04c Iustin Pop
  @param args: either an empty list, and then we query all
1092 7232c04c Iustin Pop
      instances, or should contain a list of instance names
1093 7232c04c Iustin Pop
  @rtype: int
1094 7232c04c Iustin Pop
  @return: the desired exit code
1095 7232c04c Iustin Pop

1096 a8083063 Iustin Pop
  """
1097 220cde0b Guido Trotter
  if not args and not opts.show_all:
1098 220cde0b Guido Trotter
    ToStderr("No instance selected."
1099 220cde0b Guido Trotter
             " Please pass in --all if you want to query all instances.\n"
1100 220cde0b Guido Trotter
             "Note that this can take a long time on a big cluster.")
1101 220cde0b Guido Trotter
    return 1
1102 220cde0b Guido Trotter
  elif args and opts.show_all:
1103 220cde0b Guido Trotter
    ToStderr("Cannot use --all if you specify instance names.")
1104 220cde0b Guido Trotter
    return 1
1105 220cde0b Guido Trotter
1106 a8083063 Iustin Pop
  retcode = 0
1107 5c097318 Iustin Pop
  op = opcodes.OpInstanceQueryData(instances=args, static=opts.static,
1108 5c097318 Iustin Pop
                                   use_locking=not opts.static)
1109 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
1110 a8083063 Iustin Pop
  if not result:
1111 3a24c527 Iustin Pop
    ToStdout("No instances.")
1112 a8083063 Iustin Pop
    return 1
1113 a8083063 Iustin Pop
1114 a8083063 Iustin Pop
  buf = StringIO()
1115 a8083063 Iustin Pop
  retcode = 0
1116 a8083063 Iustin Pop
  for instance_name in result:
1117 a8083063 Iustin Pop
    instance = result[instance_name]
1118 a8083063 Iustin Pop
    buf.write("Instance name: %s\n" % instance["name"])
1119 033d58b0 Iustin Pop
    buf.write("UUID: %s\n" % instance["uuid"])
1120 e2736e40 Guido Trotter
    buf.write("Serial number: %s\n" %
1121 e2736e40 Guido Trotter
              compat.TryToRoman(instance["serial_no"],
1122 e2736e40 Guido Trotter
                                convert=opts.roman_integers))
1123 90f72445 Iustin Pop
    buf.write("Creation time: %s\n" % utils.FormatTime(instance["ctime"]))
1124 90f72445 Iustin Pop
    buf.write("Modification time: %s\n" % utils.FormatTime(instance["mtime"]))
1125 57821cac Iustin Pop
    buf.write("State: configured to be %s" % instance["config_state"])
1126 f965260c Michael Hanselmann
    if instance["run_state"]:
1127 57821cac Iustin Pop
      buf.write(", actual state is %s" % instance["run_state"])
1128 57821cac Iustin Pop
    buf.write("\n")
1129 57821cac Iustin Pop
    ##buf.write("Considered for memory checks in cluster verify: %s\n" %
1130 57821cac Iustin Pop
    ##          instance["auto_balance"])
1131 a8083063 Iustin Pop
    buf.write("  Nodes:\n")
1132 a8083063 Iustin Pop
    buf.write("    - primary: %s\n" % instance["pnode"])
1133 080fbeea Michael Hanselmann
    buf.write("      group: %s (UUID %s)\n" %
1134 080fbeea Michael Hanselmann
              (instance["pnode_group_name"], instance["pnode_group_uuid"]))
1135 080fbeea Michael Hanselmann
    buf.write("    - secondaries: %s\n" %
1136 080fbeea Michael Hanselmann
              utils.CommaJoin("%s (group %s, group UUID %s)" %
1137 080fbeea Michael Hanselmann
                                (name, group_name, group_uuid)
1138 080fbeea Michael Hanselmann
                              for (name, group_name, group_uuid) in
1139 080fbeea Michael Hanselmann
                                zip(instance["snodes"],
1140 080fbeea Michael Hanselmann
                                    instance["snodes_group_names"],
1141 080fbeea Michael Hanselmann
                                    instance["snodes_group_uuids"])))
1142 a8083063 Iustin Pop
    buf.write("  Operating system: %s\n" % instance["os"])
1143 acd19189 René Nussbaumer
    FormatParameterDict(buf, instance["os_instance"], instance["os_actual"],
1144 acd19189 René Nussbaumer
                        level=2)
1145 e687ec01 Michael Hanselmann
    if "network_port" in instance:
1146 e2736e40 Guido Trotter
      buf.write("  Allocated network port: %s\n" %
1147 e2736e40 Guido Trotter
                compat.TryToRoman(instance["network_port"],
1148 e2736e40 Guido Trotter
                                  convert=opts.roman_integers))
1149 24838135 Iustin Pop
    buf.write("  Hypervisor: %s\n" % instance["hypervisor"])
1150 dfff41f8 Guido Trotter
1151 dfff41f8 Guido Trotter
    # custom VNC console information
1152 dfff41f8 Guido Trotter
    vnc_bind_address = instance["hv_actual"].get(constants.HV_VNC_BIND_ADDRESS,
1153 dfff41f8 Guido Trotter
                                                 None)
1154 dfff41f8 Guido Trotter
    if vnc_bind_address:
1155 dfff41f8 Guido Trotter
      port = instance["network_port"]
1156 dfff41f8 Guido Trotter
      display = int(port) - constants.VNC_BASE_PORT
1157 9769bb78 Manuel Franceschini
      if display > 0 and vnc_bind_address == constants.IP4_ADDRESS_ANY:
1158 dfff41f8 Guido Trotter
        vnc_console_port = "%s:%s (display %s)" % (instance["pnode"],
1159 dfff41f8 Guido Trotter
                                                   port,
1160 dfff41f8 Guido Trotter
                                                   display)
1161 8b312c1d Manuel Franceschini
      elif display > 0 and netutils.IP4Address.IsValid(vnc_bind_address):
1162 dfff41f8 Guido Trotter
        vnc_console_port = ("%s:%s (node %s) (display %s)" %
1163 dfff41f8 Guido Trotter
                             (vnc_bind_address, port,
1164 dfff41f8 Guido Trotter
                              instance["pnode"], display))
1165 a8340917 Iustin Pop
      else:
1166 dfff41f8 Guido Trotter
        # vnc bind address is a file
1167 dfff41f8 Guido Trotter
        vnc_console_port = "%s:%s" % (instance["pnode"],
1168 dfff41f8 Guido Trotter
                                      vnc_bind_address)
1169 24838135 Iustin Pop
      buf.write("    - console connection: vnc to %s\n" % vnc_console_port)
1170 24838135 Iustin Pop
1171 acd19189 René Nussbaumer
    FormatParameterDict(buf, instance["hv_instance"], instance["hv_actual"],
1172 acd19189 René Nussbaumer
                        level=2)
1173 a8083063 Iustin Pop
    buf.write("  Hardware:\n")
1174 b5ef2316 Guido Trotter
    # deprecated "memory" value, kept for one version for compatibility
1175 b5ef2316 Guido Trotter
    # TODO(ganeti 2.7) remove.
1176 83d4ba5e René Nussbaumer
    be_actual = copy.deepcopy(instance["be_actual"])
1177 83d4ba5e René Nussbaumer
    be_actual["memory"] = be_actual[constants.BE_MAXMEM]
1178 83d4ba5e René Nussbaumer
    FormatParameterDict(buf, instance["be_instance"], be_actual, level=2)
1179 83d4ba5e René Nussbaumer
    # TODO(ganeti 2.7) rework the NICs as well
1180 d2acfe27 Iustin Pop
    buf.write("    - NICs:\n")
1181 cbe4a0a5 Dimitris Aragiorgis
    for idx, (ip, mac, mode, link, network, _) in enumerate(instance["nics"]):
1182 d4117a72 Apollon Oikonomopoulos
      buf.write("      - nic/%d: MAC: %s, IP: %s,"
1183 d4117a72 Apollon Oikonomopoulos
                " mode: %s, link: %s, network: %s\n" %
1184 d4117a72 Apollon Oikonomopoulos
                (idx, mac, ip, mode, link, network))
1185 b577dac4 Michael Hanselmann
    buf.write("  Disk template: %s\n" % instance["disk_template"])
1186 19708787 Iustin Pop
    buf.write("  Disks:\n")
1187 a8083063 Iustin Pop
1188 19708787 Iustin Pop
    for idx, device in enumerate(instance["disks"]):
1189 f965260c Michael Hanselmann
      _FormatList(buf, _FormatBlockDevInfo(idx, True, device,
1190 e2736e40 Guido Trotter
                  opts.roman_integers), 2)
1191 a8083063 Iustin Pop
1192 d0c8c01d Iustin Pop
  ToStdout(buf.getvalue().rstrip("\n"))
1193 a8083063 Iustin Pop
  return retcode
1194 a8083063 Iustin Pop
1195 a8083063 Iustin Pop
1196 a71f835e Michael Hanselmann
def _ConvertNicDiskModifications(mods):
1197 a71f835e Michael Hanselmann
  """Converts NIC/disk modifications from CLI to opcode.
1198 a71f835e Michael Hanselmann

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

1204 a71f835e Michael Hanselmann
  @type mods: list of tuples
1205 a71f835e Michael Hanselmann
  @param mods: Modifications as given by command line parser
1206 a71f835e Michael Hanselmann
  @rtype: list of tuples
1207 a71f835e Michael Hanselmann
  @return: Modifications as understood by L{opcodes.OpInstanceSetParams}
1208 a71f835e Michael Hanselmann

1209 a71f835e Michael Hanselmann
  """
1210 a71f835e Michael Hanselmann
  result = []
1211 a71f835e Michael Hanselmann
1212 a71f835e Michael Hanselmann
  for (idx, params) in mods:
1213 a71f835e Michael Hanselmann
    if idx == constants.DDM_ADD:
1214 a71f835e Michael Hanselmann
      # Add item as last item (legacy interface)
1215 a71f835e Michael Hanselmann
      action = constants.DDM_ADD
1216 a71f835e Michael Hanselmann
      idxno = -1
1217 a71f835e Michael Hanselmann
    elif idx == constants.DDM_REMOVE:
1218 a71f835e Michael Hanselmann
      # Remove last item (legacy interface)
1219 a71f835e Michael Hanselmann
      action = constants.DDM_REMOVE
1220 a71f835e Michael Hanselmann
      idxno = -1
1221 a71f835e Michael Hanselmann
    else:
1222 a71f835e Michael Hanselmann
      # Modifications and adding/removing at arbitrary indices
1223 a71f835e Michael Hanselmann
      try:
1224 a71f835e Michael Hanselmann
        idxno = int(idx)
1225 a71f835e Michael Hanselmann
      except (TypeError, ValueError):
1226 a71f835e Michael Hanselmann
        raise errors.OpPrereqError("Non-numeric index '%s'" % idx,
1227 a71f835e Michael Hanselmann
                                   errors.ECODE_INVAL)
1228 a71f835e Michael Hanselmann
1229 a71f835e Michael Hanselmann
      add = params.pop(constants.DDM_ADD, _MISSING)
1230 a71f835e Michael Hanselmann
      remove = params.pop(constants.DDM_REMOVE, _MISSING)
1231 f0d22861 Constantinos Venetsanopoulos
      modify = params.pop(constants.DDM_MODIFY, _MISSING)
1232 f0d22861 Constantinos Venetsanopoulos
1233 f0d22861 Constantinos Venetsanopoulos
      if modify is _MISSING:
1234 f0d22861 Constantinos Venetsanopoulos
        if not (add is _MISSING or remove is _MISSING):
1235 f0d22861 Constantinos Venetsanopoulos
          raise errors.OpPrereqError("Cannot add and remove at the same time",
1236 f0d22861 Constantinos Venetsanopoulos
                                     errors.ECODE_INVAL)
1237 f0d22861 Constantinos Venetsanopoulos
        elif add is not _MISSING:
1238 f0d22861 Constantinos Venetsanopoulos
          action = constants.DDM_ADD
1239 f0d22861 Constantinos Venetsanopoulos
        elif remove is not _MISSING:
1240 f0d22861 Constantinos Venetsanopoulos
          action = constants.DDM_REMOVE
1241 f0d22861 Constantinos Venetsanopoulos
        else:
1242 f0d22861 Constantinos Venetsanopoulos
          action = constants.DDM_MODIFY
1243 a71f835e Michael Hanselmann
1244 7a70541e Michael Hanselmann
      elif add is _MISSING and remove is _MISSING:
1245 7a70541e Michael Hanselmann
        action = constants.DDM_MODIFY
1246 a71f835e Michael Hanselmann
      else:
1247 7a70541e Michael Hanselmann
        raise errors.OpPrereqError("Cannot modify and add/remove at the"
1248 7a70541e Michael Hanselmann
                                   " same time", errors.ECODE_INVAL)
1249 a71f835e Michael Hanselmann
1250 a71f835e Michael Hanselmann
      assert not (constants.DDMS_VALUES_WITH_MODIFY & set(params.keys()))
1251 a71f835e Michael Hanselmann
1252 a71f835e Michael Hanselmann
    if action == constants.DDM_REMOVE and params:
1253 a71f835e Michael Hanselmann
      raise errors.OpPrereqError("Not accepting parameters on removal",
1254 a71f835e Michael Hanselmann
                                 errors.ECODE_INVAL)
1255 a71f835e Michael Hanselmann
1256 a71f835e Michael Hanselmann
    result.append((action, idxno, params))
1257 a71f835e Michael Hanselmann
1258 a71f835e Michael Hanselmann
  return result
1259 a71f835e Michael Hanselmann
1260 a71f835e Michael Hanselmann
1261 a71f835e Michael Hanselmann
def _ParseDiskSizes(mods):
1262 a71f835e Michael Hanselmann
  """Parses disk sizes in parameters.
1263 a71f835e Michael Hanselmann

1264 a71f835e Michael Hanselmann
  """
1265 a71f835e Michael Hanselmann
  for (action, _, params) in mods:
1266 a71f835e Michael Hanselmann
    if params and constants.IDISK_SIZE in params:
1267 a71f835e Michael Hanselmann
      params[constants.IDISK_SIZE] = \
1268 a71f835e Michael Hanselmann
        utils.ParseUnit(params[constants.IDISK_SIZE])
1269 a71f835e Michael Hanselmann
    elif action == constants.DDM_ADD:
1270 a71f835e Michael Hanselmann
      raise errors.OpPrereqError("Missing required parameter 'size'",
1271 a71f835e Michael Hanselmann
                                 errors.ECODE_INVAL)
1272 a71f835e Michael Hanselmann
1273 a71f835e Michael Hanselmann
  return mods
1274 a71f835e Michael Hanselmann
1275 a71f835e Michael Hanselmann
1276 7767bbf5 Manuel Franceschini
def SetInstanceParams(opts, args):
1277 a8083063 Iustin Pop
  """Modifies an instance.
1278 a8083063 Iustin Pop

1279 a8083063 Iustin Pop
  All parameters take effect only at the next restart of the instance.
1280 a8083063 Iustin Pop

1281 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1282 7232c04c Iustin Pop
  @type args: list
1283 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
1284 7232c04c Iustin Pop
  @rtype: int
1285 7232c04c Iustin Pop
  @return: the desired exit code
1286 a8083063 Iustin Pop

1287 a8083063 Iustin Pop
  """
1288 e29e9550 Iustin Pop
  if not (opts.nics or opts.disks or opts.disk_template or
1289 57de31c0 Agata Murawska
          opts.hvparams or opts.beparams or opts.os or opts.osparams or
1290 2c0af7da Guido Trotter
          opts.offline_inst or opts.online_inst or opts.runtime_mem):
1291 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
1292 a8083063 Iustin Pop
    return 1
1293 a8083063 Iustin Pop
1294 467ae11e Guido Trotter
  for param in opts.beparams:
1295 e9d622bc Guido Trotter
    if isinstance(opts.beparams[param], basestring):
1296 e9d622bc Guido Trotter
      if opts.beparams[param].lower() == "default":
1297 e9d622bc Guido Trotter
        opts.beparams[param] = constants.VALUE_DEFAULT
1298 a5728081 Guido Trotter
1299 b2e233a5 Guido Trotter
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_COMPAT,
1300 a5728081 Guido Trotter
                      allowed_values=[constants.VALUE_DEFAULT])
1301 467ae11e Guido Trotter
1302 48f212d7 Iustin Pop
  for param in opts.hvparams:
1303 48f212d7 Iustin Pop
    if isinstance(opts.hvparams[param], basestring):
1304 48f212d7 Iustin Pop
      if opts.hvparams[param].lower() == "default":
1305 48f212d7 Iustin Pop
        opts.hvparams[param] = constants.VALUE_DEFAULT
1306 a5728081 Guido Trotter
1307 48f212d7 Iustin Pop
  utils.ForceDictType(opts.hvparams, constants.HVS_PARAMETER_TYPES,
1308 a5728081 Guido Trotter
                      allowed_values=[constants.VALUE_DEFAULT])
1309 61be6ba4 Iustin Pop
1310 a71f835e Michael Hanselmann
  nics = _ConvertNicDiskModifications(opts.nics)
1311 a71f835e Michael Hanselmann
  disks = _ParseDiskSizes(_ConvertNicDiskModifications(opts.disks))
1312 24991749 Iustin Pop
1313 e29e9550 Iustin Pop
  if (opts.disk_template and
1314 3429a076 Apollon Oikonomopoulos
      opts.disk_template in constants.DTS_INT_MIRROR and
1315 e29e9550 Iustin Pop
      not opts.node):
1316 e29e9550 Iustin Pop
    ToStderr("Changing the disk template to a mirrored one requires"
1317 e29e9550 Iustin Pop
             " specifying a secondary node")
1318 e29e9550 Iustin Pop
    return 1
1319 e29e9550 Iustin Pop
1320 3016bc1f Michael Hanselmann
  if opts.offline_inst:
1321 3016bc1f Michael Hanselmann
    offline = True
1322 3016bc1f Michael Hanselmann
  elif opts.online_inst:
1323 3016bc1f Michael Hanselmann
    offline = False
1324 3016bc1f Michael Hanselmann
  else:
1325 3016bc1f Michael Hanselmann
    offline = None
1326 3016bc1f Michael Hanselmann
1327 9a3cc7ae Iustin Pop
  op = opcodes.OpInstanceSetParams(instance_name=args[0],
1328 a71f835e Michael Hanselmann
                                   nics=nics,
1329 a71f835e Michael Hanselmann
                                   disks=disks,
1330 e29e9550 Iustin Pop
                                   disk_template=opts.disk_template,
1331 e29e9550 Iustin Pop
                                   remote_node=opts.node,
1332 48f212d7 Iustin Pop
                                   hvparams=opts.hvparams,
1333 338e51e8 Iustin Pop
                                   beparams=opts.beparams,
1334 2c0af7da Guido Trotter
                                   runtime_mem=opts.runtime_mem,
1335 96b39bcc Iustin Pop
                                   os_name=opts.os,
1336 1052d622 Iustin Pop
                                   osparams=opts.osparams,
1337 96b39bcc Iustin Pop
                                   force_variant=opts.force_variant,
1338 456798ab Iustin Pop
                                   force=opts.force,
1339 57de31c0 Agata Murawska
                                   wait_for_sync=opts.wait_for_sync,
1340 3016bc1f Michael Hanselmann
                                   offline=offline,
1341 9c784fb3 Dimitris Aragiorgis
                                   conflicts_check=opts.conflicts_check,
1342 1559e1e7 René Nussbaumer
                                   ignore_ipolicy=opts.ignore_ipolicy)
1343 31a853d2 Iustin Pop
1344 6340bb0a Iustin Pop
  # even if here we process the result, we allow submit only
1345 6340bb0a Iustin Pop
  result = SubmitOrSend(op, opts)
1346 a8083063 Iustin Pop
1347 a8083063 Iustin Pop
  if result:
1348 3a24c527 Iustin Pop
    ToStdout("Modified instance %s", args[0])
1349 a8083063 Iustin Pop
    for param, data in result:
1350 3a24c527 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
1351 e29e9550 Iustin Pop
    ToStdout("Please don't forget that most parameters take effect"
1352 d976957d Iustin Pop
             " only at the next (re)start of the instance initiated by"
1353 d976957d Iustin Pop
             " ganeti; restarting from within the instance will"
1354 d976957d Iustin Pop
             " not be enough.")
1355 a8083063 Iustin Pop
  return 0
1356 a8083063 Iustin Pop
1357 a8083063 Iustin Pop
1358 bd2a5569 Michael Hanselmann
def ChangeGroup(opts, args):
1359 bd2a5569 Michael Hanselmann
  """Moves an instance to another group.
1360 bd2a5569 Michael Hanselmann

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