Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_instance.py @ a8deb185

History | View | Annotate | Download (57.5 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 b82c5ff5 Michael Hanselmann
  return GenericList(constants.QR_INSTANCE, selected_fields, args, opts.units,
227 b82c5ff5 Michael Hanselmann
                     opts.separator, not opts.no_headers,
228 87e87959 Michael Hanselmann
                     format_override=fmtoverride, verbose=opts.verbose,
229 87e87959 Michael Hanselmann
                     force_filter=opts.force_filter)
230 b82c5ff5 Michael Hanselmann
231 b82c5ff5 Michael Hanselmann
232 b82c5ff5 Michael Hanselmann
def ListInstanceFields(opts, args):
233 b82c5ff5 Michael Hanselmann
  """List instance fields.
234 b82c5ff5 Michael Hanselmann

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

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

249 d77490c5 Iustin Pop
  This is just a wrapper over GenericInstanceCreate.
250 a8083063 Iustin Pop

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

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

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

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

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

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

409 d2e0774d Dimitris Aragiorgis
  @param opts: the command line options selected by the user
410 d2e0774d Dimitris Aragiorgis
  @type args: list
411 d2e0774d Dimitris Aragiorgis
  @param args: should contain only one element, the name of the
412 d2e0774d Dimitris Aragiorgis
      instance to be reinstalled
413 d2e0774d Dimitris Aragiorgis
  @rtype: int
414 d2e0774d Dimitris Aragiorgis
  @return: the desired exit code
415 d2e0774d Dimitris Aragiorgis

416 d2e0774d Dimitris Aragiorgis
  """
417 d2e0774d Dimitris Aragiorgis
  instance_name  = args[0]
418 d2e0774d Dimitris Aragiorgis
  inames = _ExpandMultiNames(_EXPAND_INSTANCES, [instance_name])
419 d2e0774d Dimitris Aragiorgis
  if not inames:
420 d2e0774d Dimitris Aragiorgis
    raise errors.OpPrereqError("Selection filter does not match any instances",
421 d2e0774d Dimitris Aragiorgis
                               errors.ECODE_INVAL)
422 d2e0774d Dimitris Aragiorgis
  multi_on = len(inames) > 1
423 d2e0774d Dimitris Aragiorgis
  jex = JobExecutor(verbose=multi_on, opts=opts)
424 d2e0774d Dimitris Aragiorgis
  for instance_name in inames:
425 d2e0774d Dimitris Aragiorgis
    op = opcodes.OpInstanceSnapshot(instance_name=instance_name,
426 d2e0774d Dimitris Aragiorgis
                                    disks=opts.disks)
427 d2e0774d Dimitris Aragiorgis
    jex.QueueJob(instance_name, op)
428 d2e0774d Dimitris Aragiorgis
429 d2e0774d Dimitris Aragiorgis
  results = jex.WaitOrShow(not opts.submit_only)
430 d2e0774d Dimitris Aragiorgis
431 d2e0774d Dimitris Aragiorgis
  if compat.all(map(compat.fst, results)):
432 d2e0774d Dimitris Aragiorgis
    return constants.EXIT_SUCCESS
433 d2e0774d Dimitris Aragiorgis
  else:
434 d2e0774d Dimitris Aragiorgis
    return constants.EXIT_FAILURE
435 d2e0774d Dimitris Aragiorgis
436 a8083063 Iustin Pop
def RemoveInstance(opts, args):
437 a8083063 Iustin Pop
  """Remove an instance.
438 a8083063 Iustin Pop

439 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
440 7232c04c Iustin Pop
  @type args: list
441 7232c04c Iustin Pop
  @param args: should contain only one element, the name of
442 7232c04c Iustin Pop
      the instance to be removed
443 7232c04c Iustin Pop
  @rtype: int
444 7232c04c Iustin Pop
  @return: the desired exit code
445 a8083063 Iustin Pop

446 a8083063 Iustin Pop
  """
447 a8083063 Iustin Pop
  instance_name = args[0]
448 a8083063 Iustin Pop
  force = opts.force
449 a76f0c4a Iustin Pop
  cl = GetClient()
450 a8083063 Iustin Pop
451 a8083063 Iustin Pop
  if not force:
452 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
453 a76f0c4a Iustin Pop
454 a8083063 Iustin Pop
    usertext = ("This will remove the volumes of the instance %s"
455 a8083063 Iustin Pop
                " (including mirrors), thus removing all the data"
456 a8083063 Iustin Pop
                " of the instance. Continue?") % instance_name
457 47988778 Iustin Pop
    if not AskUser(usertext):
458 a8083063 Iustin Pop
      return 1
459 a8083063 Iustin Pop
460 3cd2d4b1 Iustin Pop
  op = opcodes.OpInstanceRemove(instance_name=instance_name,
461 17c3f802 Guido Trotter
                                ignore_failures=opts.ignore_failures,
462 a8deb185 Dimitris Aragiorgis
                                shutdown_timeout=opts.shutdown_timeout,
463 a8deb185 Dimitris Aragiorgis
                                keep_disks=opts.keep_disks)
464 a76f0c4a Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
465 a8083063 Iustin Pop
  return 0
466 a8083063 Iustin Pop
467 a8083063 Iustin Pop
468 decd5f45 Iustin Pop
def RenameInstance(opts, args):
469 4ab0b9e3 Guido Trotter
  """Rename an instance.
470 decd5f45 Iustin Pop

471 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
472 7232c04c Iustin Pop
  @type args: list
473 7232c04c Iustin Pop
  @param args: should contain two elements, the old and the
474 7232c04c Iustin Pop
      new instance names
475 7232c04c Iustin Pop
  @rtype: int
476 7232c04c Iustin Pop
  @return: the desired exit code
477 decd5f45 Iustin Pop

478 decd5f45 Iustin Pop
  """
479 90ed09b0 René Nussbaumer
  if not opts.name_check:
480 1b6dddc8 René Nussbaumer
    if not AskUser("As you disabled the check of the DNS entry, please verify"
481 1b6dddc8 René Nussbaumer
                   " that '%s' is a FQDN. Continue?" % args[1]):
482 1b6dddc8 René Nussbaumer
      return 1
483 1b6dddc8 René Nussbaumer
484 5659e2e2 Iustin Pop
  op = opcodes.OpInstanceRename(instance_name=args[0],
485 decd5f45 Iustin Pop
                                new_name=args[1],
486 3fe11ba3 Manuel Franceschini
                                ip_check=opts.ip_check,
487 3fe11ba3 Manuel Franceschini
                                name_check=opts.name_check)
488 6a016df9 Michael Hanselmann
  result = SubmitOrSend(op, opts)
489 6a016df9 Michael Hanselmann
490 48418fea Iustin Pop
  if result:
491 48418fea Iustin Pop
    ToStdout("Instance '%s' renamed to '%s'", args[0], result)
492 6a016df9 Michael Hanselmann
493 decd5f45 Iustin Pop
  return 0
494 decd5f45 Iustin Pop
495 decd5f45 Iustin Pop
496 a8083063 Iustin Pop
def ActivateDisks(opts, args):
497 a8083063 Iustin Pop
  """Activate an instance's disks.
498 a8083063 Iustin Pop

499 a8083063 Iustin Pop
  This serves two purposes:
500 7232c04c Iustin Pop
    - it allows (as long as the instance is not running)
501 7232c04c Iustin Pop
      mounting the disks and modifying them from the node
502 a8083063 Iustin Pop
    - it repairs inactive secondary drbds
503 a8083063 Iustin Pop

504 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
505 7232c04c Iustin Pop
  @type args: list
506 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
507 7232c04c Iustin Pop
  @rtype: int
508 7232c04c Iustin Pop
  @return: the desired exit code
509 7232c04c Iustin Pop

510 a8083063 Iustin Pop
  """
511 a8083063 Iustin Pop
  instance_name = args[0]
512 83f5d475 Iustin Pop
  op = opcodes.OpInstanceActivateDisks(instance_name=instance_name,
513 f30d8165 Iustin Pop
                                       ignore_size=opts.ignore_size,
514 f30d8165 Iustin Pop
                                       wait_for_sync=opts.wait_for_sync)
515 6340bb0a Iustin Pop
  disks_info = SubmitOrSend(op, opts)
516 a8083063 Iustin Pop
  for host, iname, nname in disks_info:
517 3a24c527 Iustin Pop
    ToStdout("%s:%s:%s", host, iname, nname)
518 a8083063 Iustin Pop
  return 0
519 a8083063 Iustin Pop
520 a8083063 Iustin Pop
521 a8083063 Iustin Pop
def DeactivateDisks(opts, args):
522 bd315bfa Iustin Pop
  """Deactivate an instance's disks.
523 a8083063 Iustin Pop

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

527 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
528 7232c04c Iustin Pop
  @type args: list
529 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
530 7232c04c Iustin Pop
  @rtype: int
531 7232c04c Iustin Pop
  @return: the desired exit code
532 7232c04c Iustin Pop

533 a8083063 Iustin Pop
  """
534 a8083063 Iustin Pop
  instance_name = args[0]
535 c9c41373 Iustin Pop
  op = opcodes.OpInstanceDeactivateDisks(instance_name=instance_name,
536 c9c41373 Iustin Pop
                                         force=opts.force)
537 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
538 a8083063 Iustin Pop
  return 0
539 a8083063 Iustin Pop
540 a8083063 Iustin Pop
541 bd315bfa Iustin Pop
def RecreateDisks(opts, args):
542 bd315bfa Iustin Pop
  """Recreate an instance's disks.
543 bd315bfa Iustin Pop

544 bd315bfa Iustin Pop
  @param opts: the command line options selected by the user
545 bd315bfa Iustin Pop
  @type args: list
546 bd315bfa Iustin Pop
  @param args: should contain only one element, the instance name
547 bd315bfa Iustin Pop
  @rtype: int
548 bd315bfa Iustin Pop
  @return: the desired exit code
549 bd315bfa Iustin Pop

550 bd315bfa Iustin Pop
  """
551 bd315bfa Iustin Pop
  instance_name = args[0]
552 735e1318 Michael Hanselmann
553 735e1318 Michael Hanselmann
  disks = []
554 735e1318 Michael Hanselmann
555 bd315bfa Iustin Pop
  if opts.disks:
556 735e1318 Michael Hanselmann
    for didx, ddict in opts.disks:
557 735e1318 Michael Hanselmann
      didx = int(didx)
558 735e1318 Michael Hanselmann
559 735e1318 Michael Hanselmann
      if not ht.TDict(ddict):
560 735e1318 Michael Hanselmann
        msg = "Invalid disk/%d value: expected dict, got %s" % (didx, ddict)
561 2cfbc784 Iustin Pop
        raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
562 735e1318 Michael Hanselmann
563 735e1318 Michael Hanselmann
      if constants.IDISK_SIZE in ddict:
564 735e1318 Michael Hanselmann
        try:
565 735e1318 Michael Hanselmann
          ddict[constants.IDISK_SIZE] = \
566 735e1318 Michael Hanselmann
            utils.ParseUnit(ddict[constants.IDISK_SIZE])
567 735e1318 Michael Hanselmann
        except ValueError, err:
568 735e1318 Michael Hanselmann
          raise errors.OpPrereqError("Invalid disk size for disk %d: %s" %
569 2cfbc784 Iustin Pop
                                     (didx, err), errors.ECODE_INVAL)
570 735e1318 Michael Hanselmann
571 735e1318 Michael Hanselmann
      disks.append((didx, ddict))
572 735e1318 Michael Hanselmann
573 735e1318 Michael Hanselmann
    # TODO: Verify modifyable parameters (already done in
574 735e1318 Michael Hanselmann
    # LUInstanceRecreateDisks, but it'd be nice to have in the client)
575 bd315bfa Iustin Pop
576 c8a96ae7 Iustin Pop
  if opts.node:
577 38db4e7c Adam Ingrassia
    if opts.iallocator:
578 38db4e7c Adam Ingrassia
      msg = "At most one of either --nodes or --iallocator can be passed"
579 38db4e7c Adam Ingrassia
      raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
580 c8a96ae7 Iustin Pop
    pnode, snode = SplitNodeOption(opts.node)
581 c8a96ae7 Iustin Pop
    nodes = [pnode]
582 c8a96ae7 Iustin Pop
    if snode is not None:
583 c8a96ae7 Iustin Pop
      nodes.append(snode)
584 c8a96ae7 Iustin Pop
  else:
585 c8a96ae7 Iustin Pop
    nodes = []
586 c8a96ae7 Iustin Pop
587 6b273e78 Iustin Pop
  op = opcodes.OpInstanceRecreateDisks(instance_name=instance_name,
588 38db4e7c Adam Ingrassia
                                       disks=disks, nodes=nodes,
589 38db4e7c Adam Ingrassia
                                       iallocator=opts.iallocator)
590 bd315bfa Iustin Pop
  SubmitOrSend(op, opts)
591 735e1318 Michael Hanselmann
592 bd315bfa Iustin Pop
  return 0
593 bd315bfa Iustin Pop
594 bd315bfa Iustin Pop
595 c6e911bc Iustin Pop
def GrowDisk(opts, args):
596 7232c04c Iustin Pop
  """Grow an instance's disks.
597 c6e911bc Iustin Pop

598 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
599 7232c04c Iustin Pop
  @type args: list
600 30a83755 Guido Trotter
  @param args: should contain three elements, the target instance name,
601 30a83755 Guido Trotter
      the target disk id, and the target growth
602 7232c04c Iustin Pop
  @rtype: int
603 7232c04c Iustin Pop
  @return: the desired exit code
604 c6e911bc Iustin Pop

605 c6e911bc Iustin Pop
  """
606 c6e911bc Iustin Pop
  instance = args[0]
607 c6e911bc Iustin Pop
  disk = args[1]
608 ad24e046 Iustin Pop
  try:
609 ad24e046 Iustin Pop
    disk = int(disk)
610 691744c4 Iustin Pop
  except (TypeError, ValueError), err:
611 debac808 Iustin Pop
    raise errors.OpPrereqError("Invalid disk index: %s" % str(err),
612 debac808 Iustin Pop
                               errors.ECODE_INVAL)
613 c8bde61e Iustin Pop
  try:
614 c8bde61e Iustin Pop
    amount = utils.ParseUnit(args[2])
615 c8bde61e Iustin Pop
  except errors.UnitParseError:
616 c8bde61e Iustin Pop
    raise errors.OpPrereqError("Can't parse the given amount '%s'" % args[2],
617 c8bde61e Iustin Pop
                               errors.ECODE_INVAL)
618 60472d29 Iustin Pop
  op = opcodes.OpInstanceGrowDisk(instance_name=instance,
619 60472d29 Iustin Pop
                                  disk=disk, amount=amount,
620 ef8270dc Iustin Pop
                                  wait_for_sync=opts.wait_for_sync,
621 ef8270dc Iustin Pop
                                  absolute=opts.absolute)
622 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
623 c6e911bc Iustin Pop
  return 0
624 c6e911bc Iustin Pop
625 c6e911bc Iustin Pop
626 1c5945b6 Iustin Pop
def _StartupInstance(name, opts):
627 7232c04c Iustin Pop
  """Startup instances.
628 a8083063 Iustin Pop

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

632 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
633 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
634 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
635 a8083063 Iustin Pop

636 a8083063 Iustin Pop
  """
637 c873d91c Iustin Pop
  op = opcodes.OpInstanceStartup(instance_name=name,
638 b44bd844 Michael Hanselmann
                                 force=opts.force,
639 885a0fc4 Iustin Pop
                                 ignore_offline_nodes=opts.ignore_offline,
640 323f9095 Stephen Shirley
                                 no_remember=opts.no_remember,
641 323f9095 Stephen Shirley
                                 startup_paused=opts.startup_paused)
642 1c5945b6 Iustin Pop
  # do not add these parameters to the opcode unless they're defined
643 1c5945b6 Iustin Pop
  if opts.hvparams:
644 1c5945b6 Iustin Pop
    op.hvparams = opts.hvparams
645 1c5945b6 Iustin Pop
  if opts.beparams:
646 1c5945b6 Iustin Pop
    op.beparams = opts.beparams
647 1c5945b6 Iustin Pop
  return op
648 a8083063 Iustin Pop
649 7c0d6283 Michael Hanselmann
650 1c5945b6 Iustin Pop
def _RebootInstance(name, opts):
651 7232c04c Iustin Pop
  """Reboot instance(s).
652 7232c04c Iustin Pop

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

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

660 579d4337 Alexander Schreiber
  """
661 90ab1a95 Iustin Pop
  return opcodes.OpInstanceReboot(instance_name=name,
662 579d4337 Alexander Schreiber
                                  reboot_type=opts.reboot_type,
663 17c3f802 Guido Trotter
                                  ignore_secondaries=opts.ignore_secondaries,
664 aa922d64 Michele Tartara
                                  shutdown_timeout=opts.shutdown_timeout)
665 a8083063 Iustin Pop
666 7c0d6283 Michael Hanselmann
667 1c5945b6 Iustin Pop
def _ShutdownInstance(name, opts):
668 a8083063 Iustin Pop
  """Shutdown an instance.
669 a8083063 Iustin Pop

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

673 1c5945b6 Iustin Pop
  @param name: the name of the instance to act on
674 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
675 1c5945b6 Iustin Pop
  @return: the opcode needed for the operation
676 a8083063 Iustin Pop

677 a8083063 Iustin Pop
  """
678 ee3e37a7 Iustin Pop
  return opcodes.OpInstanceShutdown(instance_name=name,
679 0d57ce24 Guido Trotter
                                    force=opts.force,
680 b44bd844 Michael Hanselmann
                                    timeout=opts.timeout,
681 885a0fc4 Iustin Pop
                                    ignore_offline_nodes=opts.ignore_offline,
682 885a0fc4 Iustin Pop
                                    no_remember=opts.no_remember)
683 a8083063 Iustin Pop
684 a8083063 Iustin Pop
685 a8083063 Iustin Pop
def ReplaceDisks(opts, args):
686 a8083063 Iustin Pop
  """Replace the disks of an instance
687 a8083063 Iustin Pop

688 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
689 7232c04c Iustin Pop
  @type args: list
690 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
691 7232c04c Iustin Pop
  @rtype: int
692 7232c04c Iustin Pop
  @return: the desired exit code
693 a8083063 Iustin Pop

694 a8083063 Iustin Pop
  """
695 a14db5ff Iustin Pop
  new_2ndary = opts.dst_node
696 b6e82a65 Iustin Pop
  iallocator = opts.iallocator
697 a9e0c397 Iustin Pop
  if opts.disks is None:
698 54155f52 Iustin Pop
    disks = []
699 a9e0c397 Iustin Pop
  else:
700 54155f52 Iustin Pop
    try:
701 54155f52 Iustin Pop
      disks = [int(i) for i in opts.disks.split(",")]
702 691744c4 Iustin Pop
    except (TypeError, ValueError), err:
703 debac808 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err),
704 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
705 05d47e33 Michael Hanselmann
  cnt = [opts.on_primary, opts.on_secondary, opts.auto,
706 7e9366f7 Iustin Pop
         new_2ndary is not None, iallocator is not None].count(True)
707 7e9366f7 Iustin Pop
  if cnt != 1:
708 d8d838cb Michael Hanselmann
    raise errors.OpPrereqError("One and only one of the -p, -s, -a, -n and -I"
709 debac808 Iustin Pop
                               " options must be passed", errors.ECODE_INVAL)
710 7e9366f7 Iustin Pop
  elif opts.on_primary:
711 a9e0c397 Iustin Pop
    mode = constants.REPLACE_DISK_PRI
712 7e9366f7 Iustin Pop
  elif opts.on_secondary:
713 a9e0c397 Iustin Pop
    mode = constants.REPLACE_DISK_SEC
714 05d47e33 Michael Hanselmann
  elif opts.auto:
715 05d47e33 Michael Hanselmann
    mode = constants.REPLACE_DISK_AUTO
716 05d47e33 Michael Hanselmann
    if disks:
717 05d47e33 Michael Hanselmann
      raise errors.OpPrereqError("Cannot specify disks when using automatic"
718 debac808 Iustin Pop
                                 " mode", errors.ECODE_INVAL)
719 7e9366f7 Iustin Pop
  elif new_2ndary is not None or iallocator is not None:
720 7e9366f7 Iustin Pop
    # replace secondary
721 7e9366f7 Iustin Pop
    mode = constants.REPLACE_DISK_CHG
722 a9e0c397 Iustin Pop
723 668f755d Iustin Pop
  op = opcodes.OpInstanceReplaceDisks(instance_name=args[0], disks=disks,
724 668f755d Iustin Pop
                                      remote_node=new_2ndary, mode=mode,
725 668f755d Iustin Pop
                                      iallocator=iallocator,
726 893e8f49 René Nussbaumer
                                      early_release=opts.early_release,
727 893e8f49 René Nussbaumer
                                      ignore_ipolicy=opts.ignore_ipolicy)
728 6340bb0a Iustin Pop
  SubmitOrSend(op, opts)
729 a8083063 Iustin Pop
  return 0
730 a8083063 Iustin Pop
731 a8083063 Iustin Pop
732 a8083063 Iustin Pop
def FailoverInstance(opts, args):
733 a8083063 Iustin Pop
  """Failover an instance.
734 a8083063 Iustin Pop

735 a8083063 Iustin Pop
  The failover is done by shutting it down on its present node and
736 a8083063 Iustin Pop
  starting it on the secondary.
737 a8083063 Iustin Pop

738 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
739 7232c04c Iustin Pop
  @type args: list
740 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
741 7232c04c Iustin Pop
  @rtype: int
742 7232c04c Iustin Pop
  @return: the desired exit code
743 a8083063 Iustin Pop

744 a8083063 Iustin Pop
  """
745 a76f0c4a Iustin Pop
  cl = GetClient()
746 80de0e3f Iustin Pop
  instance_name = args[0]
747 80de0e3f Iustin Pop
  force = opts.force
748 1b7761fd Apollon Oikonomopoulos
  iallocator = opts.iallocator
749 1b7761fd Apollon Oikonomopoulos
  target_node = opts.dst_node
750 1b7761fd Apollon Oikonomopoulos
751 1b7761fd Apollon Oikonomopoulos
  if iallocator and target_node:
752 1b7761fd Apollon Oikonomopoulos
    raise errors.OpPrereqError("Specify either an iallocator (-I), or a target"
753 1b7761fd Apollon Oikonomopoulos
                               " node (-n) but not both", errors.ECODE_INVAL)
754 a8083063 Iustin Pop
755 80de0e3f Iustin Pop
  if not force:
756 a76f0c4a Iustin Pop
    _EnsureInstancesExist(cl, [instance_name])
757 a76f0c4a Iustin Pop
758 80de0e3f Iustin Pop
    usertext = ("Failover will happen to image %s."
759 80de0e3f Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
760 80de0e3f Iustin Pop
                (instance_name,))
761 80de0e3f Iustin Pop
    if not AskUser(usertext):
762 80de0e3f Iustin Pop
      return 1
763 a8083063 Iustin Pop
764 019dbee1 Iustin Pop
  op = opcodes.OpInstanceFailover(instance_name=instance_name,
765 17c3f802 Guido Trotter
                                  ignore_consistency=opts.ignore_consistency,
766 1b7761fd Apollon Oikonomopoulos
                                  shutdown_timeout=opts.shutdown_timeout,
767 1b7761fd Apollon Oikonomopoulos
                                  iallocator=iallocator,
768 b6aaf437 René Nussbaumer
                                  target_node=target_node,
769 b6aaf437 René Nussbaumer
                                  ignore_ipolicy=opts.ignore_ipolicy)
770 a76f0c4a Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
771 80de0e3f Iustin Pop
  return 0
772 a8083063 Iustin Pop
773 a8083063 Iustin Pop
774 53c776b5 Iustin Pop
def MigrateInstance(opts, args):
775 53c776b5 Iustin Pop
  """Migrate an instance.
776 53c776b5 Iustin Pop

777 53c776b5 Iustin Pop
  The migrate is done without shutdown.
778 53c776b5 Iustin Pop

779 2f907a8c Iustin Pop
  @param opts: the command line options selected by the user
780 2f907a8c Iustin Pop
  @type args: list
781 2f907a8c Iustin Pop
  @param args: should contain only one element, the instance name
782 2f907a8c Iustin Pop
  @rtype: int
783 2f907a8c Iustin Pop
  @return: the desired exit code
784 53c776b5 Iustin Pop

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

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

840 fbf5a861 Iustin Pop
  """
841 fbf5a861 Iustin Pop
  cl = GetClient()
842 fbf5a861 Iustin Pop
  instance_name = args[0]
843 fbf5a861 Iustin Pop
  force = opts.force
844 fbf5a861 Iustin Pop
845 fbf5a861 Iustin Pop
  if not force:
846 fbf5a861 Iustin Pop
    usertext = ("Instance %s will be moved."
847 fbf5a861 Iustin Pop
                " This requires a shutdown of the instance. Continue?" %
848 fbf5a861 Iustin Pop
                (instance_name,))
849 fbf5a861 Iustin Pop
    if not AskUser(usertext):
850 fbf5a861 Iustin Pop
      return 1
851 fbf5a861 Iustin Pop
852 0091b480 Iustin Pop
  op = opcodes.OpInstanceMove(instance_name=instance_name,
853 17c3f802 Guido Trotter
                              target_node=opts.node,
854 bb851c63 Iustin Pop
                              shutdown_timeout=opts.shutdown_timeout,
855 92cf62e3 René Nussbaumer
                              ignore_consistency=opts.ignore_consistency,
856 92cf62e3 René Nussbaumer
                              ignore_ipolicy=opts.ignore_ipolicy)
857 fbf5a861 Iustin Pop
  SubmitOrSend(op, opts, cl=cl)
858 fbf5a861 Iustin Pop
  return 0
859 fbf5a861 Iustin Pop
860 fbf5a861 Iustin Pop
861 a8083063 Iustin Pop
def ConnectToInstanceConsole(opts, args):
862 a8083063 Iustin Pop
  """Connect to the console of an instance.
863 a8083063 Iustin Pop

864 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
865 7232c04c Iustin Pop
  @type args: list
866 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
867 7232c04c Iustin Pop
  @rtype: int
868 7232c04c Iustin Pop
  @return: the desired exit code
869 a8083063 Iustin Pop

870 a8083063 Iustin Pop
  """
871 a8083063 Iustin Pop
  instance_name = args[0]
872 a8083063 Iustin Pop
873 25ce3ec4 Michael Hanselmann
  cl = GetClient()
874 25ce3ec4 Michael Hanselmann
  try:
875 25ce3ec4 Michael Hanselmann
    cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
876 d6f46b6a Michael Hanselmann
    ((console_data, oper_state), ) = \
877 d6f46b6a Michael Hanselmann
      cl.QueryInstances([instance_name], ["console", "oper_state"], False)
878 25ce3ec4 Michael Hanselmann
  finally:
879 25ce3ec4 Michael Hanselmann
    # Ensure client connection is closed while external commands are run
880 25ce3ec4 Michael Hanselmann
    cl.Close()
881 25ce3ec4 Michael Hanselmann
882 25ce3ec4 Michael Hanselmann
  del cl
883 25ce3ec4 Michael Hanselmann
884 d6f46b6a Michael Hanselmann
  if not console_data:
885 d6f46b6a Michael Hanselmann
    if oper_state:
886 d6f46b6a Michael Hanselmann
      # Instance is running
887 d6f46b6a Michael Hanselmann
      raise errors.OpExecError("Console information for instance %s is"
888 d6f46b6a Michael Hanselmann
                               " unavailable" % instance_name)
889 d6f46b6a Michael Hanselmann
    else:
890 d6f46b6a Michael Hanselmann
      raise errors.OpExecError("Instance %s is not running, can't get console" %
891 d6f46b6a Michael Hanselmann
                               instance_name)
892 d6f46b6a Michael Hanselmann
893 25ce3ec4 Michael Hanselmann
  return _DoConsole(objects.InstanceConsole.FromDict(console_data),
894 25ce3ec4 Michael Hanselmann
                    opts.show_command, cluster_name)
895 25ce3ec4 Michael Hanselmann
896 25ce3ec4 Michael Hanselmann
897 25ce3ec4 Michael Hanselmann
def _DoConsole(console, show_command, cluster_name, feedback_fn=ToStdout,
898 25ce3ec4 Michael Hanselmann
               _runcmd_fn=utils.RunCmd):
899 cc0dec7b Iustin Pop
  """Acts based on the result of L{opcodes.OpInstanceConsole}.
900 25ce3ec4 Michael Hanselmann

901 25ce3ec4 Michael Hanselmann
  @type console: L{objects.InstanceConsole}
902 25ce3ec4 Michael Hanselmann
  @param console: Console object
903 25ce3ec4 Michael Hanselmann
  @type show_command: bool
904 25ce3ec4 Michael Hanselmann
  @param show_command: Whether to just display commands
905 25ce3ec4 Michael Hanselmann
  @type cluster_name: string
906 25ce3ec4 Michael Hanselmann
  @param cluster_name: Cluster name as retrieved from master daemon
907 25ce3ec4 Michael Hanselmann

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

952 19708787 Iustin Pop
  """
953 19708787 Iustin Pop
  if dev_type == constants.LD_DRBD8:
954 19708787 Iustin Pop
    node_a, node_b, port, minor_a, minor_b, key = logical_id
955 19708787 Iustin Pop
    data = [
956 e2736e40 Guido Trotter
      ("nodeA", "%s, minor=%s" % (node_a, compat.TryToRoman(minor_a,
957 e2736e40 Guido Trotter
                                                            convert=roman))),
958 e2736e40 Guido Trotter
      ("nodeB", "%s, minor=%s" % (node_b, compat.TryToRoman(minor_b,
959 e2736e40 Guido Trotter
                                                            convert=roman))),
960 2cbcf95d Bernardo Dal Seno
      ("port", str(compat.TryToRoman(port, convert=roman))),
961 2cbcf95d Bernardo Dal Seno
      ("auth key", str(key)),
962 19708787 Iustin Pop
      ]
963 19708787 Iustin Pop
  elif dev_type == constants.LD_LV:
964 19708787 Iustin Pop
    vg_name, lv_name = logical_id
965 19708787 Iustin Pop
    data = ["%s/%s" % (vg_name, lv_name)]
966 19708787 Iustin Pop
  else:
967 19708787 Iustin Pop
    data = [str(logical_id)]
968 19708787 Iustin Pop
969 19708787 Iustin Pop
  return data
970 19708787 Iustin Pop
971 19708787 Iustin Pop
972 2cbcf95d Bernardo Dal Seno
def _FormatListInfo(data):
973 2cbcf95d Bernardo Dal Seno
  return list(str(i) for i in data)
974 2cbcf95d Bernardo Dal Seno
975 2cbcf95d Bernardo Dal Seno
976 f965260c Michael Hanselmann
def _FormatBlockDevInfo(idx, top_level, dev, roman):
977 a8083063 Iustin Pop
  """Show block device information.
978 a8083063 Iustin Pop

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

982 19708787 Iustin Pop
  @type idx: int
983 19708787 Iustin Pop
  @param idx: the index of the current disk
984 19708787 Iustin Pop
  @type top_level: boolean
985 19708787 Iustin Pop
  @param top_level: if this a top-level disk?
986 7232c04c Iustin Pop
  @type dev: dict
987 7232c04c Iustin Pop
  @param dev: dictionary with disk information
988 e2736e40 Guido Trotter
  @type roman: boolean
989 e2736e40 Guido Trotter
  @param roman: whether to try to use roman integers
990 19708787 Iustin Pop
  @return: a list of either strings, tuples or lists
991 19708787 Iustin Pop
      (which should be formatted at a higher indent level)
992 7232c04c Iustin Pop

993 a8083063 Iustin Pop
  """
994 19708787 Iustin Pop
  def helper(dtype, status):
995 7232c04c Iustin Pop
    """Format one line for physical device status.
996 7232c04c Iustin Pop

997 7232c04c Iustin Pop
    @type dtype: str
998 7232c04c Iustin Pop
    @param dtype: a constant from the L{constants.LDS_BLOCK} set
999 7232c04c Iustin Pop
    @type status: tuple
1000 7232c04c Iustin Pop
    @param status: a tuple as returned from L{backend.FindBlockDevice}
1001 19708787 Iustin Pop
    @return: the string representing the status
1002 7232c04c Iustin Pop

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

1205 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1206 7232c04c Iustin Pop
  @type args: list
1207 7232c04c Iustin Pop
  @param args: either an empty list, and then we query all
1208 7232c04c Iustin Pop
      instances, or should contain a list of instance names
1209 7232c04c Iustin Pop
  @rtype: int
1210 7232c04c Iustin Pop
  @return: the desired exit code
1211 7232c04c Iustin Pop

1212 a8083063 Iustin Pop
  """
1213 220cde0b Guido Trotter
  if not args and not opts.show_all:
1214 220cde0b Guido Trotter
    ToStderr("No instance selected."
1215 220cde0b Guido Trotter
             " Please pass in --all if you want to query all instances.\n"
1216 220cde0b Guido Trotter
             "Note that this can take a long time on a big cluster.")
1217 220cde0b Guido Trotter
    return 1
1218 220cde0b Guido Trotter
  elif args and opts.show_all:
1219 220cde0b Guido Trotter
    ToStderr("Cannot use --all if you specify instance names.")
1220 220cde0b Guido Trotter
    return 1
1221 220cde0b Guido Trotter
1222 a8083063 Iustin Pop
  retcode = 0
1223 5c097318 Iustin Pop
  op = opcodes.OpInstanceQueryData(instances=args, static=opts.static,
1224 5c097318 Iustin Pop
                                   use_locking=not opts.static)
1225 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
1226 a8083063 Iustin Pop
  if not result:
1227 3a24c527 Iustin Pop
    ToStdout("No instances.")
1228 a8083063 Iustin Pop
    return 1
1229 a8083063 Iustin Pop
1230 2cbcf95d Bernardo Dal Seno
  PrintGenericInfo([
1231 2cbcf95d Bernardo Dal Seno
    _FormatInstanceInfo(instance, opts.roman_integers)
1232 2cbcf95d Bernardo Dal Seno
    for instance in result.values()
1233 2cbcf95d Bernardo Dal Seno
    ])
1234 a8083063 Iustin Pop
  return retcode
1235 a8083063 Iustin Pop
1236 a8083063 Iustin Pop
1237 a71f835e Michael Hanselmann
def _ConvertNicDiskModifications(mods):
1238 a71f835e Michael Hanselmann
  """Converts NIC/disk modifications from CLI to opcode.
1239 a71f835e Michael Hanselmann

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

1245 a71f835e Michael Hanselmann
  @type mods: list of tuples
1246 a71f835e Michael Hanselmann
  @param mods: Modifications as given by command line parser
1247 a71f835e Michael Hanselmann
  @rtype: list of tuples
1248 a71f835e Michael Hanselmann
  @return: Modifications as understood by L{opcodes.OpInstanceSetParams}
1249 a71f835e Michael Hanselmann

1250 a71f835e Michael Hanselmann
  """
1251 a71f835e Michael Hanselmann
  result = []
1252 a71f835e Michael Hanselmann
1253 b21d488b Christos Stavrakakis
  for (identifier, params) in mods:
1254 b21d488b Christos Stavrakakis
    if identifier == constants.DDM_ADD:
1255 a71f835e Michael Hanselmann
      # Add item as last item (legacy interface)
1256 a71f835e Michael Hanselmann
      action = constants.DDM_ADD
1257 b21d488b Christos Stavrakakis
      identifier = -1
1258 b21d488b Christos Stavrakakis
    elif identifier == constants.DDM_REMOVE:
1259 a71f835e Michael Hanselmann
      # Remove last item (legacy interface)
1260 a71f835e Michael Hanselmann
      action = constants.DDM_REMOVE
1261 b21d488b Christos Stavrakakis
      identifier = -1
1262 a71f835e Michael Hanselmann
    else:
1263 a71f835e Michael Hanselmann
      # Modifications and adding/removing at arbitrary indices
1264 a71f835e Michael Hanselmann
      add = params.pop(constants.DDM_ADD, _MISSING)
1265 a71f835e Michael Hanselmann
      remove = params.pop(constants.DDM_REMOVE, _MISSING)
1266 f0d22861 Constantinos Venetsanopoulos
      modify = params.pop(constants.DDM_MODIFY, _MISSING)
1267 f0d22861 Constantinos Venetsanopoulos
1268 f0d22861 Constantinos Venetsanopoulos
      if modify is _MISSING:
1269 f0d22861 Constantinos Venetsanopoulos
        if not (add is _MISSING or remove is _MISSING):
1270 f0d22861 Constantinos Venetsanopoulos
          raise errors.OpPrereqError("Cannot add and remove at the same time",
1271 f0d22861 Constantinos Venetsanopoulos
                                     errors.ECODE_INVAL)
1272 f0d22861 Constantinos Venetsanopoulos
        elif add is not _MISSING:
1273 f0d22861 Constantinos Venetsanopoulos
          action = constants.DDM_ADD
1274 f0d22861 Constantinos Venetsanopoulos
        elif remove is not _MISSING:
1275 f0d22861 Constantinos Venetsanopoulos
          action = constants.DDM_REMOVE
1276 f0d22861 Constantinos Venetsanopoulos
        else:
1277 f0d22861 Constantinos Venetsanopoulos
          action = constants.DDM_MODIFY
1278 a71f835e Michael Hanselmann
1279 7a70541e Michael Hanselmann
      elif add is _MISSING and remove is _MISSING:
1280 7a70541e Michael Hanselmann
        action = constants.DDM_MODIFY
1281 a71f835e Michael Hanselmann
      else:
1282 7a70541e Michael Hanselmann
        raise errors.OpPrereqError("Cannot modify and add/remove at the"
1283 7a70541e Michael Hanselmann
                                   " same time", errors.ECODE_INVAL)
1284 a71f835e Michael Hanselmann
1285 a71f835e Michael Hanselmann
      assert not (constants.DDMS_VALUES_WITH_MODIFY & set(params.keys()))
1286 a71f835e Michael Hanselmann
1287 a71f835e Michael Hanselmann
    if action == constants.DDM_REMOVE and params:
1288 a71f835e Michael Hanselmann
      raise errors.OpPrereqError("Not accepting parameters on removal",
1289 a71f835e Michael Hanselmann
                                 errors.ECODE_INVAL)
1290 a71f835e Michael Hanselmann
1291 b21d488b Christos Stavrakakis
    result.append((action, identifier, params))
1292 a71f835e Michael Hanselmann
1293 a71f835e Michael Hanselmann
  return result
1294 a71f835e Michael Hanselmann
1295 a71f835e Michael Hanselmann
1296 a71f835e Michael Hanselmann
def _ParseDiskSizes(mods):
1297 a71f835e Michael Hanselmann
  """Parses disk sizes in parameters.
1298 a71f835e Michael Hanselmann

1299 a71f835e Michael Hanselmann
  """
1300 a71f835e Michael Hanselmann
  for (action, _, params) in mods:
1301 a71f835e Michael Hanselmann
    if params and constants.IDISK_SIZE in params:
1302 a71f835e Michael Hanselmann
      params[constants.IDISK_SIZE] = \
1303 a71f835e Michael Hanselmann
        utils.ParseUnit(params[constants.IDISK_SIZE])
1304 a71f835e Michael Hanselmann
    elif action == constants.DDM_ADD:
1305 a71f835e Michael Hanselmann
      raise errors.OpPrereqError("Missing required parameter 'size'",
1306 a71f835e Michael Hanselmann
                                 errors.ECODE_INVAL)
1307 a71f835e Michael Hanselmann
1308 a71f835e Michael Hanselmann
  return mods
1309 a71f835e Michael Hanselmann
1310 a71f835e Michael Hanselmann
1311 7767bbf5 Manuel Franceschini
def SetInstanceParams(opts, args):
1312 a8083063 Iustin Pop
  """Modifies an instance.
1313 a8083063 Iustin Pop

1314 a8083063 Iustin Pop
  All parameters take effect only at the next restart of the instance.
1315 a8083063 Iustin Pop

1316 7232c04c Iustin Pop
  @param opts: the command line options selected by the user
1317 7232c04c Iustin Pop
  @type args: list
1318 7232c04c Iustin Pop
  @param args: should contain only one element, the instance name
1319 7232c04c Iustin Pop
  @rtype: int
1320 7232c04c Iustin Pop
  @return: the desired exit code
1321 a8083063 Iustin Pop

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

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