Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_instance.py @ 9e448d7f

History | View | Annotate | Download (56.7 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
33 a8083063 Iustin Pop
from ganeti.cli import *
34 a8083063 Iustin Pop
from ganeti import opcodes
35 a8083063 Iustin Pop
from ganeti import constants
36 e2736e40 Guido Trotter
from ganeti import compat
37 a8083063 Iustin Pop
from ganeti import utils
38 312ac745 Iustin Pop
from ganeti import errors
39 a744b676 Manuel Franceschini
from ganeti import netutils
40 25ce3ec4 Michael Hanselmann
from ganeti import ssh
41 25ce3ec4 Michael Hanselmann
from ganeti import objects
42 735e1318 Michael Hanselmann
from ganeti import ht
43 312ac745 Iustin Pop
44 312ac745 Iustin Pop
45 c20efaa8 Michael Hanselmann
_EXPAND_CLUSTER = "cluster"
46 c20efaa8 Michael Hanselmann
_EXPAND_NODES_BOTH = "nodes"
47 c20efaa8 Michael Hanselmann
_EXPAND_NODES_PRI = "nodes-pri"
48 c20efaa8 Michael Hanselmann
_EXPAND_NODES_SEC = "nodes-sec"
49 c20efaa8 Michael Hanselmann
_EXPAND_NODES_BOTH_BY_TAGS = "nodes-by-tags"
50 c20efaa8 Michael Hanselmann
_EXPAND_NODES_PRI_BY_TAGS = "nodes-pri-by-tags"
51 c20efaa8 Michael Hanselmann
_EXPAND_NODES_SEC_BY_TAGS = "nodes-sec-by-tags"
52 c20efaa8 Michael Hanselmann
_EXPAND_INSTANCES = "instances"
53 c20efaa8 Michael Hanselmann
_EXPAND_INSTANCES_BY_TAGS = "instances-by-tags"
54 c20efaa8 Michael Hanselmann
55 b8028dcf Michael Hanselmann
_EXPAND_NODES_TAGS_MODES = compat.UniqueFrozenset([
56 c20efaa8 Michael Hanselmann
  _EXPAND_NODES_BOTH_BY_TAGS,
57 c20efaa8 Michael Hanselmann
  _EXPAND_NODES_PRI_BY_TAGS,
58 c20efaa8 Michael Hanselmann
  _EXPAND_NODES_SEC_BY_TAGS,
59 c20efaa8 Michael Hanselmann
  ])
60 312ac745 Iustin Pop
61 7232c04c Iustin Pop
#: default list of options for L{ListInstances}
62 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
63 e69d05fd Iustin Pop
  "name", "hypervisor", "os", "pnode", "status", "oper_ram",
64 48c4dfa8 Iustin Pop
  ]
65 48c4dfa8 Iustin Pop
66 a71f835e Michael Hanselmann
_MISSING = object()
67 b8028dcf Michael Hanselmann
_ENV_OVERRIDE = compat.UniqueFrozenset(["list"])
68 ef9fa5b9 René Nussbaumer
69 b0a8e8c2 René Nussbaumer
_INST_DATA_VAL = ht.TListOf(ht.TDict)
70 b0a8e8c2 René Nussbaumer
71 ef9fa5b9 René Nussbaumer
72 479636a3 Iustin Pop
def _ExpandMultiNames(mode, names, client=None):
73 312ac745 Iustin Pop
  """Expand the given names using the passed mode.
74 312ac745 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

442 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
443 7232c04c Iustin Pop
  @type args: list
444 7232c04c Iustin Pop
  @param args: should contain two elements, the old and the
445 7232c04c Iustin Pop
      new instance names
446 7232c04c Iustin Pop
  @rtype: int
447 7232c04c Iustin Pop
  @return: the desired exit code
448 decd5f45 Iustin Pop

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

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

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

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

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

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

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

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

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

577 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
578 7232c04c Iustin Pop
  @type args: list
579 30a83755 Guido Trotter
  @param args: should contain three elements, the target instance name,
580 30a83755 Guido Trotter
      the target disk id, and the target growth
581 7232c04c Iustin Pop
  @rtype: int
582 7232c04c Iustin Pop
  @return: the desired exit code
583 c6e911bc Iustin Pop

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

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

611 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
612 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
613 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
614 a8083063 Iustin Pop

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

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

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

639 579d4337 Alexander Schreiber
  """
640 90ab1a95 Iustin Pop
  return opcodes.OpInstanceReboot(instance_name=name,
641 579d4337 Alexander Schreiber
                                  reboot_type=opts.reboot_type,
642 17c3f802 Guido Trotter
                                  ignore_secondaries=opts.ignore_secondaries,
643 aa922d64 Michele Tartara
                                  shutdown_timeout=opts.shutdown_timeout)
644 a8083063 Iustin Pop
645 7c0d6283 Michael Hanselmann
646 1c5945b6 Iustin Pop
def _ShutdownInstance(name, opts):
647 a8083063 Iustin Pop
  """Shutdown an instance.
648 a8083063 Iustin Pop

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

652 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
653 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
654 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
655 a8083063 Iustin Pop

656 a8083063 Iustin Pop
  """
657 ee3e37a7 Iustin Pop
  return opcodes.OpInstanceShutdown(instance_name=name,
658 0d57ce24 Guido Trotter
                                    force=opts.force,
659 b44bd844 Michael Hanselmann
                                    timeout=opts.timeout,
660 885a0fc4 Iustin Pop
                                    ignore_offline_nodes=opts.ignore_offline,
661 885a0fc4 Iustin Pop
                                    no_remember=opts.no_remember)
662 a8083063 Iustin Pop
663 a8083063 Iustin Pop
664 a8083063 Iustin Pop
def ReplaceDisks(opts, args):
665 a8083063 Iustin Pop
  """Replace the disks of an instance
666 a8083063 Iustin Pop

667 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
668 7232c04c Iustin Pop
  @type args: list
669 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
670 7232c04c Iustin Pop
  @rtype: int
671 7232c04c Iustin Pop
  @return: the desired exit code
672 a8083063 Iustin Pop

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

714 a8083063 Iustin Pop
  The failover is done by shutting it down on its present node and
715 a8083063 Iustin Pop
  starting it on the secondary.
716 a8083063 Iustin Pop

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

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

756 53c776b5 Iustin Pop
  The migrate is done without shutdown.
757 53c776b5 Iustin Pop

758 2f907a8c Iustin Pop
  @param opts: the command line options selected by the user
759 2f907a8c Iustin Pop
  @type args: list
760 2f907a8c Iustin Pop
  @param args: should contain only one element, the instance name
761 2f907a8c Iustin Pop
  @rtype: int
762 2f907a8c Iustin Pop
  @return: the desired exit code
763 53c776b5 Iustin Pop

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

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

819 fbf5a861 Iustin Pop
  """
820 fbf5a861 Iustin Pop
  cl = GetClient()
821 fbf5a861 Iustin Pop
  instance_name = args[0]
822 fbf5a861 Iustin Pop
  force = opts.force
823 fbf5a861 Iustin Pop
824 fbf5a861 Iustin Pop
  if not force:
825 fbf5a861 Iustin Pop
    usertext = ("Instance %s will be moved."
826 fbf5a861 Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
827 fbf5a861 Iustin Pop
                (instance_name,))
828 fbf5a861 Iustin Pop
    if not AskUser(usertext):
829 fbf5a861 Iustin Pop
      return 1
830 fbf5a861 Iustin Pop
831 0091b480 Iustin Pop
  op = opcodes.OpInstanceMove(instance_name=instance_name,
832 17c3f802 Guido Trotter
                              target_node=opts.node,
833 94ab995a Thomas Thrainer
                              compress=opts.compress,
834 bb851c63 Iustin Pop
                              shutdown_timeout=opts.shutdown_timeout,
835 92cf62e3 René Nussbaumer
                              ignore_consistency=opts.ignore_consistency,
836 92cf62e3 René Nussbaumer
                              ignore_ipolicy=opts.ignore_ipolicy)
837 fbf5a861 Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
838 fbf5a861 Iustin Pop
  return 0
839 fbf5a861 Iustin Pop
840 fbf5a861 Iustin Pop
841 a8083063 Iustin Pop
def ConnectToInstanceConsole(opts, args):
842 a8083063 Iustin Pop
  """Connect to the console of an instance.
843 a8083063 Iustin Pop

844 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
845 7232c04c Iustin Pop
  @type args: list
846 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
847 7232c04c Iustin Pop
  @rtype: int
848 7232c04c Iustin Pop
  @return: the desired exit code
849 a8083063 Iustin Pop

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

881 25ce3ec4 Michael Hanselmann
  @type console: L{objects.InstanceConsole}
882 25ce3ec4 Michael Hanselmann
  @param console: Console object
883 25ce3ec4 Michael Hanselmann
  @type show_command: bool
884 25ce3ec4 Michael Hanselmann
  @param show_command: Whether to just display commands
885 25ce3ec4 Michael Hanselmann
  @type cluster_name: string
886 25ce3ec4 Michael Hanselmann
  @param cluster_name: Cluster name as retrieved from master daemon
887 25ce3ec4 Michael Hanselmann

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

933 19708787 Iustin Pop
  """
934 cd3b4ff4 Helga Velroyen
  if dev_type == constants.DT_DRBD8:
935 1c3231aa Thomas Thrainer
    drbd_info = dev["drbd_info"]
936 19708787 Iustin Pop
    data = [
937 1c3231aa Thomas Thrainer
      ("nodeA", "%s, minor=%s" %
938 1c3231aa Thomas Thrainer
                (drbd_info["primary_node"],
939 1c3231aa Thomas Thrainer
                 compat.TryToRoman(drbd_info["primary_minor"],
940 1c3231aa Thomas Thrainer
                                   convert=roman))),
941 1c3231aa Thomas Thrainer
      ("nodeB", "%s, minor=%s" %
942 1c3231aa Thomas Thrainer
                (drbd_info["secondary_node"],
943 1c3231aa Thomas Thrainer
                 compat.TryToRoman(drbd_info["secondary_minor"],
944 1c3231aa Thomas Thrainer
                                   convert=roman))),
945 1c3231aa Thomas Thrainer
      ("port", str(compat.TryToRoman(drbd_info["port"], convert=roman))),
946 1c3231aa Thomas Thrainer
      ("auth key", str(drbd_info["secret"])),
947 19708787 Iustin Pop
      ]
948 cd3b4ff4 Helga Velroyen
  elif dev_type == constants.DT_PLAIN:
949 1c3231aa Thomas Thrainer
    vg_name, lv_name = dev["logical_id"]
950 19708787 Iustin Pop
    data = ["%s/%s" % (vg_name, lv_name)]
951 19708787 Iustin Pop
  else:
952 1c3231aa Thomas Thrainer
    data = [str(dev["logical_id"])]
953 19708787 Iustin Pop
954 19708787 Iustin Pop
  return data
955 19708787 Iustin Pop
956 19708787 Iustin Pop
957 f965260c Michael Hanselmann
def _FormatBlockDevInfo(idx, top_level, dev, roman):
958 a8083063 Iustin Pop
  """Show block device information.
959 a8083063 Iustin Pop

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

963 19708787 Iustin Pop
  @type idx: int
964 19708787 Iustin Pop
  @param idx: the index of the current disk
965 19708787 Iustin Pop
  @type top_level: boolean
966 19708787 Iustin Pop
  @param top_level: if this a top-level disk?
967 7232c04c Iustin Pop
  @type dev: dict
968 7232c04c Iustin Pop
  @param dev: dictionary with disk information
969 e2736e40 Guido Trotter
  @type roman: boolean
970 e2736e40 Guido Trotter
  @param roman: whether to try to use roman integers
971 19708787 Iustin Pop
  @return: a list of either strings, tuples or lists
972 19708787 Iustin Pop
      (which should be formatted at a higher indent level)
973 7232c04c Iustin Pop

974 a8083063 Iustin Pop
  """
975 19708787 Iustin Pop
  def helper(dtype, status):
976 7232c04c Iustin Pop
    """Format one line for physical device status.
977 7232c04c Iustin Pop

978 7232c04c Iustin Pop
    @type dtype: str
979 cd3b4ff4 Helga Velroyen
    @param dtype: a constant from the L{constants.DTS_BLOCK} set
980 7232c04c Iustin Pop
    @type status: tuple
981 7232c04c Iustin Pop
    @param status: a tuple as returned from L{backend.FindBlockDevice}
982 19708787 Iustin Pop
    @return: the string representing the status
983 7232c04c Iustin Pop

984 7232c04c Iustin Pop
    """
985 a8083063 Iustin Pop
    if not status:
986 19708787 Iustin Pop
      return "not active"
987 19708787 Iustin Pop
    txt = ""
988 f208978a Michael Hanselmann
    (path, major, minor, syncp, estt, degr, ldisk_status) = status
989 19708787 Iustin Pop
    if major is None:
990 19708787 Iustin Pop
      major_string = "N/A"
991 a8083063 Iustin Pop
    else:
992 e2736e40 Guido Trotter
      major_string = str(compat.TryToRoman(major, convert=roman))
993 fd38ef95 Manuel Franceschini
994 19708787 Iustin Pop
    if minor is None:
995 19708787 Iustin Pop
      minor_string = "N/A"
996 19708787 Iustin Pop
    else:
997 e2736e40 Guido Trotter
      minor_string = str(compat.TryToRoman(minor, convert=roman))
998 19708787 Iustin Pop
999 19708787 Iustin Pop
    txt += ("%s (%s:%s)" % (path, major_string, minor_string))
1000 cd3b4ff4 Helga Velroyen
    if dtype in (constants.DT_DRBD8, ):
1001 19708787 Iustin Pop
      if syncp is not None:
1002 19708787 Iustin Pop
        sync_text = "*RECOVERING* %5.2f%%," % syncp
1003 19708787 Iustin Pop
        if estt:
1004 e2736e40 Guido Trotter
          sync_text += " ETA %ss" % compat.TryToRoman(estt, convert=roman)
1005 9db6dbce Iustin Pop
        else:
1006 19708787 Iustin Pop
          sync_text += " ETA unknown"
1007 19708787 Iustin Pop
      else:
1008 19708787 Iustin Pop
        sync_text = "in sync"
1009 19708787 Iustin Pop
      if degr:
1010 19708787 Iustin Pop
        degr_text = "*DEGRADED*"
1011 19708787 Iustin Pop
      else:
1012 19708787 Iustin Pop
        degr_text = "ok"
1013 f208978a Michael Hanselmann
      if ldisk_status == constants.LDS_FAULTY:
1014 19708787 Iustin Pop
        ldisk_text = " *MISSING DISK*"
1015 f208978a Michael Hanselmann
      elif ldisk_status == constants.LDS_UNKNOWN:
1016 f208978a Michael Hanselmann
        ldisk_text = " *UNCERTAIN STATE*"
1017 19708787 Iustin Pop
      else:
1018 19708787 Iustin Pop
        ldisk_text = ""
1019 19708787 Iustin Pop
      txt += (" %s, status %s%s" % (sync_text, degr_text, ldisk_text))
1020 cd3b4ff4 Helga Velroyen
    elif dtype == constants.DT_PLAIN:
1021 f208978a Michael Hanselmann
      if ldisk_status == constants.LDS_FAULTY:
1022 19708787 Iustin Pop
        ldisk_text = " *FAILED* (failed drive?)"
1023 19708787 Iustin Pop
      else:
1024 19708787 Iustin Pop
        ldisk_text = ""
1025 19708787 Iustin Pop
      txt += ldisk_text
1026 19708787 Iustin Pop
    return txt
1027 19708787 Iustin Pop
1028 19708787 Iustin Pop
  # the header
1029 19708787 Iustin Pop
  if top_level:
1030 19708787 Iustin Pop
    if dev["iv_name"] is not None:
1031 19708787 Iustin Pop
      txt = dev["iv_name"]
1032 19708787 Iustin Pop
    else:
1033 e2736e40 Guido Trotter
      txt = "disk %s" % compat.TryToRoman(idx, convert=roman)
1034 a8083063 Iustin Pop
  else:
1035 e2736e40 Guido Trotter
    txt = "child %s" % compat.TryToRoman(idx, convert=roman)
1036 c98162a7 Iustin Pop
  if isinstance(dev["size"], int):
1037 c98162a7 Iustin Pop
    nice_size = utils.FormatUnit(dev["size"], "h")
1038 c98162a7 Iustin Pop
  else:
1039 2cbcf95d Bernardo Dal Seno
    nice_size = str(dev["size"])
1040 2cbcf95d Bernardo Dal Seno
  data = [(txt, "%s, size %s" % (dev["dev_type"], nice_size))]
1041 19708787 Iustin Pop
  if top_level:
1042 75a6c8be Bernardo Dal Seno
    if dev["spindles"] is not None:
1043 75a6c8be Bernardo Dal Seno
      data.append(("spindles", dev["spindles"]))
1044 19708787 Iustin Pop
    data.append(("access mode", dev["mode"]))
1045 a8083063 Iustin Pop
  if dev["logical_id"] is not None:
1046 19708787 Iustin Pop
    try:
1047 1c3231aa Thomas Thrainer
      l_id = _FormatDiskDetails(dev["dev_type"], dev, roman)
1048 19708787 Iustin Pop
    except ValueError:
1049 19708787 Iustin Pop
      l_id = [str(dev["logical_id"])]
1050 19708787 Iustin Pop
    if len(l_id) == 1:
1051 19708787 Iustin Pop
      data.append(("logical_id", l_id[0]))
1052 19708787 Iustin Pop
    else:
1053 19708787 Iustin Pop
      data.extend(l_id)
1054 f965260c Michael Hanselmann
1055 f965260c Michael Hanselmann
  if dev["pstatus"]:
1056 19708787 Iustin Pop
    data.append(("on primary", helper(dev["dev_type"], dev["pstatus"])))
1057 f965260c Michael Hanselmann
1058 f965260c Michael Hanselmann
  if dev["sstatus"]:
1059 19708787 Iustin Pop
    data.append(("on secondary", helper(dev["dev_type"], dev["sstatus"])))
1060 a8083063 Iustin Pop
1061 fcbd025c Christos Stavrakakis
  data.append(("name", dev["name"]))
1062 fcbd025c Christos Stavrakakis
  data.append(("UUID", dev["uuid"]))
1063 fcbd025c Christos Stavrakakis
1064 a8083063 Iustin Pop
  if dev["children"]:
1065 2cbcf95d Bernardo Dal Seno
    data.append(("child devices", [
1066 2cbcf95d Bernardo Dal Seno
      _FormatBlockDevInfo(c_idx, False, child, roman)
1067 2cbcf95d Bernardo Dal Seno
      for c_idx, child in enumerate(dev["children"])
1068 2cbcf95d Bernardo Dal Seno
      ]))
1069 2cbcf95d Bernardo Dal Seno
  return data
1070 19708787 Iustin Pop
1071 19708787 Iustin Pop
1072 2cbcf95d Bernardo Dal Seno
def _FormatInstanceNicInfo(idx, nic):
1073 2cbcf95d Bernardo Dal Seno
  """Helper function for L{_FormatInstanceInfo()}"""
1074 d676dbea Sebastian Gebhard
  (name, uuid, ip, mac, mode, link, vlan, _, netinfo) = nic
1075 2cbcf95d Bernardo Dal Seno
  network_name = None
1076 2cbcf95d Bernardo Dal Seno
  if netinfo:
1077 2cbcf95d Bernardo Dal Seno
    network_name = netinfo["name"]
1078 2cbcf95d Bernardo Dal Seno
  return [
1079 2cbcf95d Bernardo Dal Seno
    ("nic/%d" % idx, ""),
1080 2cbcf95d Bernardo Dal Seno
    ("MAC", str(mac)),
1081 2cbcf95d Bernardo Dal Seno
    ("IP", str(ip)),
1082 2cbcf95d Bernardo Dal Seno
    ("mode", str(mode)),
1083 2cbcf95d Bernardo Dal Seno
    ("link", str(link)),
1084 d676dbea Sebastian Gebhard
    ("vlan", str(vlan)),
1085 2cbcf95d Bernardo Dal Seno
    ("network", str(network_name)),
1086 fcbd025c Christos Stavrakakis
    ("UUID", str(uuid)),
1087 fcbd025c Christos Stavrakakis
    ("name", str(name)),
1088 2cbcf95d Bernardo Dal Seno
    ]
1089 2cbcf95d Bernardo Dal Seno
1090 2cbcf95d Bernardo Dal Seno
1091 2cbcf95d Bernardo Dal Seno
def _FormatInstanceNodesInfo(instance):
1092 2cbcf95d Bernardo Dal Seno
  """Helper function for L{_FormatInstanceInfo()}"""
1093 2cbcf95d Bernardo Dal Seno
  pgroup = ("%s (UUID %s)" %
1094 2cbcf95d Bernardo Dal Seno
            (instance["pnode_group_name"], instance["pnode_group_uuid"]))
1095 2cbcf95d Bernardo Dal Seno
  secs = utils.CommaJoin(("%s (group %s, group UUID %s)" %
1096 2cbcf95d Bernardo Dal Seno
                          (name, group_name, group_uuid))
1097 2cbcf95d Bernardo Dal Seno
                         for (name, group_name, group_uuid) in
1098 2cbcf95d Bernardo Dal Seno
                           zip(instance["snodes"],
1099 2cbcf95d Bernardo Dal Seno
                               instance["snodes_group_names"],
1100 2cbcf95d Bernardo Dal Seno
                               instance["snodes_group_uuids"]))
1101 2cbcf95d Bernardo Dal Seno
  return [
1102 2cbcf95d Bernardo Dal Seno
    [
1103 2cbcf95d Bernardo Dal Seno
      ("primary", instance["pnode"]),
1104 2cbcf95d Bernardo Dal Seno
      ("group", pgroup),
1105 2cbcf95d Bernardo Dal Seno
      ],
1106 2cbcf95d Bernardo Dal Seno
    [("secondaries", secs)],
1107 2cbcf95d Bernardo Dal Seno
    ]
1108 2cbcf95d Bernardo Dal Seno
1109 2cbcf95d Bernardo Dal Seno
1110 2cbcf95d Bernardo Dal Seno
def _GetVncConsoleInfo(instance):
1111 2cbcf95d Bernardo Dal Seno
  """Helper function for L{_FormatInstanceInfo()}"""
1112 2cbcf95d Bernardo Dal Seno
  vnc_bind_address = instance["hv_actual"].get(constants.HV_VNC_BIND_ADDRESS,
1113 2cbcf95d Bernardo Dal Seno
                                               None)
1114 2cbcf95d Bernardo Dal Seno
  if vnc_bind_address:
1115 2cbcf95d Bernardo Dal Seno
    port = instance["network_port"]
1116 2cbcf95d Bernardo Dal Seno
    display = int(port) - constants.VNC_BASE_PORT
1117 2cbcf95d Bernardo Dal Seno
    if display > 0 and vnc_bind_address == constants.IP4_ADDRESS_ANY:
1118 2cbcf95d Bernardo Dal Seno
      vnc_console_port = "%s:%s (display %s)" % (instance["pnode"],
1119 2cbcf95d Bernardo Dal Seno
                                                 port,
1120 2cbcf95d Bernardo Dal Seno
                                                 display)
1121 2cbcf95d Bernardo Dal Seno
    elif display > 0 and netutils.IP4Address.IsValid(vnc_bind_address):
1122 2cbcf95d Bernardo Dal Seno
      vnc_console_port = ("%s:%s (node %s) (display %s)" %
1123 2cbcf95d Bernardo Dal Seno
                           (vnc_bind_address, port,
1124 2cbcf95d Bernardo Dal Seno
                            instance["pnode"], display))
1125 2cbcf95d Bernardo Dal Seno
    else:
1126 2cbcf95d Bernardo Dal Seno
      # vnc bind address is a file
1127 2cbcf95d Bernardo Dal Seno
      vnc_console_port = "%s:%s" % (instance["pnode"],
1128 2cbcf95d Bernardo Dal Seno
                                    vnc_bind_address)
1129 2cbcf95d Bernardo Dal Seno
    ret = "vnc to %s" % vnc_console_port
1130 2cbcf95d Bernardo Dal Seno
  else:
1131 2cbcf95d Bernardo Dal Seno
    ret = None
1132 2cbcf95d Bernardo Dal Seno
  return ret
1133 2cbcf95d Bernardo Dal Seno
1134 2cbcf95d Bernardo Dal Seno
1135 2cbcf95d Bernardo Dal Seno
def _FormatInstanceInfo(instance, roman_integers):
1136 2cbcf95d Bernardo Dal Seno
  """Format instance information for L{cli.PrintGenericInfo()}"""
1137 2cbcf95d Bernardo Dal Seno
  istate = "configured to be %s" % instance["config_state"]
1138 2cbcf95d Bernardo Dal Seno
  if instance["run_state"]:
1139 2cbcf95d Bernardo Dal Seno
    istate += ", actual state is %s" % instance["run_state"]
1140 2cbcf95d Bernardo Dal Seno
  info = [
1141 2cbcf95d Bernardo Dal Seno
    ("Instance name", instance["name"]),
1142 2cbcf95d Bernardo Dal Seno
    ("UUID", instance["uuid"]),
1143 2cbcf95d Bernardo Dal Seno
    ("Serial number",
1144 2cbcf95d Bernardo Dal Seno
     str(compat.TryToRoman(instance["serial_no"], convert=roman_integers))),
1145 2cbcf95d Bernardo Dal Seno
    ("Creation time", utils.FormatTime(instance["ctime"])),
1146 2cbcf95d Bernardo Dal Seno
    ("Modification time", utils.FormatTime(instance["mtime"])),
1147 2cbcf95d Bernardo Dal Seno
    ("State", istate),
1148 2cbcf95d Bernardo Dal Seno
    ("Nodes", _FormatInstanceNodesInfo(instance)),
1149 2cbcf95d Bernardo Dal Seno
    ("Operating system", instance["os"]),
1150 2cbcf95d Bernardo Dal Seno
    ("Operating system parameters",
1151 2cbcf95d Bernardo Dal Seno
     FormatParamsDictInfo(instance["os_instance"], instance["os_actual"])),
1152 2cbcf95d Bernardo Dal Seno
    ]
1153 2cbcf95d Bernardo Dal Seno
1154 2cbcf95d Bernardo Dal Seno
  if "network_port" in instance:
1155 2cbcf95d Bernardo Dal Seno
    info.append(("Allocated network port",
1156 2cbcf95d Bernardo Dal Seno
                 str(compat.TryToRoman(instance["network_port"],
1157 2cbcf95d Bernardo Dal Seno
                                       convert=roman_integers))))
1158 2cbcf95d Bernardo Dal Seno
  info.append(("Hypervisor", instance["hypervisor"]))
1159 2cbcf95d Bernardo Dal Seno
  console = _GetVncConsoleInfo(instance)
1160 2cbcf95d Bernardo Dal Seno
  if console:
1161 2cbcf95d Bernardo Dal Seno
    info.append(("console connection", console))
1162 2cbcf95d Bernardo Dal Seno
  # deprecated "memory" value, kept for one version for compatibility
1163 2cbcf95d Bernardo Dal Seno
  # TODO(ganeti 2.7) remove.
1164 2cbcf95d Bernardo Dal Seno
  be_actual = copy.deepcopy(instance["be_actual"])
1165 2cbcf95d Bernardo Dal Seno
  be_actual["memory"] = be_actual[constants.BE_MAXMEM]
1166 2cbcf95d Bernardo Dal Seno
  info.extend([
1167 2cbcf95d Bernardo Dal Seno
    ("Hypervisor parameters",
1168 2cbcf95d Bernardo Dal Seno
     FormatParamsDictInfo(instance["hv_instance"], instance["hv_actual"])),
1169 2cbcf95d Bernardo Dal Seno
    ("Back-end parameters",
1170 2cbcf95d Bernardo Dal Seno
     FormatParamsDictInfo(instance["be_instance"], be_actual)),
1171 2cbcf95d Bernardo Dal Seno
    ("NICs", [
1172 2cbcf95d Bernardo Dal Seno
      _FormatInstanceNicInfo(idx, nic)
1173 2cbcf95d Bernardo Dal Seno
      for (idx, nic) in enumerate(instance["nics"])
1174 2cbcf95d Bernardo Dal Seno
      ]),
1175 2cbcf95d Bernardo Dal Seno
    ("Disk template", instance["disk_template"]),
1176 2cbcf95d Bernardo Dal Seno
    ("Disks", [
1177 2cbcf95d Bernardo Dal Seno
      _FormatBlockDevInfo(idx, True, device, roman_integers)
1178 2cbcf95d Bernardo Dal Seno
      for (idx, device) in enumerate(instance["disks"])
1179 2cbcf95d Bernardo Dal Seno
      ]),
1180 2cbcf95d Bernardo Dal Seno
    ])
1181 2cbcf95d Bernardo Dal Seno
  return info
1182 19708787 Iustin Pop
1183 98825740 Michael Hanselmann
1184 a8083063 Iustin Pop
def ShowInstanceConfig(opts, args):
1185 a8083063 Iustin Pop
  """Compute instance run-time status.
1186 a8083063 Iustin Pop

1187 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1188 7232c04c Iustin Pop
  @type args: list
1189 7232c04c Iustin Pop
  @param args: either an empty list, and then we query all
1190 7232c04c Iustin Pop
      instances, or should contain a list of instance names
1191 7232c04c Iustin Pop
  @rtype: int
1192 7232c04c Iustin Pop
  @return: the desired exit code
1193 7232c04c Iustin Pop

1194 a8083063 Iustin Pop
  """
1195 220cde0b Guido Trotter
  if not args and not opts.show_all:
1196 220cde0b Guido Trotter
    ToStderr("No instance selected."
1197 220cde0b Guido Trotter
             " Please pass in --all if you want to query all instances.\n"
1198 220cde0b Guido Trotter
             "Note that this can take a long time on a big cluster.")
1199 220cde0b Guido Trotter
    return 1
1200 220cde0b Guido Trotter
  elif args and opts.show_all:
1201 220cde0b Guido Trotter
    ToStderr("Cannot use --all if you specify instance names.")
1202 220cde0b Guido Trotter
    return 1
1203 220cde0b Guido Trotter
1204 a8083063 Iustin Pop
  retcode = 0
1205 5c097318 Iustin Pop
  op = opcodes.OpInstanceQueryData(instances=args, static=opts.static,
1206 5c097318 Iustin Pop
                                   use_locking=not opts.static)
1207 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
1208 a8083063 Iustin Pop
  if not result:
1209 3a24c527 Iustin Pop
    ToStdout("No instances.")
1210 a8083063 Iustin Pop
    return 1
1211 a8083063 Iustin Pop
1212 2cbcf95d Bernardo Dal Seno
  PrintGenericInfo([
1213 2cbcf95d Bernardo Dal Seno
    _FormatInstanceInfo(instance, opts.roman_integers)
1214 2cbcf95d Bernardo Dal Seno
    for instance in result.values()
1215 2cbcf95d Bernardo Dal Seno
    ])
1216 a8083063 Iustin Pop
  return retcode
1217 a8083063 Iustin Pop
1218 a8083063 Iustin Pop
1219 a71f835e Michael Hanselmann
def _ConvertNicDiskModifications(mods):
1220 a71f835e Michael Hanselmann
  """Converts NIC/disk modifications from CLI to opcode.
1221 a71f835e Michael Hanselmann

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

1227 a71f835e Michael Hanselmann
  @type mods: list of tuples
1228 a71f835e Michael Hanselmann
  @param mods: Modifications as given by command line parser
1229 a71f835e Michael Hanselmann
  @rtype: list of tuples
1230 a71f835e Michael Hanselmann
  @return: Modifications as understood by L{opcodes.OpInstanceSetParams}
1231 a71f835e Michael Hanselmann

1232 a71f835e Michael Hanselmann
  """
1233 a71f835e Michael Hanselmann
  result = []
1234 a71f835e Michael Hanselmann
1235 b21d488b Christos Stavrakakis
  for (identifier, params) in mods:
1236 b21d488b Christos Stavrakakis
    if identifier == constants.DDM_ADD:
1237 a71f835e Michael Hanselmann
      # Add item as last item (legacy interface)
1238 a71f835e Michael Hanselmann
      action = constants.DDM_ADD
1239 b21d488b Christos Stavrakakis
      identifier = -1
1240 b21d488b Christos Stavrakakis
    elif identifier == constants.DDM_REMOVE:
1241 a71f835e Michael Hanselmann
      # Remove last item (legacy interface)
1242 a71f835e Michael Hanselmann
      action = constants.DDM_REMOVE
1243 b21d488b Christos Stavrakakis
      identifier = -1
1244 a71f835e Michael Hanselmann
    else:
1245 a71f835e Michael Hanselmann
      # Modifications and adding/removing at arbitrary indices
1246 a71f835e Michael Hanselmann
      add = params.pop(constants.DDM_ADD, _MISSING)
1247 a71f835e Michael Hanselmann
      remove = params.pop(constants.DDM_REMOVE, _MISSING)
1248 f0d22861 Constantinos Venetsanopoulos
      modify = params.pop(constants.DDM_MODIFY, _MISSING)
1249 f0d22861 Constantinos Venetsanopoulos
1250 f0d22861 Constantinos Venetsanopoulos
      if modify is _MISSING:
1251 f0d22861 Constantinos Venetsanopoulos
        if not (add is _MISSING or remove is _MISSING):
1252 f0d22861 Constantinos Venetsanopoulos
          raise errors.OpPrereqError("Cannot add and remove at the same time",
1253 f0d22861 Constantinos Venetsanopoulos
                                     errors.ECODE_INVAL)
1254 f0d22861 Constantinos Venetsanopoulos
        elif add is not _MISSING:
1255 f0d22861 Constantinos Venetsanopoulos
          action = constants.DDM_ADD
1256 f0d22861 Constantinos Venetsanopoulos
        elif remove is not _MISSING:
1257 f0d22861 Constantinos Venetsanopoulos
          action = constants.DDM_REMOVE
1258 f0d22861 Constantinos Venetsanopoulos
        else:
1259 f0d22861 Constantinos Venetsanopoulos
          action = constants.DDM_MODIFY
1260 a71f835e Michael Hanselmann
1261 7a70541e Michael Hanselmann
      elif add is _MISSING and remove is _MISSING:
1262 7a70541e Michael Hanselmann
        action = constants.DDM_MODIFY
1263 a71f835e Michael Hanselmann
      else:
1264 7a70541e Michael Hanselmann
        raise errors.OpPrereqError("Cannot modify and add/remove at the"
1265 7a70541e Michael Hanselmann
                                   " same time", errors.ECODE_INVAL)
1266 a71f835e Michael Hanselmann
1267 a71f835e Michael Hanselmann
      assert not (constants.DDMS_VALUES_WITH_MODIFY & set(params.keys()))
1268 a71f835e Michael Hanselmann
1269 a71f835e Michael Hanselmann
    if action == constants.DDM_REMOVE and params:
1270 a71f835e Michael Hanselmann
      raise errors.OpPrereqError("Not accepting parameters on removal",
1271 a71f835e Michael Hanselmann
                                 errors.ECODE_INVAL)
1272 a71f835e Michael Hanselmann
1273 b21d488b Christos Stavrakakis
    result.append((action, identifier, params))
1274 a71f835e Michael Hanselmann
1275 a71f835e Michael Hanselmann
  return result
1276 a71f835e Michael Hanselmann
1277 a71f835e Michael Hanselmann
1278 a71f835e Michael Hanselmann
def _ParseDiskSizes(mods):
1279 a71f835e Michael Hanselmann
  """Parses disk sizes in parameters.
1280 a71f835e Michael Hanselmann

1281 a71f835e Michael Hanselmann
  """
1282 a71f835e Michael Hanselmann
  for (action, _, params) in mods:
1283 a71f835e Michael Hanselmann
    if params and constants.IDISK_SIZE in params:
1284 a71f835e Michael Hanselmann
      params[constants.IDISK_SIZE] = \
1285 a71f835e Michael Hanselmann
        utils.ParseUnit(params[constants.IDISK_SIZE])
1286 a71f835e Michael Hanselmann
    elif action == constants.DDM_ADD:
1287 a71f835e Michael Hanselmann
      raise errors.OpPrereqError("Missing required parameter 'size'",
1288 a71f835e Michael Hanselmann
                                 errors.ECODE_INVAL)
1289 a71f835e Michael Hanselmann
1290 a71f835e Michael Hanselmann
  return mods
1291 a71f835e Michael Hanselmann
1292 a71f835e Michael Hanselmann
1293 7767bbf5 Manuel Franceschini
def SetInstanceParams(opts, args):
1294 a8083063 Iustin Pop
  """Modifies an instance.
1295 a8083063 Iustin Pop

1296 a8083063 Iustin Pop
  All parameters take effect only at the next restart of the instance.
1297 a8083063 Iustin Pop

1298 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1299 7232c04c Iustin Pop
  @type args: list
1300 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
1301 7232c04c Iustin Pop
  @rtype: int
1302 7232c04c Iustin Pop
  @return: the desired exit code
1303 a8083063 Iustin Pop

1304 a8083063 Iustin Pop
  """
1305 e29e9550 Iustin Pop
  if not (opts.nics or opts.disks or opts.disk_template or
1306 57de31c0 Agata Murawska
          opts.hvparams or opts.beparams or opts.os or opts.osparams or
1307 3438e1f8 Klaus Aehlig
          opts.offline_inst or opts.online_inst or opts.runtime_mem or
1308 3438e1f8 Klaus Aehlig
          opts.new_primary_node):
1309 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
1310 a8083063 Iustin Pop
    return 1
1311 a8083063 Iustin Pop
1312 467ae11e Guido Trotter
  for param in opts.beparams:
1313 e9d622bc Guido Trotter
    if isinstance(opts.beparams[param], basestring):
1314 e9d622bc Guido Trotter
      if opts.beparams[param].lower() == "default":
1315 e9d622bc Guido Trotter
        opts.beparams[param] = constants.VALUE_DEFAULT
1316 a5728081 Guido Trotter
1317 b2e233a5 Guido Trotter
  utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_COMPAT,
1318 a5728081 Guido Trotter
                      allowed_values=[constants.VALUE_DEFAULT])
1319 467ae11e Guido Trotter
1320 48f212d7 Iustin Pop
  for param in opts.hvparams:
1321 48f212d7 Iustin Pop
    if isinstance(opts.hvparams[param], basestring):
1322 48f212d7 Iustin Pop
      if opts.hvparams[param].lower() == "default":
1323 48f212d7 Iustin Pop
        opts.hvparams[param] = constants.VALUE_DEFAULT
1324 a5728081 Guido Trotter
1325 48f212d7 Iustin Pop
  utils.ForceDictType(opts.hvparams, constants.HVS_PARAMETER_TYPES,
1326 a5728081 Guido Trotter
                      allowed_values=[constants.VALUE_DEFAULT])
1327 61be6ba4 Iustin Pop
1328 a71f835e Michael Hanselmann
  nics = _ConvertNicDiskModifications(opts.nics)
1329 df58ca1c Dimitris Aragiorgis
  for action, _, __ in nics:
1330 e15a00dc Dimitris Aragiorgis
    if action == constants.DDM_MODIFY and opts.hotplug and not opts.force:
1331 df58ca1c Dimitris Aragiorgis
      usertext = ("You are about to hot-modify a NIC. This will be done"
1332 df58ca1c Dimitris Aragiorgis
                  " by removing the exisiting and then adding a new one."
1333 df58ca1c Dimitris Aragiorgis
                  " Network connection might be lost. Continue?")
1334 df58ca1c Dimitris Aragiorgis
      if not AskUser(usertext):
1335 df58ca1c Dimitris Aragiorgis
        return 1
1336 df58ca1c Dimitris Aragiorgis
1337 a71f835e Michael Hanselmann
  disks = _ParseDiskSizes(_ConvertNicDiskModifications(opts.disks))
1338 24991749 Iustin Pop
1339 e29e9550 Iustin Pop
  if (opts.disk_template and
1340 3429a076 Apollon Oikonomopoulos
      opts.disk_template in constants.DTS_INT_MIRROR and
1341 e29e9550 Iustin Pop
      not opts.node):
1342 e29e9550 Iustin Pop
    ToStderr("Changing the disk template to a mirrored one requires"
1343 e29e9550 Iustin Pop
             " specifying a secondary node")
1344 e29e9550 Iustin Pop
    return 1
1345 e29e9550 Iustin Pop
1346 3016bc1f Michael Hanselmann
  if opts.offline_inst:
1347 3016bc1f Michael Hanselmann
    offline = True
1348 3016bc1f Michael Hanselmann
  elif opts.online_inst:
1349 3016bc1f Michael Hanselmann
    offline = False
1350 3016bc1f Michael Hanselmann
  else:
1351 3016bc1f Michael Hanselmann
    offline = None
1352 3016bc1f Michael Hanselmann
1353 9a3cc7ae Iustin Pop
  op = opcodes.OpInstanceSetParams(instance_name=args[0],
1354 a71f835e Michael Hanselmann
                                   nics=nics,
1355 a71f835e Michael Hanselmann
                                   disks=disks,
1356 df58ca1c Dimitris Aragiorgis
                                   hotplug=opts.hotplug,
1357 e29e9550 Iustin Pop
                                   disk_template=opts.disk_template,
1358 e29e9550 Iustin Pop
                                   remote_node=opts.node,
1359 3438e1f8 Klaus Aehlig
                                   pnode=opts.new_primary_node,
1360 48f212d7 Iustin Pop
                                   hvparams=opts.hvparams,
1361 338e51e8 Iustin Pop
                                   beparams=opts.beparams,
1362 2c0af7da Guido Trotter
                                   runtime_mem=opts.runtime_mem,
1363 96b39bcc Iustin Pop
                                   os_name=opts.os,
1364 1052d622 Iustin Pop
                                   osparams=opts.osparams,
1365 96b39bcc Iustin Pop
                                   force_variant=opts.force_variant,
1366 456798ab Iustin Pop
                                   force=opts.force,
1367 57de31c0 Agata Murawska
                                   wait_for_sync=opts.wait_for_sync,
1368 3016bc1f Michael Hanselmann
                                   offline=offline,
1369 9c784fb3 Dimitris Aragiorgis
                                   conflicts_check=opts.conflicts_check,
1370 1559e1e7 René Nussbaumer
                                   ignore_ipolicy=opts.ignore_ipolicy)
1371 31a853d2 Iustin Pop
1372 6340bb0a Iustin Pop
  # even if here we process the result, we allow submit only
1373 6340bb0a Iustin Pop
  result = SubmitOrSend(op, opts)
1374 a8083063 Iustin Pop
1375 a8083063 Iustin Pop
  if result:
1376 3a24c527 Iustin Pop
    ToStdout("Modified instance %s", args[0])
1377 a8083063 Iustin Pop
    for param, data in result:
1378 3a24c527 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
1379 e29e9550 Iustin Pop
    ToStdout("Please don't forget that most parameters take effect"
1380 d976957d Iustin Pop
             " only at the next (re)start of the instance initiated by"
1381 d976957d Iustin Pop
             " ganeti; restarting from within the instance will"
1382 d976957d Iustin Pop
             " not be enough.")
1383 a8083063 Iustin Pop
  return 0
1384 a8083063 Iustin Pop
1385 a8083063 Iustin Pop
1386 bd2a5569 Michael Hanselmann
def ChangeGroup(opts, args):
1387 bd2a5569 Michael Hanselmann
  """Moves an instance to another group.
1388 bd2a5569 Michael Hanselmann

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