Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / instance.py @ 87ed6b79

History | View | Annotate | Download (157.1 kB)

1 22b7f6f8 Thomas Thrainer
#
2 22b7f6f8 Thomas Thrainer
#
3 22b7f6f8 Thomas Thrainer
4 81c222af Jose A. Lopes
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Google Inc.
5 22b7f6f8 Thomas Thrainer
#
6 22b7f6f8 Thomas Thrainer
# This program is free software; you can redistribute it and/or modify
7 22b7f6f8 Thomas Thrainer
# it under the terms of the GNU General Public License as published by
8 22b7f6f8 Thomas Thrainer
# the Free Software Foundation; either version 2 of the License, or
9 22b7f6f8 Thomas Thrainer
# (at your option) any later version.
10 22b7f6f8 Thomas Thrainer
#
11 22b7f6f8 Thomas Thrainer
# This program is distributed in the hope that it will be useful, but
12 22b7f6f8 Thomas Thrainer
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 22b7f6f8 Thomas Thrainer
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 22b7f6f8 Thomas Thrainer
# General Public License for more details.
15 22b7f6f8 Thomas Thrainer
#
16 22b7f6f8 Thomas Thrainer
# You should have received a copy of the GNU General Public License
17 22b7f6f8 Thomas Thrainer
# along with this program; if not, write to the Free Software
18 22b7f6f8 Thomas Thrainer
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 22b7f6f8 Thomas Thrainer
# 02110-1301, USA.
20 22b7f6f8 Thomas Thrainer
21 22b7f6f8 Thomas Thrainer
22 22b7f6f8 Thomas Thrainer
"""Logical units dealing with instances."""
23 22b7f6f8 Thomas Thrainer
24 22b7f6f8 Thomas Thrainer
import OpenSSL
25 22b7f6f8 Thomas Thrainer
import copy
26 22b7f6f8 Thomas Thrainer
import logging
27 22b7f6f8 Thomas Thrainer
import os
28 22b7f6f8 Thomas Thrainer
29 22b7f6f8 Thomas Thrainer
from ganeti import compat
30 22b7f6f8 Thomas Thrainer
from ganeti import constants
31 22b7f6f8 Thomas Thrainer
from ganeti import errors
32 22b7f6f8 Thomas Thrainer
from ganeti import ht
33 22b7f6f8 Thomas Thrainer
from ganeti import hypervisor
34 22b7f6f8 Thomas Thrainer
from ganeti import locking
35 22b7f6f8 Thomas Thrainer
from ganeti.masterd import iallocator
36 22b7f6f8 Thomas Thrainer
from ganeti import masterd
37 22b7f6f8 Thomas Thrainer
from ganeti import netutils
38 22b7f6f8 Thomas Thrainer
from ganeti import objects
39 22b7f6f8 Thomas Thrainer
from ganeti import pathutils
40 6bce7ba2 Santi Raffa
from ganeti import serializer
41 2329ffdd Jose A. Lopes
from ganeti import ssh
42 4869595d Petr Pudlak
import ganeti.rpc.node as rpc
43 22b7f6f8 Thomas Thrainer
from ganeti import utils
44 22b7f6f8 Thomas Thrainer
45 8aa8f6b1 Thomas Thrainer
from ganeti.cmdlib.base import NoHooksLU, LogicalUnit, ResultWithJobs
46 22b7f6f8 Thomas Thrainer
47 13f6af81 Thomas Thrainer
from ganeti.cmdlib.common import INSTANCE_DOWN, \
48 5eacbcae Thomas Thrainer
  INSTANCE_NOT_RUNNING, CAN_CHANGE_INSTANCE_OFFLINE, CheckNodeOnline, \
49 5eacbcae Thomas Thrainer
  ShareAll, GetDefaultIAllocator, CheckInstanceNodeGroups, \
50 5eacbcae Thomas Thrainer
  LoadNodeEvacResult, CheckIAllocatorOrNode, CheckParamsNotGlobal, \
51 1c4910f7 Jose A. Lopes
  IsExclusiveStorageEnabledNode, CheckHVParams, CheckOSParams, CheckOSImage, \
52 da4a52a3 Thomas Thrainer
  AnnotateDiskParams, GetUpdatedParams, ExpandInstanceUuidAndName, \
53 1f7c8208 Helga Velroyen
  ComputeIPolicySpecViolation, CheckInstanceState, ExpandNodeUuidAndName, \
54 294254b1 Raffa Santi
  CheckDiskTemplateEnabled, IsValidDiskAccessModeCombination
55 5eacbcae Thomas Thrainer
from ganeti.cmdlib.instance_storage import CreateDisks, \
56 2329ffdd Jose A. Lopes
  CheckNodesFreeDiskPerVG, WipeDisks, WipeOrCleanupDisks, ImageDisks, \
57 2329ffdd Jose A. Lopes
  WaitForSync, IsExclusiveStorageEnabledNodeUuid, CreateSingleBlockDev, \
58 2329ffdd Jose A. Lopes
  ComputeDisks, CheckRADOSFreeSpace, ComputeDiskSizePerVG, \
59 2329ffdd Jose A. Lopes
  GenerateDiskTemplate, StartInstanceDisks, ShutdownInstanceDisks, \
60 2329ffdd Jose A. Lopes
  AssembleInstanceDisks, CheckSpindlesExclusiveStorage
61 5eacbcae Thomas Thrainer
from ganeti.cmdlib.instance_utils import BuildInstanceHookEnvByObject, \
62 5eacbcae Thomas Thrainer
  GetClusterDomainSecret, BuildInstanceHookEnv, NICListToTuple, \
63 5eacbcae Thomas Thrainer
  NICToTuple, CheckNodeNotDrained, RemoveInstance, CopyLockList, \
64 5eacbcae Thomas Thrainer
  ReleaseLocks, CheckNodeVmCapable, CheckTargetNodeIPolicy, \
65 5eacbcae Thomas Thrainer
  GetInstanceInfoText, RemoveDisks, CheckNodeFreeMemory, \
66 5eacbcae Thomas Thrainer
  CheckInstanceBridgesExist, CheckNicsBridgesExist, CheckNodeHasOS
67 22b7f6f8 Thomas Thrainer
68 22b7f6f8 Thomas Thrainer
import ganeti.masterd.instance
69 22b7f6f8 Thomas Thrainer
70 22b7f6f8 Thomas Thrainer
71 5eacbcae Thomas Thrainer
#: Type description for changes as returned by L{_ApplyContainerMods}'s
72 22b7f6f8 Thomas Thrainer
#: callbacks
73 22b7f6f8 Thomas Thrainer
_TApplyContModsCbChanges = \
74 22b7f6f8 Thomas Thrainer
  ht.TMaybeListOf(ht.TAnd(ht.TIsLength(2), ht.TItems([
75 22b7f6f8 Thomas Thrainer
    ht.TNonEmptyString,
76 22b7f6f8 Thomas Thrainer
    ht.TAny,
77 22b7f6f8 Thomas Thrainer
    ])))
78 22b7f6f8 Thomas Thrainer
79 22b7f6f8 Thomas Thrainer
80 22b7f6f8 Thomas Thrainer
def _CheckHostnameSane(lu, name):
81 22b7f6f8 Thomas Thrainer
  """Ensures that a given hostname resolves to a 'sane' name.
82 22b7f6f8 Thomas Thrainer

83 22b7f6f8 Thomas Thrainer
  The given name is required to be a prefix of the resolved hostname,
84 22b7f6f8 Thomas Thrainer
  to prevent accidental mismatches.
85 22b7f6f8 Thomas Thrainer

86 22b7f6f8 Thomas Thrainer
  @param lu: the logical unit on behalf of which we're checking
87 22b7f6f8 Thomas Thrainer
  @param name: the name we should resolve and check
88 22b7f6f8 Thomas Thrainer
  @return: the resolved hostname object
89 22b7f6f8 Thomas Thrainer

90 22b7f6f8 Thomas Thrainer
  """
91 22b7f6f8 Thomas Thrainer
  hostname = netutils.GetHostname(name=name)
92 22b7f6f8 Thomas Thrainer
  if hostname.name != name:
93 22b7f6f8 Thomas Thrainer
    lu.LogInfo("Resolved given name '%s' to '%s'", name, hostname.name)
94 22b7f6f8 Thomas Thrainer
  if not utils.MatchNameComponent(name, [hostname.name]):
95 22b7f6f8 Thomas Thrainer
    raise errors.OpPrereqError(("Resolved hostname '%s' does not look the"
96 22b7f6f8 Thomas Thrainer
                                " same as given hostname '%s'") %
97 22b7f6f8 Thomas Thrainer
                               (hostname.name, name), errors.ECODE_INVAL)
98 22b7f6f8 Thomas Thrainer
  return hostname
99 22b7f6f8 Thomas Thrainer
100 22b7f6f8 Thomas Thrainer
101 22b7f6f8 Thomas Thrainer
def _CheckOpportunisticLocking(op):
102 22b7f6f8 Thomas Thrainer
  """Generate error if opportunistic locking is not possible.
103 22b7f6f8 Thomas Thrainer

104 22b7f6f8 Thomas Thrainer
  """
105 22b7f6f8 Thomas Thrainer
  if op.opportunistic_locking and not op.iallocator:
106 22b7f6f8 Thomas Thrainer
    raise errors.OpPrereqError("Opportunistic locking is only available in"
107 22b7f6f8 Thomas Thrainer
                               " combination with an instance allocator",
108 22b7f6f8 Thomas Thrainer
                               errors.ECODE_INVAL)
109 22b7f6f8 Thomas Thrainer
110 22b7f6f8 Thomas Thrainer
111 1c3231aa Thomas Thrainer
def _CreateInstanceAllocRequest(op, disks, nics, beparams, node_name_whitelist):
112 22b7f6f8 Thomas Thrainer
  """Wrapper around IAReqInstanceAlloc.
113 22b7f6f8 Thomas Thrainer

114 22b7f6f8 Thomas Thrainer
  @param op: The instance opcode
115 22b7f6f8 Thomas Thrainer
  @param disks: The computed disks
116 22b7f6f8 Thomas Thrainer
  @param nics: The computed nics
117 22b7f6f8 Thomas Thrainer
  @param beparams: The full filled beparams
118 1c3231aa Thomas Thrainer
  @param node_name_whitelist: List of nodes which should appear as online to the
119 22b7f6f8 Thomas Thrainer
    allocator (unless the node is already marked offline)
120 22b7f6f8 Thomas Thrainer

121 22b7f6f8 Thomas Thrainer
  @returns: A filled L{iallocator.IAReqInstanceAlloc}
122 22b7f6f8 Thomas Thrainer

123 22b7f6f8 Thomas Thrainer
  """
124 22b7f6f8 Thomas Thrainer
  spindle_use = beparams[constants.BE_SPINDLE_USE]
125 22b7f6f8 Thomas Thrainer
  return iallocator.IAReqInstanceAlloc(name=op.instance_name,
126 22b7f6f8 Thomas Thrainer
                                       disk_template=op.disk_template,
127 22b7f6f8 Thomas Thrainer
                                       tags=op.tags,
128 22b7f6f8 Thomas Thrainer
                                       os=op.os_type,
129 22b7f6f8 Thomas Thrainer
                                       vcpus=beparams[constants.BE_VCPUS],
130 22b7f6f8 Thomas Thrainer
                                       memory=beparams[constants.BE_MAXMEM],
131 22b7f6f8 Thomas Thrainer
                                       spindle_use=spindle_use,
132 22b7f6f8 Thomas Thrainer
                                       disks=disks,
133 22b7f6f8 Thomas Thrainer
                                       nics=[n.ToDict() for n in nics],
134 22b7f6f8 Thomas Thrainer
                                       hypervisor=op.hypervisor,
135 1c3231aa Thomas Thrainer
                                       node_whitelist=node_name_whitelist)
136 22b7f6f8 Thomas Thrainer
137 22b7f6f8 Thomas Thrainer
138 22b7f6f8 Thomas Thrainer
def _ComputeFullBeParams(op, cluster):
139 22b7f6f8 Thomas Thrainer
  """Computes the full beparams.
140 22b7f6f8 Thomas Thrainer

141 22b7f6f8 Thomas Thrainer
  @param op: The instance opcode
142 22b7f6f8 Thomas Thrainer
  @param cluster: The cluster config object
143 22b7f6f8 Thomas Thrainer

144 22b7f6f8 Thomas Thrainer
  @return: The fully filled beparams
145 22b7f6f8 Thomas Thrainer

146 22b7f6f8 Thomas Thrainer
  """
147 22b7f6f8 Thomas Thrainer
  default_beparams = cluster.beparams[constants.PP_DEFAULT]
148 22b7f6f8 Thomas Thrainer
  for param, value in op.beparams.iteritems():
149 22b7f6f8 Thomas Thrainer
    if value == constants.VALUE_AUTO:
150 22b7f6f8 Thomas Thrainer
      op.beparams[param] = default_beparams[param]
151 22b7f6f8 Thomas Thrainer
  objects.UpgradeBeParams(op.beparams)
152 22b7f6f8 Thomas Thrainer
  utils.ForceDictType(op.beparams, constants.BES_PARAMETER_TYPES)
153 22b7f6f8 Thomas Thrainer
  return cluster.SimpleFillBE(op.beparams)
154 22b7f6f8 Thomas Thrainer
155 22b7f6f8 Thomas Thrainer
156 22b7f6f8 Thomas Thrainer
def _ComputeNics(op, cluster, default_ip, cfg, ec_id):
157 22b7f6f8 Thomas Thrainer
  """Computes the nics.
158 22b7f6f8 Thomas Thrainer

159 22b7f6f8 Thomas Thrainer
  @param op: The instance opcode
160 22b7f6f8 Thomas Thrainer
  @param cluster: Cluster configuration object
161 22b7f6f8 Thomas Thrainer
  @param default_ip: The default ip to assign
162 22b7f6f8 Thomas Thrainer
  @param cfg: An instance of the configuration object
163 22b7f6f8 Thomas Thrainer
  @param ec_id: Execution context ID
164 22b7f6f8 Thomas Thrainer

165 22b7f6f8 Thomas Thrainer
  @returns: The build up nics
166 22b7f6f8 Thomas Thrainer

167 22b7f6f8 Thomas Thrainer
  """
168 22b7f6f8 Thomas Thrainer
  nics = []
169 22b7f6f8 Thomas Thrainer
  for nic in op.nics:
170 22b7f6f8 Thomas Thrainer
    nic_mode_req = nic.get(constants.INIC_MODE, None)
171 22b7f6f8 Thomas Thrainer
    nic_mode = nic_mode_req
172 22b7f6f8 Thomas Thrainer
    if nic_mode is None or nic_mode == constants.VALUE_AUTO:
173 22b7f6f8 Thomas Thrainer
      nic_mode = cluster.nicparams[constants.PP_DEFAULT][constants.NIC_MODE]
174 22b7f6f8 Thomas Thrainer
175 22b7f6f8 Thomas Thrainer
    net = nic.get(constants.INIC_NETWORK, None)
176 22b7f6f8 Thomas Thrainer
    link = nic.get(constants.NIC_LINK, None)
177 22b7f6f8 Thomas Thrainer
    ip = nic.get(constants.INIC_IP, None)
178 9f7d5fe4 Sebastian Gebhard
    vlan = nic.get(constants.INIC_VLAN, None)
179 22b7f6f8 Thomas Thrainer
180 22b7f6f8 Thomas Thrainer
    if net is None or net.lower() == constants.VALUE_NONE:
181 22b7f6f8 Thomas Thrainer
      net = None
182 22b7f6f8 Thomas Thrainer
    else:
183 22b7f6f8 Thomas Thrainer
      if nic_mode_req is not None or link is not None:
184 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("If network is given, no mode or link"
185 22b7f6f8 Thomas Thrainer
                                   " is allowed to be passed",
186 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
187 22b7f6f8 Thomas Thrainer
188 22b7f6f8 Thomas Thrainer
    # ip validity checks
189 22b7f6f8 Thomas Thrainer
    if ip is None or ip.lower() == constants.VALUE_NONE:
190 22b7f6f8 Thomas Thrainer
      nic_ip = None
191 22b7f6f8 Thomas Thrainer
    elif ip.lower() == constants.VALUE_AUTO:
192 22b7f6f8 Thomas Thrainer
      if not op.name_check:
193 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("IP address set to auto but name checks"
194 22b7f6f8 Thomas Thrainer
                                   " have been skipped",
195 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
196 22b7f6f8 Thomas Thrainer
      nic_ip = default_ip
197 22b7f6f8 Thomas Thrainer
    else:
198 22b7f6f8 Thomas Thrainer
      # We defer pool operations until later, so that the iallocator has
199 22b7f6f8 Thomas Thrainer
      # filled in the instance's node(s) dimara
200 22b7f6f8 Thomas Thrainer
      if ip.lower() == constants.NIC_IP_POOL:
201 22b7f6f8 Thomas Thrainer
        if net is None:
202 22b7f6f8 Thomas Thrainer
          raise errors.OpPrereqError("if ip=pool, parameter network"
203 22b7f6f8 Thomas Thrainer
                                     " must be passed too",
204 22b7f6f8 Thomas Thrainer
                                     errors.ECODE_INVAL)
205 22b7f6f8 Thomas Thrainer
206 22b7f6f8 Thomas Thrainer
      elif not netutils.IPAddress.IsValid(ip):
207 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Invalid IP address '%s'" % ip,
208 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
209 22b7f6f8 Thomas Thrainer
210 22b7f6f8 Thomas Thrainer
      nic_ip = ip
211 22b7f6f8 Thomas Thrainer
212 22b7f6f8 Thomas Thrainer
    # TODO: check the ip address for uniqueness
213 22b7f6f8 Thomas Thrainer
    if nic_mode == constants.NIC_MODE_ROUTED and not nic_ip:
214 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Routed nic mode requires an ip address",
215 22b7f6f8 Thomas Thrainer
                                 errors.ECODE_INVAL)
216 22b7f6f8 Thomas Thrainer
217 22b7f6f8 Thomas Thrainer
    # MAC address verification
218 22b7f6f8 Thomas Thrainer
    mac = nic.get(constants.INIC_MAC, constants.VALUE_AUTO)
219 22b7f6f8 Thomas Thrainer
    if mac not in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
220 22b7f6f8 Thomas Thrainer
      mac = utils.NormalizeAndValidateMac(mac)
221 22b7f6f8 Thomas Thrainer
222 22b7f6f8 Thomas Thrainer
      try:
223 22b7f6f8 Thomas Thrainer
        # TODO: We need to factor this out
224 22b7f6f8 Thomas Thrainer
        cfg.ReserveMAC(mac, ec_id)
225 22b7f6f8 Thomas Thrainer
      except errors.ReservationError:
226 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("MAC address %s already in use"
227 22b7f6f8 Thomas Thrainer
                                   " in cluster" % mac,
228 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_NOTUNIQUE)
229 22b7f6f8 Thomas Thrainer
230 22b7f6f8 Thomas Thrainer
    #  Build nic parameters
231 22b7f6f8 Thomas Thrainer
    nicparams = {}
232 22b7f6f8 Thomas Thrainer
    if nic_mode_req:
233 22b7f6f8 Thomas Thrainer
      nicparams[constants.NIC_MODE] = nic_mode
234 22b7f6f8 Thomas Thrainer
    if link:
235 22b7f6f8 Thomas Thrainer
      nicparams[constants.NIC_LINK] = link
236 9f7d5fe4 Sebastian Gebhard
    if vlan:
237 9f7d5fe4 Sebastian Gebhard
      nicparams[constants.NIC_VLAN] = vlan
238 22b7f6f8 Thomas Thrainer
239 22b7f6f8 Thomas Thrainer
    check_params = cluster.SimpleFillNIC(nicparams)
240 22b7f6f8 Thomas Thrainer
    objects.NIC.CheckParameterSyntax(check_params)
241 22b7f6f8 Thomas Thrainer
    net_uuid = cfg.LookupNetwork(net)
242 22b7f6f8 Thomas Thrainer
    name = nic.get(constants.INIC_NAME, None)
243 22b7f6f8 Thomas Thrainer
    if name is not None and name.lower() == constants.VALUE_NONE:
244 22b7f6f8 Thomas Thrainer
      name = None
245 22b7f6f8 Thomas Thrainer
    nic_obj = objects.NIC(mac=mac, ip=nic_ip, name=name,
246 22b7f6f8 Thomas Thrainer
                          network=net_uuid, nicparams=nicparams)
247 22b7f6f8 Thomas Thrainer
    nic_obj.uuid = cfg.GenerateUniqueID(ec_id)
248 22b7f6f8 Thomas Thrainer
    nics.append(nic_obj)
249 22b7f6f8 Thomas Thrainer
250 22b7f6f8 Thomas Thrainer
  return nics
251 22b7f6f8 Thomas Thrainer
252 22b7f6f8 Thomas Thrainer
253 1c3231aa Thomas Thrainer
def _CheckForConflictingIp(lu, ip, node_uuid):
254 22b7f6f8 Thomas Thrainer
  """In case of conflicting IP address raise error.
255 22b7f6f8 Thomas Thrainer

256 22b7f6f8 Thomas Thrainer
  @type ip: string
257 22b7f6f8 Thomas Thrainer
  @param ip: IP address
258 1c3231aa Thomas Thrainer
  @type node_uuid: string
259 1c3231aa Thomas Thrainer
  @param node_uuid: node UUID
260 22b7f6f8 Thomas Thrainer

261 22b7f6f8 Thomas Thrainer
  """
262 1c3231aa Thomas Thrainer
  (conf_net, _) = lu.cfg.CheckIPInNodeGroup(ip, node_uuid)
263 22b7f6f8 Thomas Thrainer
  if conf_net is not None:
264 22b7f6f8 Thomas Thrainer
    raise errors.OpPrereqError(("The requested IP address (%s) belongs to"
265 22b7f6f8 Thomas Thrainer
                                " network %s, but the target NIC does not." %
266 22b7f6f8 Thomas Thrainer
                                (ip, conf_net)),
267 22b7f6f8 Thomas Thrainer
                               errors.ECODE_STATE)
268 22b7f6f8 Thomas Thrainer
269 22b7f6f8 Thomas Thrainer
  return (None, None)
270 22b7f6f8 Thomas Thrainer
271 22b7f6f8 Thomas Thrainer
272 22b7f6f8 Thomas Thrainer
def _ComputeIPolicyInstanceSpecViolation(
273 22b7f6f8 Thomas Thrainer
  ipolicy, instance_spec, disk_template,
274 5eacbcae Thomas Thrainer
  _compute_fn=ComputeIPolicySpecViolation):
275 22b7f6f8 Thomas Thrainer
  """Compute if instance specs meets the specs of ipolicy.
276 22b7f6f8 Thomas Thrainer

277 22b7f6f8 Thomas Thrainer
  @type ipolicy: dict
278 22b7f6f8 Thomas Thrainer
  @param ipolicy: The ipolicy to verify against
279 22b7f6f8 Thomas Thrainer
  @param instance_spec: dict
280 22b7f6f8 Thomas Thrainer
  @param instance_spec: The instance spec to verify
281 22b7f6f8 Thomas Thrainer
  @type disk_template: string
282 22b7f6f8 Thomas Thrainer
  @param disk_template: the disk template of the instance
283 22b7f6f8 Thomas Thrainer
  @param _compute_fn: The function to verify ipolicy (unittest only)
284 5eacbcae Thomas Thrainer
  @see: L{ComputeIPolicySpecViolation}
285 22b7f6f8 Thomas Thrainer

286 22b7f6f8 Thomas Thrainer
  """
287 22b7f6f8 Thomas Thrainer
  mem_size = instance_spec.get(constants.ISPEC_MEM_SIZE, None)
288 22b7f6f8 Thomas Thrainer
  cpu_count = instance_spec.get(constants.ISPEC_CPU_COUNT, None)
289 22b7f6f8 Thomas Thrainer
  disk_count = instance_spec.get(constants.ISPEC_DISK_COUNT, 0)
290 22b7f6f8 Thomas Thrainer
  disk_sizes = instance_spec.get(constants.ISPEC_DISK_SIZE, [])
291 22b7f6f8 Thomas Thrainer
  nic_count = instance_spec.get(constants.ISPEC_NIC_COUNT, 0)
292 22b7f6f8 Thomas Thrainer
  spindle_use = instance_spec.get(constants.ISPEC_SPINDLE_USE, None)
293 22b7f6f8 Thomas Thrainer
294 22b7f6f8 Thomas Thrainer
  return _compute_fn(ipolicy, mem_size, cpu_count, disk_count, nic_count,
295 22b7f6f8 Thomas Thrainer
                     disk_sizes, spindle_use, disk_template)
296 22b7f6f8 Thomas Thrainer
297 22b7f6f8 Thomas Thrainer
298 e25625ab Jose A. Lopes
def _ComputeInstanceCommunicationNIC(instance_name):
299 e25625ab Jose A. Lopes
  """Compute the name of the instance NIC used by instance
300 e25625ab Jose A. Lopes
  communication.
301 e25625ab Jose A. Lopes

302 e25625ab Jose A. Lopes
  With instance communication, a new NIC is added to the instance.
303 e25625ab Jose A. Lopes
  This NIC has a special name that identities it as being part of
304 e25625ab Jose A. Lopes
  instance communication, and not just a normal NIC.  This function
305 e25625ab Jose A. Lopes
  generates the name of the NIC based on a prefix and the instance
306 e25625ab Jose A. Lopes
  name
307 e25625ab Jose A. Lopes

308 e25625ab Jose A. Lopes
  @type instance_name: string
309 e25625ab Jose A. Lopes
  @param instance_name: name of the instance the NIC belongs to
310 e25625ab Jose A. Lopes

311 e25625ab Jose A. Lopes
  @rtype: string
312 e25625ab Jose A. Lopes
  @return: name of the NIC
313 e25625ab Jose A. Lopes

314 e25625ab Jose A. Lopes
  """
315 e25625ab Jose A. Lopes
  return constants.INSTANCE_COMMUNICATION_NIC_PREFIX + instance_name
316 e25625ab Jose A. Lopes
317 e25625ab Jose A. Lopes
318 22b7f6f8 Thomas Thrainer
class LUInstanceCreate(LogicalUnit):
319 22b7f6f8 Thomas Thrainer
  """Create an instance.
320 22b7f6f8 Thomas Thrainer

321 22b7f6f8 Thomas Thrainer
  """
322 22b7f6f8 Thomas Thrainer
  HPATH = "instance-add"
323 22b7f6f8 Thomas Thrainer
  HTYPE = constants.HTYPE_INSTANCE
324 22b7f6f8 Thomas Thrainer
  REQ_BGL = False
325 22b7f6f8 Thomas Thrainer
326 dab6ea3d Helga Velroyen
  def _CheckDiskTemplateValid(self):
327 dab6ea3d Helga Velroyen
    """Checks validity of disk template.
328 22b7f6f8 Thomas Thrainer

329 22b7f6f8 Thomas Thrainer
    """
330 22b7f6f8 Thomas Thrainer
    cluster = self.cfg.GetClusterInfo()
331 72080db1 Helga Velroyen
    if self.op.disk_template is None:
332 72080db1 Helga Velroyen
      # FIXME: It would be better to take the default disk template from the
333 72080db1 Helga Velroyen
      # ipolicy, but for the ipolicy we need the primary node, which we get from
334 72080db1 Helga Velroyen
      # the iallocator, which wants the disk template as input. To solve this
335 72080db1 Helga Velroyen
      # chicken-and-egg problem, it should be possible to specify just a node
336 72080db1 Helga Velroyen
      # group from the iallocator and take the ipolicy from that.
337 72080db1 Helga Velroyen
      self.op.disk_template = cluster.enabled_disk_templates[0]
338 1f7c8208 Helga Velroyen
    CheckDiskTemplateEnabled(cluster, self.op.disk_template)
339 22b7f6f8 Thomas Thrainer
340 dab6ea3d Helga Velroyen
  def _CheckDiskArguments(self):
341 dab6ea3d Helga Velroyen
    """Checks validity of disk-related arguments.
342 dab6ea3d Helga Velroyen

343 dab6ea3d Helga Velroyen
    """
344 dab6ea3d Helga Velroyen
    # check that disk's names are unique and valid
345 dab6ea3d Helga Velroyen
    utils.ValidateDeviceNames("disk", self.op.disks)
346 dab6ea3d Helga Velroyen
347 dab6ea3d Helga Velroyen
    self._CheckDiskTemplateValid()
348 dab6ea3d Helga Velroyen
349 22b7f6f8 Thomas Thrainer
    # check disks. parameter names and consistent adopt/no-adopt strategy
350 22b7f6f8 Thomas Thrainer
    has_adopt = has_no_adopt = False
351 22b7f6f8 Thomas Thrainer
    for disk in self.op.disks:
352 22b7f6f8 Thomas Thrainer
      if self.op.disk_template != constants.DT_EXT:
353 22b7f6f8 Thomas Thrainer
        utils.ForceDictType(disk, constants.IDISK_PARAMS_TYPES)
354 22b7f6f8 Thomas Thrainer
      if constants.IDISK_ADOPT in disk:
355 22b7f6f8 Thomas Thrainer
        has_adopt = True
356 22b7f6f8 Thomas Thrainer
      else:
357 22b7f6f8 Thomas Thrainer
        has_no_adopt = True
358 22b7f6f8 Thomas Thrainer
    if has_adopt and has_no_adopt:
359 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Either all disks are adopted or none is",
360 22b7f6f8 Thomas Thrainer
                                 errors.ECODE_INVAL)
361 22b7f6f8 Thomas Thrainer
    if has_adopt:
362 22b7f6f8 Thomas Thrainer
      if self.op.disk_template not in constants.DTS_MAY_ADOPT:
363 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Disk adoption is not supported for the"
364 22b7f6f8 Thomas Thrainer
                                   " '%s' disk template" %
365 22b7f6f8 Thomas Thrainer
                                   self.op.disk_template,
366 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
367 22b7f6f8 Thomas Thrainer
      if self.op.iallocator is not None:
368 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Disk adoption not allowed with an"
369 22b7f6f8 Thomas Thrainer
                                   " iallocator script", errors.ECODE_INVAL)
370 22b7f6f8 Thomas Thrainer
      if self.op.mode == constants.INSTANCE_IMPORT:
371 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Disk adoption not allowed for"
372 22b7f6f8 Thomas Thrainer
                                   " instance import", errors.ECODE_INVAL)
373 22b7f6f8 Thomas Thrainer
    else:
374 22b7f6f8 Thomas Thrainer
      if self.op.disk_template in constants.DTS_MUST_ADOPT:
375 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Disk template %s requires disk adoption,"
376 22b7f6f8 Thomas Thrainer
                                   " but no 'adopt' parameter given" %
377 22b7f6f8 Thomas Thrainer
                                   self.op.disk_template,
378 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
379 22b7f6f8 Thomas Thrainer
380 22b7f6f8 Thomas Thrainer
    self.adopt_disks = has_adopt
381 22b7f6f8 Thomas Thrainer
382 9f7d5fe4 Sebastian Gebhard
  def _CheckVLANArguments(self):
383 9f7d5fe4 Sebastian Gebhard
    """ Check validity of VLANs if given
384 9f7d5fe4 Sebastian Gebhard

385 9f7d5fe4 Sebastian Gebhard
    """
386 9f7d5fe4 Sebastian Gebhard
    for nic in self.op.nics:
387 5ce6fa9a Sebastian Gebhard
      vlan = nic.get(constants.INIC_VLAN, None)
388 5ce6fa9a Sebastian Gebhard
      if vlan:
389 9f7d5fe4 Sebastian Gebhard
        if vlan[0] == ".":
390 9f7d5fe4 Sebastian Gebhard
          # vlan starting with dot means single untagged vlan,
391 9f7d5fe4 Sebastian Gebhard
          # might be followed by trunk (:)
392 9f7d5fe4 Sebastian Gebhard
          if not vlan[1:].isdigit():
393 9f7d5fe4 Sebastian Gebhard
            vlanlist = vlan[1:].split(':')
394 9f7d5fe4 Sebastian Gebhard
            for vl in vlanlist:
395 9f7d5fe4 Sebastian Gebhard
              if not vl.isdigit():
396 9f7d5fe4 Sebastian Gebhard
                raise errors.OpPrereqError("Specified VLAN parameter is "
397 9f7d5fe4 Sebastian Gebhard
                                           "invalid : %s" % vlan,
398 9f7d5fe4 Sebastian Gebhard
                                             errors.ECODE_INVAL)
399 9f7d5fe4 Sebastian Gebhard
        elif vlan[0] == ":":
400 9f7d5fe4 Sebastian Gebhard
          # Trunk - tagged only
401 9f7d5fe4 Sebastian Gebhard
          vlanlist = vlan[1:].split(':')
402 9f7d5fe4 Sebastian Gebhard
          for vl in vlanlist:
403 9f7d5fe4 Sebastian Gebhard
            if not vl.isdigit():
404 9f7d5fe4 Sebastian Gebhard
              raise errors.OpPrereqError("Specified VLAN parameter is invalid"
405 9f7d5fe4 Sebastian Gebhard
                                           " : %s" % vlan, errors.ECODE_INVAL)
406 9f7d5fe4 Sebastian Gebhard
        elif vlan.isdigit():
407 9f7d5fe4 Sebastian Gebhard
          # This is the simplest case. No dots, only single digit
408 9f7d5fe4 Sebastian Gebhard
          # -> Create untagged access port, dot needs to be added
409 9f7d5fe4 Sebastian Gebhard
          nic[constants.INIC_VLAN] = "." + vlan
410 9f7d5fe4 Sebastian Gebhard
        else:
411 9f7d5fe4 Sebastian Gebhard
          raise errors.OpPrereqError("Specified VLAN parameter is invalid"
412 9f7d5fe4 Sebastian Gebhard
                                       " : %s" % vlan, errors.ECODE_INVAL)
413 9f7d5fe4 Sebastian Gebhard
414 dab6ea3d Helga Velroyen
  def CheckArguments(self):
415 dab6ea3d Helga Velroyen
    """Check arguments.
416 dab6ea3d Helga Velroyen

417 dab6ea3d Helga Velroyen
    """
418 dab6ea3d Helga Velroyen
    # do not require name_check to ease forward/backward compatibility
419 dab6ea3d Helga Velroyen
    # for tools
420 dab6ea3d Helga Velroyen
    if self.op.no_install and self.op.start:
421 dab6ea3d Helga Velroyen
      self.LogInfo("No-installation mode selected, disabling startup")
422 dab6ea3d Helga Velroyen
      self.op.start = False
423 dab6ea3d Helga Velroyen
    # validate/normalize the instance name
424 dab6ea3d Helga Velroyen
    self.op.instance_name = \
425 dab6ea3d Helga Velroyen
      netutils.Hostname.GetNormalizedName(self.op.instance_name)
426 dab6ea3d Helga Velroyen
427 dab6ea3d Helga Velroyen
    if self.op.ip_check and not self.op.name_check:
428 dab6ea3d Helga Velroyen
      # TODO: make the ip check more flexible and not depend on the name check
429 dab6ea3d Helga Velroyen
      raise errors.OpPrereqError("Cannot do IP address check without a name"
430 dab6ea3d Helga Velroyen
                                 " check", errors.ECODE_INVAL)
431 dab6ea3d Helga Velroyen
432 7a51281a Jose A. Lopes
    # add NIC for instance communication
433 81c222af Jose A. Lopes
    if self.op.instance_communication:
434 e25625ab Jose A. Lopes
      nic_name = _ComputeInstanceCommunicationNIC(self.op.instance_name)
435 81c222af Jose A. Lopes
436 81c222af Jose A. Lopes
      self.op.nics.append({constants.INIC_NAME: nic_name,
437 81c222af Jose A. Lopes
                           constants.INIC_MAC: constants.VALUE_GENERATE,
438 81c222af Jose A. Lopes
                           constants.INIC_IP: constants.NIC_IP_POOL,
439 9a94cee3 Jose A. Lopes
                           constants.INIC_NETWORK:
440 9a94cee3 Jose A. Lopes
                             self.cfg.GetInstanceCommunicationNetwork()})
441 81c222af Jose A. Lopes
442 dab6ea3d Helga Velroyen
    # check nics' parameter names
443 dab6ea3d Helga Velroyen
    for nic in self.op.nics:
444 dab6ea3d Helga Velroyen
      utils.ForceDictType(nic, constants.INIC_PARAMS_TYPES)
445 dab6ea3d Helga Velroyen
    # check that NIC's parameters names are unique and valid
446 dab6ea3d Helga Velroyen
    utils.ValidateDeviceNames("NIC", self.op.nics)
447 dab6ea3d Helga Velroyen
448 9f7d5fe4 Sebastian Gebhard
    self._CheckVLANArguments()
449 9f7d5fe4 Sebastian Gebhard
450 dab6ea3d Helga Velroyen
    self._CheckDiskArguments()
451 66222813 Thomas Thrainer
    assert self.op.disk_template is not None
452 dab6ea3d Helga Velroyen
453 22b7f6f8 Thomas Thrainer
    # instance name verification
454 22b7f6f8 Thomas Thrainer
    if self.op.name_check:
455 da4a52a3 Thomas Thrainer
      self.hostname = _CheckHostnameSane(self, self.op.instance_name)
456 da4a52a3 Thomas Thrainer
      self.op.instance_name = self.hostname.name
457 22b7f6f8 Thomas Thrainer
      # used in CheckPrereq for ip ping check
458 da4a52a3 Thomas Thrainer
      self.check_ip = self.hostname.ip
459 22b7f6f8 Thomas Thrainer
    else:
460 22b7f6f8 Thomas Thrainer
      self.check_ip = None
461 22b7f6f8 Thomas Thrainer
462 22b7f6f8 Thomas Thrainer
    # file storage checks
463 22b7f6f8 Thomas Thrainer
    if (self.op.file_driver and
464 22b7f6f8 Thomas Thrainer
        not self.op.file_driver in constants.FILE_DRIVER):
465 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Invalid file driver name '%s'" %
466 22b7f6f8 Thomas Thrainer
                                 self.op.file_driver, errors.ECODE_INVAL)
467 22b7f6f8 Thomas Thrainer
468 ff34fb97 Michele Tartara
    # set default file_driver if unset and required
469 ff34fb97 Michele Tartara
    if (not self.op.file_driver and
470 a09639d1 Santi Raffa
        self.op.disk_template in constants.DTS_FILEBASED):
471 ff34fb97 Michele Tartara
      self.op.file_driver = constants.FD_LOOP
472 ff34fb97 Michele Tartara
473 22b7f6f8 Thomas Thrainer
    ### Node/iallocator related checks
474 5eacbcae Thomas Thrainer
    CheckIAllocatorOrNode(self, "iallocator", "pnode")
475 22b7f6f8 Thomas Thrainer
476 22b7f6f8 Thomas Thrainer
    if self.op.pnode is not None:
477 22b7f6f8 Thomas Thrainer
      if self.op.disk_template in constants.DTS_INT_MIRROR:
478 22b7f6f8 Thomas Thrainer
        if self.op.snode is None:
479 22b7f6f8 Thomas Thrainer
          raise errors.OpPrereqError("The networked disk templates need"
480 22b7f6f8 Thomas Thrainer
                                     " a mirror node", errors.ECODE_INVAL)
481 22b7f6f8 Thomas Thrainer
      elif self.op.snode:
482 22b7f6f8 Thomas Thrainer
        self.LogWarning("Secondary node will be ignored on non-mirrored disk"
483 22b7f6f8 Thomas Thrainer
                        " template")
484 22b7f6f8 Thomas Thrainer
        self.op.snode = None
485 22b7f6f8 Thomas Thrainer
486 22b7f6f8 Thomas Thrainer
    _CheckOpportunisticLocking(self.op)
487 22b7f6f8 Thomas Thrainer
488 22b7f6f8 Thomas Thrainer
    if self.op.mode == constants.INSTANCE_IMPORT:
489 22b7f6f8 Thomas Thrainer
      # On import force_variant must be True, because if we forced it at
490 22b7f6f8 Thomas Thrainer
      # initial install, our only chance when importing it back is that it
491 22b7f6f8 Thomas Thrainer
      # works again!
492 22b7f6f8 Thomas Thrainer
      self.op.force_variant = True
493 22b7f6f8 Thomas Thrainer
494 22b7f6f8 Thomas Thrainer
      if self.op.no_install:
495 22b7f6f8 Thomas Thrainer
        self.LogInfo("No-installation mode has no effect during import")
496 22b7f6f8 Thomas Thrainer
497 1c4910f7 Jose A. Lopes
      if objects.GetOSImage(self.op.osparams):
498 1c4910f7 Jose A. Lopes
        self.LogInfo("OS image has no effect during import")
499 22b7f6f8 Thomas Thrainer
    elif self.op.mode == constants.INSTANCE_CREATE:
500 1c4910f7 Jose A. Lopes
      os_image = CheckOSImage(self.op)
501 1c4910f7 Jose A. Lopes
502 1c4910f7 Jose A. Lopes
      if self.op.os_type is None and os_image is None:
503 1c4910f7 Jose A. Lopes
        raise errors.OpPrereqError("No guest OS or OS image specified",
504 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
505 1c4910f7 Jose A. Lopes
506 1c4910f7 Jose A. Lopes
      if self.op.os_type is not None \
507 1c4910f7 Jose A. Lopes
            and self.op.os_type in self.cfg.GetClusterInfo().blacklisted_os:
508 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Guest OS '%s' is not allowed for"
509 22b7f6f8 Thomas Thrainer
                                   " installation" % self.op.os_type,
510 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_STATE)
511 22b7f6f8 Thomas Thrainer
    elif self.op.mode == constants.INSTANCE_REMOTE_IMPORT:
512 1c4910f7 Jose A. Lopes
      if objects.GetOSImage(self.op.osparams):
513 1c4910f7 Jose A. Lopes
        self.LogInfo("OS image has no effect during import")
514 1c4910f7 Jose A. Lopes
515 66222813 Thomas Thrainer
      self._cds = GetClusterDomainSecret()
516 66222813 Thomas Thrainer
517 22b7f6f8 Thomas Thrainer
      # Check handshake to ensure both clusters have the same domain secret
518 22b7f6f8 Thomas Thrainer
      src_handshake = self.op.source_handshake
519 22b7f6f8 Thomas Thrainer
      if not src_handshake:
520 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Missing source handshake",
521 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
522 22b7f6f8 Thomas Thrainer
523 22b7f6f8 Thomas Thrainer
      errmsg = masterd.instance.CheckRemoteExportHandshake(self._cds,
524 22b7f6f8 Thomas Thrainer
                                                           src_handshake)
525 22b7f6f8 Thomas Thrainer
      if errmsg:
526 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Invalid handshake: %s" % errmsg,
527 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
528 22b7f6f8 Thomas Thrainer
529 22b7f6f8 Thomas Thrainer
      # Load and check source CA
530 22b7f6f8 Thomas Thrainer
      self.source_x509_ca_pem = self.op.source_x509_ca
531 22b7f6f8 Thomas Thrainer
      if not self.source_x509_ca_pem:
532 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Missing source X509 CA",
533 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
534 22b7f6f8 Thomas Thrainer
535 22b7f6f8 Thomas Thrainer
      try:
536 22b7f6f8 Thomas Thrainer
        (cert, _) = utils.LoadSignedX509Certificate(self.source_x509_ca_pem,
537 22b7f6f8 Thomas Thrainer
                                                    self._cds)
538 22b7f6f8 Thomas Thrainer
      except OpenSSL.crypto.Error, err:
539 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Unable to load source X509 CA (%s)" %
540 22b7f6f8 Thomas Thrainer
                                   (err, ), errors.ECODE_INVAL)
541 22b7f6f8 Thomas Thrainer
542 22b7f6f8 Thomas Thrainer
      (errcode, msg) = utils.VerifyX509Certificate(cert, None, None)
543 22b7f6f8 Thomas Thrainer
      if errcode is not None:
544 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Invalid source X509 CA (%s)" % (msg, ),
545 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
546 22b7f6f8 Thomas Thrainer
547 22b7f6f8 Thomas Thrainer
      self.source_x509_ca = cert
548 22b7f6f8 Thomas Thrainer
549 22b7f6f8 Thomas Thrainer
      src_instance_name = self.op.source_instance_name
550 22b7f6f8 Thomas Thrainer
      if not src_instance_name:
551 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Missing source instance name",
552 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
553 22b7f6f8 Thomas Thrainer
554 22b7f6f8 Thomas Thrainer
      self.source_instance_name = \
555 22b7f6f8 Thomas Thrainer
        netutils.GetHostname(name=src_instance_name).name
556 22b7f6f8 Thomas Thrainer
557 22b7f6f8 Thomas Thrainer
    else:
558 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Invalid instance creation mode %r" %
559 22b7f6f8 Thomas Thrainer
                                 self.op.mode, errors.ECODE_INVAL)
560 22b7f6f8 Thomas Thrainer
561 22b7f6f8 Thomas Thrainer
  def ExpandNames(self):
562 22b7f6f8 Thomas Thrainer
    """ExpandNames for CreateInstance.
563 22b7f6f8 Thomas Thrainer

564 22b7f6f8 Thomas Thrainer
    Figure out the right locks for instance creation.
565 22b7f6f8 Thomas Thrainer

566 22b7f6f8 Thomas Thrainer
    """
567 22b7f6f8 Thomas Thrainer
    self.needed_locks = {}
568 22b7f6f8 Thomas Thrainer
569 22b7f6f8 Thomas Thrainer
    # this is just a preventive check, but someone might still add this
570 22b7f6f8 Thomas Thrainer
    # instance in the meantime, and creation will fail at lock-add time
571 da4a52a3 Thomas Thrainer
    if self.op.instance_name in\
572 da4a52a3 Thomas Thrainer
      [inst.name for inst in self.cfg.GetAllInstancesInfo().values()]:
573 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
574 d0d7d7cf Thomas Thrainer
                                 self.op.instance_name, errors.ECODE_EXISTS)
575 22b7f6f8 Thomas Thrainer
576 d0d7d7cf Thomas Thrainer
    self.add_locks[locking.LEVEL_INSTANCE] = self.op.instance_name
577 22b7f6f8 Thomas Thrainer
578 22b7f6f8 Thomas Thrainer
    if self.op.iallocator:
579 22b7f6f8 Thomas Thrainer
      # TODO: Find a solution to not lock all nodes in the cluster, e.g. by
580 22b7f6f8 Thomas Thrainer
      # specifying a group on instance creation and then selecting nodes from
581 22b7f6f8 Thomas Thrainer
      # that group
582 22b7f6f8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
583 22b7f6f8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE_ALLOC] = locking.ALL_SET
584 22b7f6f8 Thomas Thrainer
585 22b7f6f8 Thomas Thrainer
      if self.op.opportunistic_locking:
586 22b7f6f8 Thomas Thrainer
        self.opportunistic_locks[locking.LEVEL_NODE] = True
587 22b7f6f8 Thomas Thrainer
    else:
588 1c3231aa Thomas Thrainer
      (self.op.pnode_uuid, self.op.pnode) = \
589 1c3231aa Thomas Thrainer
        ExpandNodeUuidAndName(self.cfg, self.op.pnode_uuid, self.op.pnode)
590 1c3231aa Thomas Thrainer
      nodelist = [self.op.pnode_uuid]
591 22b7f6f8 Thomas Thrainer
      if self.op.snode is not None:
592 1c3231aa Thomas Thrainer
        (self.op.snode_uuid, self.op.snode) = \
593 1c3231aa Thomas Thrainer
          ExpandNodeUuidAndName(self.cfg, self.op.snode_uuid, self.op.snode)
594 1c3231aa Thomas Thrainer
        nodelist.append(self.op.snode_uuid)
595 22b7f6f8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE] = nodelist
596 22b7f6f8 Thomas Thrainer
597 22b7f6f8 Thomas Thrainer
    # in case of import lock the source node too
598 22b7f6f8 Thomas Thrainer
    if self.op.mode == constants.INSTANCE_IMPORT:
599 22b7f6f8 Thomas Thrainer
      src_node = self.op.src_node
600 22b7f6f8 Thomas Thrainer
      src_path = self.op.src_path
601 22b7f6f8 Thomas Thrainer
602 22b7f6f8 Thomas Thrainer
      if src_path is None:
603 22b7f6f8 Thomas Thrainer
        self.op.src_path = src_path = self.op.instance_name
604 22b7f6f8 Thomas Thrainer
605 22b7f6f8 Thomas Thrainer
      if src_node is None:
606 22b7f6f8 Thomas Thrainer
        self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
607 22b7f6f8 Thomas Thrainer
        self.needed_locks[locking.LEVEL_NODE_ALLOC] = locking.ALL_SET
608 22b7f6f8 Thomas Thrainer
        self.op.src_node = None
609 22b7f6f8 Thomas Thrainer
        if os.path.isabs(src_path):
610 22b7f6f8 Thomas Thrainer
          raise errors.OpPrereqError("Importing an instance from a path"
611 22b7f6f8 Thomas Thrainer
                                     " requires a source node option",
612 22b7f6f8 Thomas Thrainer
                                     errors.ECODE_INVAL)
613 22b7f6f8 Thomas Thrainer
      else:
614 1c3231aa Thomas Thrainer
        (self.op.src_node_uuid, self.op.src_node) = (_, src_node) = \
615 1c3231aa Thomas Thrainer
          ExpandNodeUuidAndName(self.cfg, self.op.src_node_uuid, src_node)
616 22b7f6f8 Thomas Thrainer
        if self.needed_locks[locking.LEVEL_NODE] is not locking.ALL_SET:
617 1c3231aa Thomas Thrainer
          self.needed_locks[locking.LEVEL_NODE].append(self.op.src_node_uuid)
618 22b7f6f8 Thomas Thrainer
        if not os.path.isabs(src_path):
619 a61a0813 Thomas Thrainer
          self.op.src_path = \
620 22b7f6f8 Thomas Thrainer
            utils.PathJoin(pathutils.EXPORT_DIR, src_path)
621 22b7f6f8 Thomas Thrainer
622 22b7f6f8 Thomas Thrainer
    self.needed_locks[locking.LEVEL_NODE_RES] = \
623 5eacbcae Thomas Thrainer
      CopyLockList(self.needed_locks[locking.LEVEL_NODE])
624 22b7f6f8 Thomas Thrainer
625 8b9887c5 Petr Pudlak
    # Optimistically acquire shared group locks (we're reading the
626 8b9887c5 Petr Pudlak
    # configuration).  We can't just call GetInstanceNodeGroups, because the
627 8b9887c5 Petr Pudlak
    # instance doesn't exist yet. Therefore we lock all node groups of all
628 8b9887c5 Petr Pudlak
    # nodes we have.
629 8b9887c5 Petr Pudlak
    if self.needed_locks[locking.LEVEL_NODE] == locking.ALL_SET:
630 8b9887c5 Petr Pudlak
      # In the case we lock all nodes for opportunistic allocation, we have no
631 8b9887c5 Petr Pudlak
      # choice than to lock all groups, because they're allocated before nodes.
632 8b9887c5 Petr Pudlak
      # This is sad, but true. At least we release all those we don't need in
633 8b9887c5 Petr Pudlak
      # CheckPrereq later.
634 8b9887c5 Petr Pudlak
      self.needed_locks[locking.LEVEL_NODEGROUP] = locking.ALL_SET
635 8b9887c5 Petr Pudlak
    else:
636 8b9887c5 Petr Pudlak
      self.needed_locks[locking.LEVEL_NODEGROUP] = \
637 8b9887c5 Petr Pudlak
        list(self.cfg.GetNodeGroupsFromNodes(
638 8b9887c5 Petr Pudlak
          self.needed_locks[locking.LEVEL_NODE]))
639 8b9887c5 Petr Pudlak
    self.share_locks[locking.LEVEL_NODEGROUP] = 1
640 8b9887c5 Petr Pudlak
641 4289f617 Thomas Thrainer
  def DeclareLocks(self, level):
642 4289f617 Thomas Thrainer
    if level == locking.LEVEL_NODE_RES and \
643 4289f617 Thomas Thrainer
      self.opportunistic_locks[locking.LEVEL_NODE]:
644 4289f617 Thomas Thrainer
      # Even when using opportunistic locking, we require the same set of
645 4289f617 Thomas Thrainer
      # NODE_RES locks as we got NODE locks
646 4289f617 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE_RES] = \
647 4289f617 Thomas Thrainer
        self.owned_locks(locking.LEVEL_NODE)
648 4289f617 Thomas Thrainer
649 22b7f6f8 Thomas Thrainer
  def _RunAllocator(self):
650 22b7f6f8 Thomas Thrainer
    """Run the allocator based on input opcode.
651 22b7f6f8 Thomas Thrainer

652 22b7f6f8 Thomas Thrainer
    """
653 22b7f6f8 Thomas Thrainer
    if self.op.opportunistic_locking:
654 22b7f6f8 Thomas Thrainer
      # Only consider nodes for which a lock is held
655 4665b94f Thomas Thrainer
      node_name_whitelist = self.cfg.GetNodeNames(
656 4665b94f Thomas Thrainer
        self.owned_locks(locking.LEVEL_NODE))
657 22b7f6f8 Thomas Thrainer
    else:
658 4665b94f Thomas Thrainer
      node_name_whitelist = None
659 22b7f6f8 Thomas Thrainer
660 22b7f6f8 Thomas Thrainer
    req = _CreateInstanceAllocRequest(self.op, self.disks,
661 22b7f6f8 Thomas Thrainer
                                      self.nics, self.be_full,
662 4665b94f Thomas Thrainer
                                      node_name_whitelist)
663 22b7f6f8 Thomas Thrainer
    ial = iallocator.IAllocator(self.cfg, self.rpc, req)
664 22b7f6f8 Thomas Thrainer
665 22b7f6f8 Thomas Thrainer
    ial.Run(self.op.iallocator)
666 22b7f6f8 Thomas Thrainer
667 22b7f6f8 Thomas Thrainer
    if not ial.success:
668 22b7f6f8 Thomas Thrainer
      # When opportunistic locks are used only a temporary failure is generated
669 22b7f6f8 Thomas Thrainer
      if self.op.opportunistic_locking:
670 22b7f6f8 Thomas Thrainer
        ecode = errors.ECODE_TEMP_NORES
671 22b7f6f8 Thomas Thrainer
      else:
672 22b7f6f8 Thomas Thrainer
        ecode = errors.ECODE_NORES
673 22b7f6f8 Thomas Thrainer
674 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Can't compute nodes using"
675 22b7f6f8 Thomas Thrainer
                                 " iallocator '%s': %s" %
676 22b7f6f8 Thomas Thrainer
                                 (self.op.iallocator, ial.info),
677 22b7f6f8 Thomas Thrainer
                                 ecode)
678 22b7f6f8 Thomas Thrainer
679 1c3231aa Thomas Thrainer
    (self.op.pnode_uuid, self.op.pnode) = \
680 1c3231aa Thomas Thrainer
      ExpandNodeUuidAndName(self.cfg, None, ial.result[0])
681 22b7f6f8 Thomas Thrainer
    self.LogInfo("Selected nodes for instance %s via iallocator %s: %s",
682 22b7f6f8 Thomas Thrainer
                 self.op.instance_name, self.op.iallocator,
683 22b7f6f8 Thomas Thrainer
                 utils.CommaJoin(ial.result))
684 22b7f6f8 Thomas Thrainer
685 22b7f6f8 Thomas Thrainer
    assert req.RequiredNodes() in (1, 2), "Wrong node count from iallocator"
686 22b7f6f8 Thomas Thrainer
687 22b7f6f8 Thomas Thrainer
    if req.RequiredNodes() == 2:
688 1c3231aa Thomas Thrainer
      (self.op.snode_uuid, self.op.snode) = \
689 1c3231aa Thomas Thrainer
        ExpandNodeUuidAndName(self.cfg, None, ial.result[1])
690 22b7f6f8 Thomas Thrainer
691 22b7f6f8 Thomas Thrainer
  def BuildHooksEnv(self):
692 22b7f6f8 Thomas Thrainer
    """Build hooks env.
693 22b7f6f8 Thomas Thrainer

694 22b7f6f8 Thomas Thrainer
    This runs on master, primary and secondary nodes of the instance.
695 22b7f6f8 Thomas Thrainer

696 22b7f6f8 Thomas Thrainer
    """
697 22b7f6f8 Thomas Thrainer
    env = {
698 22b7f6f8 Thomas Thrainer
      "ADD_MODE": self.op.mode,
699 22b7f6f8 Thomas Thrainer
      }
700 22b7f6f8 Thomas Thrainer
    if self.op.mode == constants.INSTANCE_IMPORT:
701 22b7f6f8 Thomas Thrainer
      env["SRC_NODE"] = self.op.src_node
702 22b7f6f8 Thomas Thrainer
      env["SRC_PATH"] = self.op.src_path
703 22b7f6f8 Thomas Thrainer
      env["SRC_IMAGES"] = self.src_images
704 22b7f6f8 Thomas Thrainer
705 5eacbcae Thomas Thrainer
    env.update(BuildInstanceHookEnv(
706 22b7f6f8 Thomas Thrainer
      name=self.op.instance_name,
707 1c3231aa Thomas Thrainer
      primary_node_name=self.op.pnode,
708 1c3231aa Thomas Thrainer
      secondary_node_names=self.cfg.GetNodeNames(self.secondaries),
709 22b7f6f8 Thomas Thrainer
      status=self.op.start,
710 22b7f6f8 Thomas Thrainer
      os_type=self.op.os_type,
711 22b7f6f8 Thomas Thrainer
      minmem=self.be_full[constants.BE_MINMEM],
712 22b7f6f8 Thomas Thrainer
      maxmem=self.be_full[constants.BE_MAXMEM],
713 22b7f6f8 Thomas Thrainer
      vcpus=self.be_full[constants.BE_VCPUS],
714 5eacbcae Thomas Thrainer
      nics=NICListToTuple(self, self.nics),
715 22b7f6f8 Thomas Thrainer
      disk_template=self.op.disk_template,
716 8a348b15 Christos Stavrakakis
      disks=[(d[constants.IDISK_NAME], d.get("uuid", ""),
717 8a348b15 Christos Stavrakakis
              d[constants.IDISK_SIZE], d[constants.IDISK_MODE])
718 8a348b15 Christos Stavrakakis
             for d in self.disks],
719 22b7f6f8 Thomas Thrainer
      bep=self.be_full,
720 22b7f6f8 Thomas Thrainer
      hvp=self.hv_full,
721 22b7f6f8 Thomas Thrainer
      hypervisor_name=self.op.hypervisor,
722 22b7f6f8 Thomas Thrainer
      tags=self.op.tags,
723 22b7f6f8 Thomas Thrainer
      ))
724 22b7f6f8 Thomas Thrainer
725 22b7f6f8 Thomas Thrainer
    return env
726 22b7f6f8 Thomas Thrainer
727 22b7f6f8 Thomas Thrainer
  def BuildHooksNodes(self):
728 22b7f6f8 Thomas Thrainer
    """Build hooks nodes.
729 22b7f6f8 Thomas Thrainer

730 22b7f6f8 Thomas Thrainer
    """
731 1c3231aa Thomas Thrainer
    nl = [self.cfg.GetMasterNode(), self.op.pnode_uuid] + self.secondaries
732 22b7f6f8 Thomas Thrainer
    return nl, nl
733 22b7f6f8 Thomas Thrainer
734 22b7f6f8 Thomas Thrainer
  def _ReadExportInfo(self):
735 22b7f6f8 Thomas Thrainer
    """Reads the export information from disk.
736 22b7f6f8 Thomas Thrainer

737 22b7f6f8 Thomas Thrainer
    It will override the opcode source node and path with the actual
738 22b7f6f8 Thomas Thrainer
    information, if these two were not specified before.
739 22b7f6f8 Thomas Thrainer

740 22b7f6f8 Thomas Thrainer
    @return: the export information
741 22b7f6f8 Thomas Thrainer

742 22b7f6f8 Thomas Thrainer
    """
743 22b7f6f8 Thomas Thrainer
    assert self.op.mode == constants.INSTANCE_IMPORT
744 22b7f6f8 Thomas Thrainer
745 d0d7d7cf Thomas Thrainer
    if self.op.src_node_uuid is None:
746 22b7f6f8 Thomas Thrainer
      locked_nodes = self.owned_locks(locking.LEVEL_NODE)
747 22b7f6f8 Thomas Thrainer
      exp_list = self.rpc.call_export_list(locked_nodes)
748 22b7f6f8 Thomas Thrainer
      found = False
749 a61a0813 Thomas Thrainer
      for node_uuid in exp_list:
750 a61a0813 Thomas Thrainer
        if exp_list[node_uuid].fail_msg:
751 22b7f6f8 Thomas Thrainer
          continue
752 a61a0813 Thomas Thrainer
        if self.op.src_path in exp_list[node_uuid].payload:
753 22b7f6f8 Thomas Thrainer
          found = True
754 a61a0813 Thomas Thrainer
          self.op.src_node = self.cfg.GetNodeInfo(node_uuid).name
755 a61a0813 Thomas Thrainer
          self.op.src_node_uuid = node_uuid
756 d0d7d7cf Thomas Thrainer
          self.op.src_path = utils.PathJoin(pathutils.EXPORT_DIR,
757 d0d7d7cf Thomas Thrainer
                                            self.op.src_path)
758 22b7f6f8 Thomas Thrainer
          break
759 22b7f6f8 Thomas Thrainer
      if not found:
760 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("No export found for relative path %s" %
761 d0d7d7cf Thomas Thrainer
                                   self.op.src_path, errors.ECODE_INVAL)
762 22b7f6f8 Thomas Thrainer
763 d0d7d7cf Thomas Thrainer
    CheckNodeOnline(self, self.op.src_node_uuid)
764 d0d7d7cf Thomas Thrainer
    result = self.rpc.call_export_info(self.op.src_node_uuid, self.op.src_path)
765 d0d7d7cf Thomas Thrainer
    result.Raise("No export or invalid export found in dir %s" %
766 d0d7d7cf Thomas Thrainer
                 self.op.src_path)
767 22b7f6f8 Thomas Thrainer
768 22b7f6f8 Thomas Thrainer
    export_info = objects.SerializableConfigParser.Loads(str(result.payload))
769 22b7f6f8 Thomas Thrainer
    if not export_info.has_section(constants.INISECT_EXP):
770 22b7f6f8 Thomas Thrainer
      raise errors.ProgrammerError("Corrupted export config",
771 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_ENVIRON)
772 22b7f6f8 Thomas Thrainer
773 22b7f6f8 Thomas Thrainer
    ei_version = export_info.get(constants.INISECT_EXP, "version")
774 1c3231aa Thomas Thrainer
    if int(ei_version) != constants.EXPORT_VERSION:
775 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Wrong export version %s (wanted %d)" %
776 22b7f6f8 Thomas Thrainer
                                 (ei_version, constants.EXPORT_VERSION),
777 22b7f6f8 Thomas Thrainer
                                 errors.ECODE_ENVIRON)
778 22b7f6f8 Thomas Thrainer
    return export_info
779 22b7f6f8 Thomas Thrainer
780 22b7f6f8 Thomas Thrainer
  def _ReadExportParams(self, einfo):
781 22b7f6f8 Thomas Thrainer
    """Use export parameters as defaults.
782 22b7f6f8 Thomas Thrainer

783 22b7f6f8 Thomas Thrainer
    In case the opcode doesn't specify (as in override) some instance
784 22b7f6f8 Thomas Thrainer
    parameters, then try to use them from the export information, if
785 22b7f6f8 Thomas Thrainer
    that declares them.
786 22b7f6f8 Thomas Thrainer

787 22b7f6f8 Thomas Thrainer
    """
788 22b7f6f8 Thomas Thrainer
    self.op.os_type = einfo.get(constants.INISECT_EXP, "os")
789 22b7f6f8 Thomas Thrainer
790 22b7f6f8 Thomas Thrainer
    if not self.op.disks:
791 22b7f6f8 Thomas Thrainer
      disks = []
792 22b7f6f8 Thomas Thrainer
      # TODO: import the disk iv_name too
793 22b7f6f8 Thomas Thrainer
      for idx in range(constants.MAX_DISKS):
794 22b7f6f8 Thomas Thrainer
        if einfo.has_option(constants.INISECT_INS, "disk%d_size" % idx):
795 22b7f6f8 Thomas Thrainer
          disk_sz = einfo.getint(constants.INISECT_INS, "disk%d_size" % idx)
796 0f68f7fa Dimitris Aragiorgis
          disk_name = einfo.get(constants.INISECT_INS, "disk%d_name" % idx)
797 0f68f7fa Dimitris Aragiorgis
          disk = {
798 0f68f7fa Dimitris Aragiorgis
            constants.IDISK_SIZE: disk_sz,
799 0f68f7fa Dimitris Aragiorgis
            constants.IDISK_NAME: disk_name
800 0f68f7fa Dimitris Aragiorgis
            }
801 0f68f7fa Dimitris Aragiorgis
          disks.append(disk)
802 22b7f6f8 Thomas Thrainer
      self.op.disks = disks
803 22b7f6f8 Thomas Thrainer
      if not disks and self.op.disk_template != constants.DT_DISKLESS:
804 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("No disk info specified and the export"
805 22b7f6f8 Thomas Thrainer
                                   " is missing the disk information",
806 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
807 22b7f6f8 Thomas Thrainer
808 22b7f6f8 Thomas Thrainer
    if not self.op.nics:
809 22b7f6f8 Thomas Thrainer
      nics = []
810 22b7f6f8 Thomas Thrainer
      for idx in range(constants.MAX_NICS):
811 22b7f6f8 Thomas Thrainer
        if einfo.has_option(constants.INISECT_INS, "nic%d_mac" % idx):
812 22b7f6f8 Thomas Thrainer
          ndict = {}
813 0f68f7fa Dimitris Aragiorgis
          for name in [constants.INIC_IP,
814 0f68f7fa Dimitris Aragiorgis
                       constants.INIC_MAC, constants.INIC_NAME]:
815 a61a0813 Thomas Thrainer
            nic_param_name = "nic%d_%s" % (idx, name)
816 a61a0813 Thomas Thrainer
            if einfo.has_option(constants.INISECT_INS, nic_param_name):
817 fd5578ee Klaus Aehlig
              v = einfo.get(constants.INISECT_INS, "nic%d_%s" % (idx, name))
818 fd5578ee Klaus Aehlig
              ndict[name] = v
819 0973f9ed Dimitris Aragiorgis
          network = einfo.get(constants.INISECT_INS,
820 0973f9ed Dimitris Aragiorgis
                              "nic%d_%s" % (idx, constants.INIC_NETWORK))
821 0973f9ed Dimitris Aragiorgis
          # in case network is given link and mode are inherited
822 0973f9ed Dimitris Aragiorgis
          # from nodegroup's netparams and thus should not be passed here
823 0973f9ed Dimitris Aragiorgis
          if network:
824 0973f9ed Dimitris Aragiorgis
            ndict[constants.INIC_NETWORK] = network
825 0973f9ed Dimitris Aragiorgis
          else:
826 0973f9ed Dimitris Aragiorgis
            for name in list(constants.NICS_PARAMETERS):
827 0973f9ed Dimitris Aragiorgis
              v = einfo.get(constants.INISECT_INS, "nic%d_%s" % (idx, name))
828 a61a0813 Thomas Thrainer
              ndict[name] = v
829 22b7f6f8 Thomas Thrainer
          nics.append(ndict)
830 22b7f6f8 Thomas Thrainer
        else:
831 22b7f6f8 Thomas Thrainer
          break
832 22b7f6f8 Thomas Thrainer
      self.op.nics = nics
833 22b7f6f8 Thomas Thrainer
834 22b7f6f8 Thomas Thrainer
    if not self.op.tags and einfo.has_option(constants.INISECT_INS, "tags"):
835 22b7f6f8 Thomas Thrainer
      self.op.tags = einfo.get(constants.INISECT_INS, "tags").split()
836 22b7f6f8 Thomas Thrainer
837 22b7f6f8 Thomas Thrainer
    if (self.op.hypervisor is None and
838 22b7f6f8 Thomas Thrainer
        einfo.has_option(constants.INISECT_INS, "hypervisor")):
839 22b7f6f8 Thomas Thrainer
      self.op.hypervisor = einfo.get(constants.INISECT_INS, "hypervisor")
840 22b7f6f8 Thomas Thrainer
841 22b7f6f8 Thomas Thrainer
    if einfo.has_section(constants.INISECT_HYP):
842 22b7f6f8 Thomas Thrainer
      # use the export parameters but do not override the ones
843 22b7f6f8 Thomas Thrainer
      # specified by the user
844 22b7f6f8 Thomas Thrainer
      for name, value in einfo.items(constants.INISECT_HYP):
845 22b7f6f8 Thomas Thrainer
        if name not in self.op.hvparams:
846 22b7f6f8 Thomas Thrainer
          self.op.hvparams[name] = value
847 22b7f6f8 Thomas Thrainer
848 22b7f6f8 Thomas Thrainer
    if einfo.has_section(constants.INISECT_BEP):
849 22b7f6f8 Thomas Thrainer
      # use the parameters, without overriding
850 22b7f6f8 Thomas Thrainer
      for name, value in einfo.items(constants.INISECT_BEP):
851 22b7f6f8 Thomas Thrainer
        if name not in self.op.beparams:
852 22b7f6f8 Thomas Thrainer
          self.op.beparams[name] = value
853 22b7f6f8 Thomas Thrainer
        # Compatibility for the old "memory" be param
854 22b7f6f8 Thomas Thrainer
        if name == constants.BE_MEMORY:
855 22b7f6f8 Thomas Thrainer
          if constants.BE_MAXMEM not in self.op.beparams:
856 22b7f6f8 Thomas Thrainer
            self.op.beparams[constants.BE_MAXMEM] = value
857 22b7f6f8 Thomas Thrainer
          if constants.BE_MINMEM not in self.op.beparams:
858 22b7f6f8 Thomas Thrainer
            self.op.beparams[constants.BE_MINMEM] = value
859 22b7f6f8 Thomas Thrainer
    else:
860 22b7f6f8 Thomas Thrainer
      # try to read the parameters old style, from the main section
861 22b7f6f8 Thomas Thrainer
      for name in constants.BES_PARAMETERS:
862 22b7f6f8 Thomas Thrainer
        if (name not in self.op.beparams and
863 22b7f6f8 Thomas Thrainer
            einfo.has_option(constants.INISECT_INS, name)):
864 22b7f6f8 Thomas Thrainer
          self.op.beparams[name] = einfo.get(constants.INISECT_INS, name)
865 22b7f6f8 Thomas Thrainer
866 22b7f6f8 Thomas Thrainer
    if einfo.has_section(constants.INISECT_OSP):
867 22b7f6f8 Thomas Thrainer
      # use the parameters, without overriding
868 22b7f6f8 Thomas Thrainer
      for name, value in einfo.items(constants.INISECT_OSP):
869 22b7f6f8 Thomas Thrainer
        if name not in self.op.osparams:
870 22b7f6f8 Thomas Thrainer
          self.op.osparams[name] = value
871 22b7f6f8 Thomas Thrainer
872 6bce7ba2 Santi Raffa
    if einfo.has_section(constants.INISECT_OSP_PRIVATE):
873 6bce7ba2 Santi Raffa
      # use the parameters, without overriding
874 6bce7ba2 Santi Raffa
      for name, value in einfo.items(constants.INISECT_OSP_PRIVATE):
875 6bce7ba2 Santi Raffa
        if name not in self.op.osparams_private:
876 6bce7ba2 Santi Raffa
          self.op.osparams_private[name] = serializer.Private(value, descr=name)
877 6bce7ba2 Santi Raffa
878 22b7f6f8 Thomas Thrainer
  def _RevertToDefaults(self, cluster):
879 22b7f6f8 Thomas Thrainer
    """Revert the instance parameters to the default values.
880 22b7f6f8 Thomas Thrainer

881 22b7f6f8 Thomas Thrainer
    """
882 22b7f6f8 Thomas Thrainer
    # hvparams
883 22b7f6f8 Thomas Thrainer
    hv_defs = cluster.SimpleFillHV(self.op.hypervisor, self.op.os_type, {})
884 22b7f6f8 Thomas Thrainer
    for name in self.op.hvparams.keys():
885 22b7f6f8 Thomas Thrainer
      if name in hv_defs and hv_defs[name] == self.op.hvparams[name]:
886 22b7f6f8 Thomas Thrainer
        del self.op.hvparams[name]
887 22b7f6f8 Thomas Thrainer
    # beparams
888 22b7f6f8 Thomas Thrainer
    be_defs = cluster.SimpleFillBE({})
889 22b7f6f8 Thomas Thrainer
    for name in self.op.beparams.keys():
890 22b7f6f8 Thomas Thrainer
      if name in be_defs and be_defs[name] == self.op.beparams[name]:
891 22b7f6f8 Thomas Thrainer
        del self.op.beparams[name]
892 22b7f6f8 Thomas Thrainer
    # nic params
893 22b7f6f8 Thomas Thrainer
    nic_defs = cluster.SimpleFillNIC({})
894 22b7f6f8 Thomas Thrainer
    for nic in self.op.nics:
895 22b7f6f8 Thomas Thrainer
      for name in constants.NICS_PARAMETERS:
896 22b7f6f8 Thomas Thrainer
        if name in nic and name in nic_defs and nic[name] == nic_defs[name]:
897 22b7f6f8 Thomas Thrainer
          del nic[name]
898 22b7f6f8 Thomas Thrainer
    # osparams
899 22b7f6f8 Thomas Thrainer
    os_defs = cluster.SimpleFillOS(self.op.os_type, {})
900 22b7f6f8 Thomas Thrainer
    for name in self.op.osparams.keys():
901 22b7f6f8 Thomas Thrainer
      if name in os_defs and os_defs[name] == self.op.osparams[name]:
902 22b7f6f8 Thomas Thrainer
        del self.op.osparams[name]
903 22b7f6f8 Thomas Thrainer
904 6bce7ba2 Santi Raffa
    os_defs_ = cluster.SimpleFillOS(self.op.os_type, {},
905 6bce7ba2 Santi Raffa
                                    os_params_private={})
906 6bce7ba2 Santi Raffa
    for name in self.op.osparams_private.keys():
907 6bce7ba2 Santi Raffa
      if name in os_defs_ and os_defs_[name] == self.op.osparams_private[name]:
908 6bce7ba2 Santi Raffa
        del self.op.osparams_private[name]
909 6bce7ba2 Santi Raffa
910 22b7f6f8 Thomas Thrainer
  def _CalculateFileStorageDir(self):
911 22b7f6f8 Thomas Thrainer
    """Calculate final instance file storage dir.
912 22b7f6f8 Thomas Thrainer

913 22b7f6f8 Thomas Thrainer
    """
914 22b7f6f8 Thomas Thrainer
    # file storage dir calculation/check
915 22b7f6f8 Thomas Thrainer
    self.instance_file_storage_dir = None
916 22b7f6f8 Thomas Thrainer
    if self.op.disk_template in constants.DTS_FILEBASED:
917 22b7f6f8 Thomas Thrainer
      # build the full file storage dir path
918 22b7f6f8 Thomas Thrainer
      joinargs = []
919 22b7f6f8 Thomas Thrainer
920 ac156ecd Santi Raffa
      cfg_storage = None
921 ac156ecd Santi Raffa
      if self.op.disk_template == constants.DT_FILE:
922 ac156ecd Santi Raffa
        cfg_storage = self.cfg.GetFileStorageDir()
923 ac156ecd Santi Raffa
      elif self.op.disk_template == constants.DT_SHARED_FILE:
924 ac156ecd Santi Raffa
        cfg_storage = self.cfg.GetSharedFileStorageDir()
925 ac156ecd Santi Raffa
      elif self.op.disk_template == constants.DT_GLUSTER:
926 ac156ecd Santi Raffa
        cfg_storage = self.cfg.GetGlusterStorageDir()
927 ac156ecd Santi Raffa
928 ac156ecd Santi Raffa
      if not cfg_storage:
929 ac156ecd Santi Raffa
        raise errors.OpPrereqError(
930 ac156ecd Santi Raffa
          "Cluster file storage dir for {tpl} storage type not defined".format(
931 ac156ecd Santi Raffa
            tpl=repr(self.op.disk_template)
932 ac156ecd Santi Raffa
          ),
933 ac156ecd Santi Raffa
          errors.ECODE_STATE
934 ac156ecd Santi Raffa
      )
935 ac156ecd Santi Raffa
936 ac156ecd Santi Raffa
      joinargs.append(cfg_storage)
937 22b7f6f8 Thomas Thrainer
938 22b7f6f8 Thomas Thrainer
      if self.op.file_storage_dir is not None:
939 22b7f6f8 Thomas Thrainer
        joinargs.append(self.op.file_storage_dir)
940 22b7f6f8 Thomas Thrainer
941 ac156ecd Santi Raffa
      if self.op.disk_template != constants.DT_GLUSTER:
942 ac156ecd Santi Raffa
        joinargs.append(self.op.instance_name)
943 22b7f6f8 Thomas Thrainer
944 ac156ecd Santi Raffa
      if len(joinargs) > 1:
945 ac156ecd Santi Raffa
        # pylint: disable=W0142
946 ac156ecd Santi Raffa
        self.instance_file_storage_dir = utils.PathJoin(*joinargs)
947 ac156ecd Santi Raffa
      else:
948 ac156ecd Santi Raffa
        self.instance_file_storage_dir = joinargs[0]
949 22b7f6f8 Thomas Thrainer
950 22b7f6f8 Thomas Thrainer
  def CheckPrereq(self): # pylint: disable=R0914
951 22b7f6f8 Thomas Thrainer
    """Check prerequisites.
952 22b7f6f8 Thomas Thrainer

953 22b7f6f8 Thomas Thrainer
    """
954 8b9887c5 Petr Pudlak
    # Check that the optimistically acquired groups are correct wrt the
955 8b9887c5 Petr Pudlak
    # acquired nodes
956 8b9887c5 Petr Pudlak
    owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
957 8b9887c5 Petr Pudlak
    owned_nodes = frozenset(self.owned_locks(locking.LEVEL_NODE))
958 8b9887c5 Petr Pudlak
    cur_groups = list(self.cfg.GetNodeGroupsFromNodes(owned_nodes))
959 8b9887c5 Petr Pudlak
    if not owned_groups.issuperset(cur_groups):
960 8b9887c5 Petr Pudlak
      raise errors.OpPrereqError("New instance %s's node groups changed since"
961 8b9887c5 Petr Pudlak
                                 " locks were acquired, current groups are"
962 8b9887c5 Petr Pudlak
                                 " are '%s', owning groups '%s'; retry the"
963 8b9887c5 Petr Pudlak
                                 " operation" %
964 8b9887c5 Petr Pudlak
                                 (self.op.instance_name,
965 8b9887c5 Petr Pudlak
                                  utils.CommaJoin(cur_groups),
966 8b9887c5 Petr Pudlak
                                  utils.CommaJoin(owned_groups)),
967 8b9887c5 Petr Pudlak
                                 errors.ECODE_STATE)
968 8b9887c5 Petr Pudlak
969 22b7f6f8 Thomas Thrainer
    self._CalculateFileStorageDir()
970 22b7f6f8 Thomas Thrainer
971 22b7f6f8 Thomas Thrainer
    if self.op.mode == constants.INSTANCE_IMPORT:
972 22b7f6f8 Thomas Thrainer
      export_info = self._ReadExportInfo()
973 22b7f6f8 Thomas Thrainer
      self._ReadExportParams(export_info)
974 22b7f6f8 Thomas Thrainer
      self._old_instance_name = export_info.get(constants.INISECT_INS, "name")
975 22b7f6f8 Thomas Thrainer
    else:
976 22b7f6f8 Thomas Thrainer
      self._old_instance_name = None
977 22b7f6f8 Thomas Thrainer
978 22b7f6f8 Thomas Thrainer
    if (not self.cfg.GetVGName() and
979 22b7f6f8 Thomas Thrainer
        self.op.disk_template not in constants.DTS_NOT_LVM):
980 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Cluster does not support lvm-based"
981 22b7f6f8 Thomas Thrainer
                                 " instances", errors.ECODE_STATE)
982 22b7f6f8 Thomas Thrainer
983 22b7f6f8 Thomas Thrainer
    if (self.op.hypervisor is None or
984 22b7f6f8 Thomas Thrainer
        self.op.hypervisor == constants.VALUE_AUTO):
985 22b7f6f8 Thomas Thrainer
      self.op.hypervisor = self.cfg.GetHypervisorType()
986 22b7f6f8 Thomas Thrainer
987 22b7f6f8 Thomas Thrainer
    cluster = self.cfg.GetClusterInfo()
988 22b7f6f8 Thomas Thrainer
    enabled_hvs = cluster.enabled_hypervisors
989 22b7f6f8 Thomas Thrainer
    if self.op.hypervisor not in enabled_hvs:
990 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Selected hypervisor (%s) not enabled in the"
991 22b7f6f8 Thomas Thrainer
                                 " cluster (%s)" %
992 22b7f6f8 Thomas Thrainer
                                 (self.op.hypervisor, ",".join(enabled_hvs)),
993 22b7f6f8 Thomas Thrainer
                                 errors.ECODE_STATE)
994 22b7f6f8 Thomas Thrainer
995 22b7f6f8 Thomas Thrainer
    # Check tag validity
996 22b7f6f8 Thomas Thrainer
    for tag in self.op.tags:
997 22b7f6f8 Thomas Thrainer
      objects.TaggableObject.ValidateTag(tag)
998 22b7f6f8 Thomas Thrainer
999 22b7f6f8 Thomas Thrainer
    # check hypervisor parameter syntax (locally)
1000 22b7f6f8 Thomas Thrainer
    utils.ForceDictType(self.op.hvparams, constants.HVS_PARAMETER_TYPES)
1001 22b7f6f8 Thomas Thrainer
    filled_hvp = cluster.SimpleFillHV(self.op.hypervisor, self.op.os_type,
1002 22b7f6f8 Thomas Thrainer
                                      self.op.hvparams)
1003 22b7f6f8 Thomas Thrainer
    hv_type = hypervisor.GetHypervisorClass(self.op.hypervisor)
1004 22b7f6f8 Thomas Thrainer
    hv_type.CheckParameterSyntax(filled_hvp)
1005 22b7f6f8 Thomas Thrainer
    self.hv_full = filled_hvp
1006 22b7f6f8 Thomas Thrainer
    # check that we don't specify global parameters on an instance
1007 5eacbcae Thomas Thrainer
    CheckParamsNotGlobal(self.op.hvparams, constants.HVC_GLOBALS, "hypervisor",
1008 5eacbcae Thomas Thrainer
                         "instance", "cluster")
1009 22b7f6f8 Thomas Thrainer
1010 22b7f6f8 Thomas Thrainer
    # fill and remember the beparams dict
1011 22b7f6f8 Thomas Thrainer
    self.be_full = _ComputeFullBeParams(self.op, cluster)
1012 22b7f6f8 Thomas Thrainer
1013 22b7f6f8 Thomas Thrainer
    # build os parameters
1014 6bce7ba2 Santi Raffa
    if self.op.osparams_private is None:
1015 6bce7ba2 Santi Raffa
      self.op.osparams_private = serializer.PrivateDict()
1016 6bce7ba2 Santi Raffa
    if self.op.osparams_secret is None:
1017 6bce7ba2 Santi Raffa
      self.op.osparams_secret = serializer.PrivateDict()
1018 6bce7ba2 Santi Raffa
1019 6bce7ba2 Santi Raffa
    self.os_full = cluster.SimpleFillOS(
1020 6bce7ba2 Santi Raffa
      self.op.os_type,
1021 6bce7ba2 Santi Raffa
      self.op.osparams,
1022 6bce7ba2 Santi Raffa
      os_params_private=self.op.osparams_private,
1023 6bce7ba2 Santi Raffa
      os_params_secret=self.op.osparams_secret
1024 6bce7ba2 Santi Raffa
    )
1025 22b7f6f8 Thomas Thrainer
1026 22b7f6f8 Thomas Thrainer
    # now that hvp/bep are in final format, let's reset to defaults,
1027 22b7f6f8 Thomas Thrainer
    # if told to do so
1028 22b7f6f8 Thomas Thrainer
    if self.op.identify_defaults:
1029 22b7f6f8 Thomas Thrainer
      self._RevertToDefaults(cluster)
1030 22b7f6f8 Thomas Thrainer
1031 22b7f6f8 Thomas Thrainer
    # NIC buildup
1032 22b7f6f8 Thomas Thrainer
    self.nics = _ComputeNics(self.op, cluster, self.check_ip, self.cfg,
1033 22b7f6f8 Thomas Thrainer
                             self.proc.GetECId())
1034 22b7f6f8 Thomas Thrainer
1035 22b7f6f8 Thomas Thrainer
    # disk checks/pre-build
1036 22b7f6f8 Thomas Thrainer
    default_vg = self.cfg.GetVGName()
1037 5eacbcae Thomas Thrainer
    self.disks = ComputeDisks(self.op, default_vg)
1038 22b7f6f8 Thomas Thrainer
1039 22b7f6f8 Thomas Thrainer
    if self.op.mode == constants.INSTANCE_IMPORT:
1040 22b7f6f8 Thomas Thrainer
      disk_images = []
1041 22b7f6f8 Thomas Thrainer
      for idx in range(len(self.disks)):
1042 22b7f6f8 Thomas Thrainer
        option = "disk%d_dump" % idx
1043 22b7f6f8 Thomas Thrainer
        if export_info.has_option(constants.INISECT_INS, option):
1044 22b7f6f8 Thomas Thrainer
          # FIXME: are the old os-es, disk sizes, etc. useful?
1045 22b7f6f8 Thomas Thrainer
          export_name = export_info.get(constants.INISECT_INS, option)
1046 22b7f6f8 Thomas Thrainer
          image = utils.PathJoin(self.op.src_path, export_name)
1047 22b7f6f8 Thomas Thrainer
          disk_images.append(image)
1048 22b7f6f8 Thomas Thrainer
        else:
1049 22b7f6f8 Thomas Thrainer
          disk_images.append(False)
1050 22b7f6f8 Thomas Thrainer
1051 22b7f6f8 Thomas Thrainer
      self.src_images = disk_images
1052 22b7f6f8 Thomas Thrainer
1053 22b7f6f8 Thomas Thrainer
      if self.op.instance_name == self._old_instance_name:
1054 22b7f6f8 Thomas Thrainer
        for idx, nic in enumerate(self.nics):
1055 22b7f6f8 Thomas Thrainer
          if nic.mac == constants.VALUE_AUTO:
1056 22b7f6f8 Thomas Thrainer
            nic_mac_ini = "nic%d_mac" % idx
1057 22b7f6f8 Thomas Thrainer
            nic.mac = export_info.get(constants.INISECT_INS, nic_mac_ini)
1058 22b7f6f8 Thomas Thrainer
1059 22b7f6f8 Thomas Thrainer
    # ENDIF: self.op.mode == constants.INSTANCE_IMPORT
1060 22b7f6f8 Thomas Thrainer
1061 22b7f6f8 Thomas Thrainer
    # ip ping checks (we use the same ip that was resolved in ExpandNames)
1062 22b7f6f8 Thomas Thrainer
    if self.op.ip_check:
1063 22b7f6f8 Thomas Thrainer
      if netutils.TcpPing(self.check_ip, constants.DEFAULT_NODED_PORT):
1064 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("IP %s of instance %s already in use" %
1065 22b7f6f8 Thomas Thrainer
                                   (self.check_ip, self.op.instance_name),
1066 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_NOTUNIQUE)
1067 22b7f6f8 Thomas Thrainer
1068 22b7f6f8 Thomas Thrainer
    #### mac address generation
1069 22b7f6f8 Thomas Thrainer
    # By generating here the mac address both the allocator and the hooks get
1070 22b7f6f8 Thomas Thrainer
    # the real final mac address rather than the 'auto' or 'generate' value.
1071 22b7f6f8 Thomas Thrainer
    # There is a race condition between the generation and the instance object
1072 22b7f6f8 Thomas Thrainer
    # creation, which means that we know the mac is valid now, but we're not
1073 22b7f6f8 Thomas Thrainer
    # sure it will be when we actually add the instance. If things go bad
1074 22b7f6f8 Thomas Thrainer
    # adding the instance will abort because of a duplicate mac, and the
1075 22b7f6f8 Thomas Thrainer
    # creation job will fail.
1076 22b7f6f8 Thomas Thrainer
    for nic in self.nics:
1077 22b7f6f8 Thomas Thrainer
      if nic.mac in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
1078 22b7f6f8 Thomas Thrainer
        nic.mac = self.cfg.GenerateMAC(nic.network, self.proc.GetECId())
1079 22b7f6f8 Thomas Thrainer
1080 22b7f6f8 Thomas Thrainer
    #### allocator run
1081 22b7f6f8 Thomas Thrainer
1082 22b7f6f8 Thomas Thrainer
    if self.op.iallocator is not None:
1083 22b7f6f8 Thomas Thrainer
      self._RunAllocator()
1084 22b7f6f8 Thomas Thrainer
1085 22b7f6f8 Thomas Thrainer
    # Release all unneeded node locks
1086 1c3231aa Thomas Thrainer
    keep_locks = filter(None, [self.op.pnode_uuid, self.op.snode_uuid,
1087 1c3231aa Thomas Thrainer
                               self.op.src_node_uuid])
1088 5eacbcae Thomas Thrainer
    ReleaseLocks(self, locking.LEVEL_NODE, keep=keep_locks)
1089 5eacbcae Thomas Thrainer
    ReleaseLocks(self, locking.LEVEL_NODE_RES, keep=keep_locks)
1090 5eacbcae Thomas Thrainer
    ReleaseLocks(self, locking.LEVEL_NODE_ALLOC)
1091 8b9887c5 Petr Pudlak
    # Release all unneeded group locks
1092 8b9887c5 Petr Pudlak
    ReleaseLocks(self, locking.LEVEL_NODEGROUP,
1093 8b9887c5 Petr Pudlak
                 keep=self.cfg.GetNodeGroupsFromNodes(keep_locks))
1094 22b7f6f8 Thomas Thrainer
1095 22b7f6f8 Thomas Thrainer
    assert (self.owned_locks(locking.LEVEL_NODE) ==
1096 22b7f6f8 Thomas Thrainer
            self.owned_locks(locking.LEVEL_NODE_RES)), \
1097 22b7f6f8 Thomas Thrainer
      "Node locks differ from node resource locks"
1098 22b7f6f8 Thomas Thrainer
1099 22b7f6f8 Thomas Thrainer
    #### node related checks
1100 22b7f6f8 Thomas Thrainer
1101 22b7f6f8 Thomas Thrainer
    # check primary node
1102 1c3231aa Thomas Thrainer
    self.pnode = pnode = self.cfg.GetNodeInfo(self.op.pnode_uuid)
1103 22b7f6f8 Thomas Thrainer
    assert self.pnode is not None, \
1104 1c3231aa Thomas Thrainer
      "Cannot retrieve locked node %s" % self.op.pnode_uuid
1105 22b7f6f8 Thomas Thrainer
    if pnode.offline:
1106 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Cannot use offline primary node '%s'" %
1107 22b7f6f8 Thomas Thrainer
                                 pnode.name, errors.ECODE_STATE)
1108 22b7f6f8 Thomas Thrainer
    if pnode.drained:
1109 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Cannot use drained primary node '%s'" %
1110 22b7f6f8 Thomas Thrainer
                                 pnode.name, errors.ECODE_STATE)
1111 22b7f6f8 Thomas Thrainer
    if not pnode.vm_capable:
1112 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Cannot use non-vm_capable primary node"
1113 22b7f6f8 Thomas Thrainer
                                 " '%s'" % pnode.name, errors.ECODE_STATE)
1114 22b7f6f8 Thomas Thrainer
1115 22b7f6f8 Thomas Thrainer
    self.secondaries = []
1116 22b7f6f8 Thomas Thrainer
1117 22b7f6f8 Thomas Thrainer
    # Fill in any IPs from IP pools. This must happen here, because we need to
1118 22b7f6f8 Thomas Thrainer
    # know the nic's primary node, as specified by the iallocator
1119 22b7f6f8 Thomas Thrainer
    for idx, nic in enumerate(self.nics):
1120 22b7f6f8 Thomas Thrainer
      net_uuid = nic.network
1121 22b7f6f8 Thomas Thrainer
      if net_uuid is not None:
1122 22b7f6f8 Thomas Thrainer
        nobj = self.cfg.GetNetwork(net_uuid)
1123 1c3231aa Thomas Thrainer
        netparams = self.cfg.GetGroupNetParams(net_uuid, self.pnode.uuid)
1124 22b7f6f8 Thomas Thrainer
        if netparams is None:
1125 22b7f6f8 Thomas Thrainer
          raise errors.OpPrereqError("No netparams found for network"
1126 66222813 Thomas Thrainer
                                     " %s. Probably not connected to"
1127 22b7f6f8 Thomas Thrainer
                                     " node's %s nodegroup" %
1128 22b7f6f8 Thomas Thrainer
                                     (nobj.name, self.pnode.name),
1129 22b7f6f8 Thomas Thrainer
                                     errors.ECODE_INVAL)
1130 22b7f6f8 Thomas Thrainer
        self.LogInfo("NIC/%d inherits netparams %s" %
1131 22b7f6f8 Thomas Thrainer
                     (idx, netparams.values()))
1132 22b7f6f8 Thomas Thrainer
        nic.nicparams = dict(netparams)
1133 22b7f6f8 Thomas Thrainer
        if nic.ip is not None:
1134 22b7f6f8 Thomas Thrainer
          if nic.ip.lower() == constants.NIC_IP_POOL:
1135 22b7f6f8 Thomas Thrainer
            try:
1136 22b7f6f8 Thomas Thrainer
              nic.ip = self.cfg.GenerateIp(net_uuid, self.proc.GetECId())
1137 22b7f6f8 Thomas Thrainer
            except errors.ReservationError:
1138 22b7f6f8 Thomas Thrainer
              raise errors.OpPrereqError("Unable to get a free IP for NIC %d"
1139 22b7f6f8 Thomas Thrainer
                                         " from the address pool" % idx,
1140 22b7f6f8 Thomas Thrainer
                                         errors.ECODE_STATE)
1141 22b7f6f8 Thomas Thrainer
            self.LogInfo("Chose IP %s from network %s", nic.ip, nobj.name)
1142 22b7f6f8 Thomas Thrainer
          else:
1143 22b7f6f8 Thomas Thrainer
            try:
1144 031d2db1 Dimitris Aragiorgis
              self.cfg.ReserveIp(net_uuid, nic.ip, self.proc.GetECId(),
1145 031d2db1 Dimitris Aragiorgis
                                 check=self.op.conflicts_check)
1146 22b7f6f8 Thomas Thrainer
            except errors.ReservationError:
1147 22b7f6f8 Thomas Thrainer
              raise errors.OpPrereqError("IP address %s already in use"
1148 22b7f6f8 Thomas Thrainer
                                         " or does not belong to network %s" %
1149 22b7f6f8 Thomas Thrainer
                                         (nic.ip, nobj.name),
1150 22b7f6f8 Thomas Thrainer
                                         errors.ECODE_NOTUNIQUE)
1151 22b7f6f8 Thomas Thrainer
1152 22b7f6f8 Thomas Thrainer
      # net is None, ip None or given
1153 22b7f6f8 Thomas Thrainer
      elif self.op.conflicts_check:
1154 1c3231aa Thomas Thrainer
        _CheckForConflictingIp(self, nic.ip, self.pnode.uuid)
1155 22b7f6f8 Thomas Thrainer
1156 22b7f6f8 Thomas Thrainer
    # mirror node verification
1157 22b7f6f8 Thomas Thrainer
    if self.op.disk_template in constants.DTS_INT_MIRROR:
1158 1c3231aa Thomas Thrainer
      if self.op.snode_uuid == pnode.uuid:
1159 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("The secondary node cannot be the"
1160 22b7f6f8 Thomas Thrainer
                                   " primary node", errors.ECODE_INVAL)
1161 1c3231aa Thomas Thrainer
      CheckNodeOnline(self, self.op.snode_uuid)
1162 1c3231aa Thomas Thrainer
      CheckNodeNotDrained(self, self.op.snode_uuid)
1163 1c3231aa Thomas Thrainer
      CheckNodeVmCapable(self, self.op.snode_uuid)
1164 1c3231aa Thomas Thrainer
      self.secondaries.append(self.op.snode_uuid)
1165 22b7f6f8 Thomas Thrainer
1166 1c3231aa Thomas Thrainer
      snode = self.cfg.GetNodeInfo(self.op.snode_uuid)
1167 22b7f6f8 Thomas Thrainer
      if pnode.group != snode.group:
1168 22b7f6f8 Thomas Thrainer
        self.LogWarning("The primary and secondary nodes are in two"
1169 22b7f6f8 Thomas Thrainer
                        " different node groups; the disk parameters"
1170 22b7f6f8 Thomas Thrainer
                        " from the first disk's node group will be"
1171 22b7f6f8 Thomas Thrainer
                        " used")
1172 22b7f6f8 Thomas Thrainer
1173 1bb99a33 Bernardo Dal Seno
    nodes = [pnode]
1174 1bb99a33 Bernardo Dal Seno
    if self.op.disk_template in constants.DTS_INT_MIRROR:
1175 1bb99a33 Bernardo Dal Seno
      nodes.append(snode)
1176 1bb99a33 Bernardo Dal Seno
    has_es = lambda n: IsExclusiveStorageEnabledNode(self.cfg, n)
1177 3f3ea14c Bernardo Dal Seno
    excl_stor = compat.any(map(has_es, nodes))
1178 3f3ea14c Bernardo Dal Seno
    if excl_stor and not self.op.disk_template in constants.DTS_EXCL_STORAGE:
1179 3f3ea14c Bernardo Dal Seno
      raise errors.OpPrereqError("Disk template %s not supported with"
1180 3f3ea14c Bernardo Dal Seno
                                 " exclusive storage" % self.op.disk_template,
1181 3f3ea14c Bernardo Dal Seno
                                 errors.ECODE_STATE)
1182 3f3ea14c Bernardo Dal Seno
    for disk in self.disks:
1183 7c848a6a Bernardo Dal Seno
      CheckSpindlesExclusiveStorage(disk, excl_stor, True)
1184 22b7f6f8 Thomas Thrainer
1185 1c3231aa Thomas Thrainer
    node_uuids = [pnode.uuid] + self.secondaries
1186 22b7f6f8 Thomas Thrainer
1187 22b7f6f8 Thomas Thrainer
    if not self.adopt_disks:
1188 22b7f6f8 Thomas Thrainer
      if self.op.disk_template == constants.DT_RBD:
1189 22b7f6f8 Thomas Thrainer
        # _CheckRADOSFreeSpace() is just a placeholder.
1190 22b7f6f8 Thomas Thrainer
        # Any function that checks prerequisites can be placed here.
1191 22b7f6f8 Thomas Thrainer
        # Check if there is enough space on the RADOS cluster.
1192 5eacbcae Thomas Thrainer
        CheckRADOSFreeSpace()
1193 22b7f6f8 Thomas Thrainer
      elif self.op.disk_template == constants.DT_EXT:
1194 22b7f6f8 Thomas Thrainer
        # FIXME: Function that checks prereqs if needed
1195 22b7f6f8 Thomas Thrainer
        pass
1196 d48c944b Helga Velroyen
      elif self.op.disk_template in constants.DTS_LVM:
1197 22b7f6f8 Thomas Thrainer
        # Check lv size requirements, if not adopting
1198 5eacbcae Thomas Thrainer
        req_sizes = ComputeDiskSizePerVG(self.op.disk_template, self.disks)
1199 1c3231aa Thomas Thrainer
        CheckNodesFreeDiskPerVG(self, node_uuids, req_sizes)
1200 4b92e992 Helga Velroyen
      else:
1201 4b92e992 Helga Velroyen
        # FIXME: add checks for other, non-adopting, non-lvm disk templates
1202 4b92e992 Helga Velroyen
        pass
1203 22b7f6f8 Thomas Thrainer
1204 22b7f6f8 Thomas Thrainer
    elif self.op.disk_template == constants.DT_PLAIN: # Check the adoption data
1205 22b7f6f8 Thomas Thrainer
      all_lvs = set(["%s/%s" % (disk[constants.IDISK_VG],
1206 22b7f6f8 Thomas Thrainer
                                disk[constants.IDISK_ADOPT])
1207 22b7f6f8 Thomas Thrainer
                     for disk in self.disks])
1208 22b7f6f8 Thomas Thrainer
      if len(all_lvs) != len(self.disks):
1209 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Duplicate volume names given for adoption",
1210 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
1211 22b7f6f8 Thomas Thrainer
      for lv_name in all_lvs:
1212 22b7f6f8 Thomas Thrainer
        try:
1213 22b7f6f8 Thomas Thrainer
          # FIXME: lv_name here is "vg/lv" need to ensure that other calls
1214 22b7f6f8 Thomas Thrainer
          # to ReserveLV uses the same syntax
1215 22b7f6f8 Thomas Thrainer
          self.cfg.ReserveLV(lv_name, self.proc.GetECId())
1216 22b7f6f8 Thomas Thrainer
        except errors.ReservationError:
1217 22b7f6f8 Thomas Thrainer
          raise errors.OpPrereqError("LV named %s used by another instance" %
1218 22b7f6f8 Thomas Thrainer
                                     lv_name, errors.ECODE_NOTUNIQUE)
1219 22b7f6f8 Thomas Thrainer
1220 1c3231aa Thomas Thrainer
      vg_names = self.rpc.call_vg_list([pnode.uuid])[pnode.uuid]
1221 22b7f6f8 Thomas Thrainer
      vg_names.Raise("Cannot get VG information from node %s" % pnode.name)
1222 22b7f6f8 Thomas Thrainer
1223 1c3231aa Thomas Thrainer
      node_lvs = self.rpc.call_lv_list([pnode.uuid],
1224 1c3231aa Thomas Thrainer
                                       vg_names.payload.keys())[pnode.uuid]
1225 22b7f6f8 Thomas Thrainer
      node_lvs.Raise("Cannot get LV information from node %s" % pnode.name)
1226 22b7f6f8 Thomas Thrainer
      node_lvs = node_lvs.payload
1227 22b7f6f8 Thomas Thrainer
1228 22b7f6f8 Thomas Thrainer
      delta = all_lvs.difference(node_lvs.keys())
1229 22b7f6f8 Thomas Thrainer
      if delta:
1230 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Missing logical volume(s): %s" %
1231 22b7f6f8 Thomas Thrainer
                                   utils.CommaJoin(delta),
1232 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
1233 22b7f6f8 Thomas Thrainer
      online_lvs = [lv for lv in all_lvs if node_lvs[lv][2]]
1234 22b7f6f8 Thomas Thrainer
      if online_lvs:
1235 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Online logical volumes found, cannot"
1236 22b7f6f8 Thomas Thrainer
                                   " adopt: %s" % utils.CommaJoin(online_lvs),
1237 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_STATE)
1238 22b7f6f8 Thomas Thrainer
      # update the size of disk based on what is found
1239 22b7f6f8 Thomas Thrainer
      for dsk in self.disks:
1240 22b7f6f8 Thomas Thrainer
        dsk[constants.IDISK_SIZE] = \
1241 22b7f6f8 Thomas Thrainer
          int(float(node_lvs["%s/%s" % (dsk[constants.IDISK_VG],
1242 22b7f6f8 Thomas Thrainer
                                        dsk[constants.IDISK_ADOPT])][0]))
1243 22b7f6f8 Thomas Thrainer
1244 22b7f6f8 Thomas Thrainer
    elif self.op.disk_template == constants.DT_BLOCK:
1245 22b7f6f8 Thomas Thrainer
      # Normalize and de-duplicate device paths
1246 22b7f6f8 Thomas Thrainer
      all_disks = set([os.path.abspath(disk[constants.IDISK_ADOPT])
1247 22b7f6f8 Thomas Thrainer
                       for disk in self.disks])
1248 22b7f6f8 Thomas Thrainer
      if len(all_disks) != len(self.disks):
1249 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Duplicate disk names given for adoption",
1250 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
1251 22b7f6f8 Thomas Thrainer
      baddisks = [d for d in all_disks
1252 22b7f6f8 Thomas Thrainer
                  if not d.startswith(constants.ADOPTABLE_BLOCKDEV_ROOT)]
1253 22b7f6f8 Thomas Thrainer
      if baddisks:
1254 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Device node(s) %s lie outside %s and"
1255 22b7f6f8 Thomas Thrainer
                                   " cannot be adopted" %
1256 22b7f6f8 Thomas Thrainer
                                   (utils.CommaJoin(baddisks),
1257 22b7f6f8 Thomas Thrainer
                                    constants.ADOPTABLE_BLOCKDEV_ROOT),
1258 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
1259 22b7f6f8 Thomas Thrainer
1260 1c3231aa Thomas Thrainer
      node_disks = self.rpc.call_bdev_sizes([pnode.uuid],
1261 1c3231aa Thomas Thrainer
                                            list(all_disks))[pnode.uuid]
1262 22b7f6f8 Thomas Thrainer
      node_disks.Raise("Cannot get block device information from node %s" %
1263 22b7f6f8 Thomas Thrainer
                       pnode.name)
1264 22b7f6f8 Thomas Thrainer
      node_disks = node_disks.payload
1265 22b7f6f8 Thomas Thrainer
      delta = all_disks.difference(node_disks.keys())
1266 22b7f6f8 Thomas Thrainer
      if delta:
1267 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Missing block device(s): %s" %
1268 22b7f6f8 Thomas Thrainer
                                   utils.CommaJoin(delta),
1269 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
1270 22b7f6f8 Thomas Thrainer
      for dsk in self.disks:
1271 22b7f6f8 Thomas Thrainer
        dsk[constants.IDISK_SIZE] = \
1272 22b7f6f8 Thomas Thrainer
          int(float(node_disks[dsk[constants.IDISK_ADOPT]]))
1273 22b7f6f8 Thomas Thrainer
1274 294254b1 Raffa Santi
    # Check disk access param to be compatible with specified hypervisor
1275 294254b1 Raffa Santi
    node_info = self.cfg.GetNodeInfo(self.op.pnode_uuid)
1276 294254b1 Raffa Santi
    node_group = self.cfg.GetNodeGroup(node_info.group)
1277 294254b1 Raffa Santi
    disk_params = self.cfg.GetGroupDiskParams(node_group)
1278 294254b1 Raffa Santi
    access_type = disk_params[self.op.disk_template].get(
1279 294254b1 Raffa Santi
      constants.RBD_ACCESS, constants.DISK_KERNELSPACE
1280 294254b1 Raffa Santi
    )
1281 294254b1 Raffa Santi
1282 294254b1 Raffa Santi
    if not IsValidDiskAccessModeCombination(self.op.hypervisor,
1283 294254b1 Raffa Santi
                                            self.op.disk_template,
1284 294254b1 Raffa Santi
                                            access_type):
1285 294254b1 Raffa Santi
      raise errors.OpPrereqError("Selected hypervisor (%s) cannot be"
1286 294254b1 Raffa Santi
                                 " used with %s disk access param" %
1287 294254b1 Raffa Santi
                                 (self.op.hypervisor, access_type),
1288 294254b1 Raffa Santi
                                  errors.ECODE_STATE)
1289 294254b1 Raffa Santi
1290 22b7f6f8 Thomas Thrainer
    # Verify instance specs
1291 22b7f6f8 Thomas Thrainer
    spindle_use = self.be_full.get(constants.BE_SPINDLE_USE, None)
1292 22b7f6f8 Thomas Thrainer
    ispec = {
1293 22b7f6f8 Thomas Thrainer
      constants.ISPEC_MEM_SIZE: self.be_full.get(constants.BE_MAXMEM, None),
1294 22b7f6f8 Thomas Thrainer
      constants.ISPEC_CPU_COUNT: self.be_full.get(constants.BE_VCPUS, None),
1295 22b7f6f8 Thomas Thrainer
      constants.ISPEC_DISK_COUNT: len(self.disks),
1296 22b7f6f8 Thomas Thrainer
      constants.ISPEC_DISK_SIZE: [disk[constants.IDISK_SIZE]
1297 22b7f6f8 Thomas Thrainer
                                  for disk in self.disks],
1298 22b7f6f8 Thomas Thrainer
      constants.ISPEC_NIC_COUNT: len(self.nics),
1299 22b7f6f8 Thomas Thrainer
      constants.ISPEC_SPINDLE_USE: spindle_use,
1300 22b7f6f8 Thomas Thrainer
      }
1301 22b7f6f8 Thomas Thrainer
1302 22b7f6f8 Thomas Thrainer
    group_info = self.cfg.GetNodeGroup(pnode.group)
1303 22b7f6f8 Thomas Thrainer
    ipolicy = ganeti.masterd.instance.CalculateGroupIPolicy(cluster, group_info)
1304 22b7f6f8 Thomas Thrainer
    res = _ComputeIPolicyInstanceSpecViolation(ipolicy, ispec,
1305 22b7f6f8 Thomas Thrainer
                                               self.op.disk_template)
1306 22b7f6f8 Thomas Thrainer
    if not self.op.ignore_ipolicy and res:
1307 22b7f6f8 Thomas Thrainer
      msg = ("Instance allocation to group %s (%s) violates policy: %s" %
1308 22b7f6f8 Thomas Thrainer
             (pnode.group, group_info.name, utils.CommaJoin(res)))
1309 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
1310 22b7f6f8 Thomas Thrainer
1311 1c3231aa Thomas Thrainer
    CheckHVParams(self, node_uuids, self.op.hypervisor, self.op.hvparams)
1312 22b7f6f8 Thomas Thrainer
1313 1c4910f7 Jose A. Lopes
    if self.op.os_type is not None:
1314 1c4910f7 Jose A. Lopes
      CheckNodeHasOS(self, pnode.uuid, self.op.os_type, self.op.force_variant)
1315 1c4910f7 Jose A. Lopes
1316 22b7f6f8 Thomas Thrainer
    # check OS parameters (remotely)
1317 1c3231aa Thomas Thrainer
    CheckOSParams(self, True, node_uuids, self.op.os_type, self.os_full)
1318 22b7f6f8 Thomas Thrainer
1319 1c3231aa Thomas Thrainer
    CheckNicsBridgesExist(self, self.nics, self.pnode.uuid)
1320 22b7f6f8 Thomas Thrainer
1321 22b7f6f8 Thomas Thrainer
    #TODO: _CheckExtParams (remotely)
1322 22b7f6f8 Thomas Thrainer
    # Check parameters for extstorage
1323 22b7f6f8 Thomas Thrainer
1324 22b7f6f8 Thomas Thrainer
    # memory check on primary node
1325 22b7f6f8 Thomas Thrainer
    #TODO(dynmem): use MINMEM for checking
1326 22b7f6f8 Thomas Thrainer
    if self.op.start:
1327 a295eb80 Helga Velroyen
      hvfull = objects.FillDict(cluster.hvparams.get(self.op.hypervisor, {}),
1328 a295eb80 Helga Velroyen
                                self.op.hvparams)
1329 1c3231aa Thomas Thrainer
      CheckNodeFreeMemory(self, self.pnode.uuid,
1330 5eacbcae Thomas Thrainer
                          "creating instance %s" % self.op.instance_name,
1331 5eacbcae Thomas Thrainer
                          self.be_full[constants.BE_MAXMEM],
1332 a295eb80 Helga Velroyen
                          self.op.hypervisor, hvfull)
1333 22b7f6f8 Thomas Thrainer
1334 1c3231aa Thomas Thrainer
    self.dry_run_result = list(node_uuids)
1335 22b7f6f8 Thomas Thrainer
1336 987ec378 Jose A. Lopes
  def _RemoveDegradedDisks(self, feedback_fn, disk_abort, instance):
1337 987ec378 Jose A. Lopes
    """Removes degraded disks and instance.
1338 987ec378 Jose A. Lopes

1339 987ec378 Jose A. Lopes
    It optionally checks whether disks are degraded.  If the disks are
1340 987ec378 Jose A. Lopes
    degraded, they are removed and the instance is also removed from
1341 987ec378 Jose A. Lopes
    the configuration.
1342 987ec378 Jose A. Lopes

1343 987ec378 Jose A. Lopes
    If L{disk_abort} is True, then the disks are considered degraded
1344 987ec378 Jose A. Lopes
    and removed, and the instance is removed from the configuration.
1345 987ec378 Jose A. Lopes

1346 987ec378 Jose A. Lopes
    If L{disk_abort} is False, then it first checks whether disks are
1347 987ec378 Jose A. Lopes
    degraded and, if so, it removes the disks and the instance is
1348 987ec378 Jose A. Lopes
    removed from the configuration.
1349 987ec378 Jose A. Lopes

1350 987ec378 Jose A. Lopes
    @type feedback_fn: callable
1351 987ec378 Jose A. Lopes
    @param feedback_fn: function used send feedback back to the caller
1352 987ec378 Jose A. Lopes

1353 987ec378 Jose A. Lopes
    @type disk_abort: boolean
1354 987ec378 Jose A. Lopes
    @param disk_abort:
1355 987ec378 Jose A. Lopes
      True if disks are degraded, False to first check if disks are
1356 987ec378 Jose A. Lopes
      degraded
1357 987ec378 Jose A. Lopes

1358 987ec378 Jose A. Lopes
    @type instance: L{objects.Instance}
1359 987ec378 Jose A. Lopes
    @param instance: instance containing the disks to check
1360 987ec378 Jose A. Lopes

1361 987ec378 Jose A. Lopes
    @rtype: NoneType
1362 987ec378 Jose A. Lopes
    @return: None
1363 987ec378 Jose A. Lopes
    @raise errors.OpPrereqError: if disks are degraded
1364 987ec378 Jose A. Lopes

1365 987ec378 Jose A. Lopes
    """
1366 987ec378 Jose A. Lopes
    if disk_abort:
1367 987ec378 Jose A. Lopes
      pass
1368 987ec378 Jose A. Lopes
    elif self.op.wait_for_sync:
1369 987ec378 Jose A. Lopes
      disk_abort = not WaitForSync(self, instance)
1370 987ec378 Jose A. Lopes
    elif instance.disk_template in constants.DTS_INT_MIRROR:
1371 987ec378 Jose A. Lopes
      # make sure the disks are not degraded (still sync-ing is ok)
1372 987ec378 Jose A. Lopes
      feedback_fn("* checking mirrors status")
1373 987ec378 Jose A. Lopes
      disk_abort = not WaitForSync(self, instance, oneshot=True)
1374 987ec378 Jose A. Lopes
    else:
1375 987ec378 Jose A. Lopes
      disk_abort = False
1376 987ec378 Jose A. Lopes
1377 987ec378 Jose A. Lopes
    if disk_abort:
1378 987ec378 Jose A. Lopes
      RemoveDisks(self, instance)
1379 987ec378 Jose A. Lopes
      self.cfg.RemoveInstance(instance.uuid)
1380 987ec378 Jose A. Lopes
      # Make sure the instance lock gets removed
1381 987ec378 Jose A. Lopes
      self.remove_locks[locking.LEVEL_INSTANCE] = instance.name
1382 987ec378 Jose A. Lopes
      raise errors.OpExecError("There are some degraded disks for"
1383 987ec378 Jose A. Lopes
                               " this instance")
1384 987ec378 Jose A. Lopes
1385 22b7f6f8 Thomas Thrainer
  def Exec(self, feedback_fn):
1386 22b7f6f8 Thomas Thrainer
    """Create and add the instance to the cluster.
1387 22b7f6f8 Thomas Thrainer

1388 22b7f6f8 Thomas Thrainer
    """
1389 22b7f6f8 Thomas Thrainer
    assert not (self.owned_locks(locking.LEVEL_NODE_RES) -
1390 22b7f6f8 Thomas Thrainer
                self.owned_locks(locking.LEVEL_NODE)), \
1391 22b7f6f8 Thomas Thrainer
      "Node locks differ from node resource locks"
1392 22b7f6f8 Thomas Thrainer
1393 22b7f6f8 Thomas Thrainer
    ht_kind = self.op.hypervisor
1394 22b7f6f8 Thomas Thrainer
    if ht_kind in constants.HTS_REQ_PORT:
1395 22b7f6f8 Thomas Thrainer
      network_port = self.cfg.AllocatePort()
1396 22b7f6f8 Thomas Thrainer
    else:
1397 22b7f6f8 Thomas Thrainer
      network_port = None
1398 22b7f6f8 Thomas Thrainer
1399 da4a52a3 Thomas Thrainer
    instance_uuid = self.cfg.GenerateUniqueID(self.proc.GetECId())
1400 da4a52a3 Thomas Thrainer
1401 22b7f6f8 Thomas Thrainer
    # This is ugly but we got a chicken-egg problem here
1402 22b7f6f8 Thomas Thrainer
    # We can only take the group disk parameters, as the instance
1403 22b7f6f8 Thomas Thrainer
    # has no disks yet (we are generating them right here).
1404 1c3231aa Thomas Thrainer
    nodegroup = self.cfg.GetNodeGroup(self.pnode.group)
1405 5eacbcae Thomas Thrainer
    disks = GenerateDiskTemplate(self,
1406 5eacbcae Thomas Thrainer
                                 self.op.disk_template,
1407 da4a52a3 Thomas Thrainer
                                 instance_uuid, self.pnode.uuid,
1408 5eacbcae Thomas Thrainer
                                 self.secondaries,
1409 5eacbcae Thomas Thrainer
                                 self.disks,
1410 5eacbcae Thomas Thrainer
                                 self.instance_file_storage_dir,
1411 5eacbcae Thomas Thrainer
                                 self.op.file_driver,
1412 5eacbcae Thomas Thrainer
                                 0,
1413 5eacbcae Thomas Thrainer
                                 feedback_fn,
1414 5eacbcae Thomas Thrainer
                                 self.cfg.GetGroupDiskParams(nodegroup))
1415 22b7f6f8 Thomas Thrainer
1416 1c4910f7 Jose A. Lopes
    if self.op.os_type is None:
1417 1c4910f7 Jose A. Lopes
      os_type = ""
1418 1c4910f7 Jose A. Lopes
    else:
1419 1c4910f7 Jose A. Lopes
      os_type = self.op.os_type
1420 1c4910f7 Jose A. Lopes
1421 da4a52a3 Thomas Thrainer
    iobj = objects.Instance(name=self.op.instance_name,
1422 da4a52a3 Thomas Thrainer
                            uuid=instance_uuid,
1423 1c4910f7 Jose A. Lopes
                            os=os_type,
1424 1c3231aa Thomas Thrainer
                            primary_node=self.pnode.uuid,
1425 22b7f6f8 Thomas Thrainer
                            nics=self.nics, disks=disks,
1426 22b7f6f8 Thomas Thrainer
                            disk_template=self.op.disk_template,
1427 1d4a4b26 Thomas Thrainer
                            disks_active=False,
1428 22b7f6f8 Thomas Thrainer
                            admin_state=constants.ADMINST_DOWN,
1429 22b7f6f8 Thomas Thrainer
                            network_port=network_port,
1430 22b7f6f8 Thomas Thrainer
                            beparams=self.op.beparams,
1431 22b7f6f8 Thomas Thrainer
                            hvparams=self.op.hvparams,
1432 22b7f6f8 Thomas Thrainer
                            hypervisor=self.op.hypervisor,
1433 22b7f6f8 Thomas Thrainer
                            osparams=self.op.osparams,
1434 6bce7ba2 Santi Raffa
                            osparams_private=self.op.osparams_private,
1435 22b7f6f8 Thomas Thrainer
                            )
1436 22b7f6f8 Thomas Thrainer
1437 22b7f6f8 Thomas Thrainer
    if self.op.tags:
1438 22b7f6f8 Thomas Thrainer
      for tag in self.op.tags:
1439 22b7f6f8 Thomas Thrainer
        iobj.AddTag(tag)
1440 22b7f6f8 Thomas Thrainer
1441 22b7f6f8 Thomas Thrainer
    if self.adopt_disks:
1442 22b7f6f8 Thomas Thrainer
      if self.op.disk_template == constants.DT_PLAIN:
1443 22b7f6f8 Thomas Thrainer
        # rename LVs to the newly-generated names; we need to construct
1444 22b7f6f8 Thomas Thrainer
        # 'fake' LV disks with the old data, plus the new unique_id
1445 22b7f6f8 Thomas Thrainer
        tmp_disks = [objects.Disk.FromDict(v.ToDict()) for v in disks]
1446 22b7f6f8 Thomas Thrainer
        rename_to = []
1447 22b7f6f8 Thomas Thrainer
        for t_dsk, a_dsk in zip(tmp_disks, self.disks):
1448 22b7f6f8 Thomas Thrainer
          rename_to.append(t_dsk.logical_id)
1449 22b7f6f8 Thomas Thrainer
          t_dsk.logical_id = (t_dsk.logical_id[0], a_dsk[constants.IDISK_ADOPT])
1450 1c3231aa Thomas Thrainer
        result = self.rpc.call_blockdev_rename(self.pnode.uuid,
1451 22b7f6f8 Thomas Thrainer
                                               zip(tmp_disks, rename_to))
1452 22b7f6f8 Thomas Thrainer
        result.Raise("Failed to rename adoped LVs")
1453 22b7f6f8 Thomas Thrainer
    else:
1454 22b7f6f8 Thomas Thrainer
      feedback_fn("* creating instance disks...")
1455 22b7f6f8 Thomas Thrainer
      try:
1456 5eacbcae Thomas Thrainer
        CreateDisks(self, iobj)
1457 22b7f6f8 Thomas Thrainer
      except errors.OpExecError:
1458 22b7f6f8 Thomas Thrainer
        self.LogWarning("Device creation failed")
1459 d0d7d7cf Thomas Thrainer
        self.cfg.ReleaseDRBDMinors(self.op.instance_name)
1460 22b7f6f8 Thomas Thrainer
        raise
1461 22b7f6f8 Thomas Thrainer
1462 d0d7d7cf Thomas Thrainer
    feedback_fn("adding instance %s to cluster config" % self.op.instance_name)
1463 22b7f6f8 Thomas Thrainer
1464 22b7f6f8 Thomas Thrainer
    self.cfg.AddInstance(iobj, self.proc.GetECId())
1465 22b7f6f8 Thomas Thrainer
1466 22b7f6f8 Thomas Thrainer
    # Declare that we don't want to remove the instance lock anymore, as we've
1467 22b7f6f8 Thomas Thrainer
    # added the instance to the config
1468 22b7f6f8 Thomas Thrainer
    del self.remove_locks[locking.LEVEL_INSTANCE]
1469 22b7f6f8 Thomas Thrainer
1470 22b7f6f8 Thomas Thrainer
    if self.op.mode == constants.INSTANCE_IMPORT:
1471 22b7f6f8 Thomas Thrainer
      # Release unused nodes
1472 1c3231aa Thomas Thrainer
      ReleaseLocks(self, locking.LEVEL_NODE, keep=[self.op.src_node_uuid])
1473 22b7f6f8 Thomas Thrainer
    else:
1474 22b7f6f8 Thomas Thrainer
      # Release all nodes
1475 5eacbcae Thomas Thrainer
      ReleaseLocks(self, locking.LEVEL_NODE)
1476 22b7f6f8 Thomas Thrainer
1477 987ec378 Jose A. Lopes
    # Wipe disks
1478 22b7f6f8 Thomas Thrainer
    disk_abort = False
1479 22b7f6f8 Thomas Thrainer
    if not self.adopt_disks and self.cfg.GetClusterInfo().prealloc_wipe_disks:
1480 22b7f6f8 Thomas Thrainer
      feedback_fn("* wiping instance disks...")
1481 22b7f6f8 Thomas Thrainer
      try:
1482 5eacbcae Thomas Thrainer
        WipeDisks(self, iobj)
1483 22b7f6f8 Thomas Thrainer
      except errors.OpExecError, err:
1484 22b7f6f8 Thomas Thrainer
        logging.exception("Wiping disks failed")
1485 22b7f6f8 Thomas Thrainer
        self.LogWarning("Wiping instance disks failed (%s)", err)
1486 22b7f6f8 Thomas Thrainer
        disk_abort = True
1487 22b7f6f8 Thomas Thrainer
1488 987ec378 Jose A. Lopes
    self._RemoveDegradedDisks(feedback_fn, disk_abort, iobj)
1489 22b7f6f8 Thomas Thrainer
1490 2329ffdd Jose A. Lopes
    # Image disks
1491 2329ffdd Jose A. Lopes
    os_image = objects.GetOSImage(iobj.osparams)
1492 2329ffdd Jose A. Lopes
    disk_abort = False
1493 2329ffdd Jose A. Lopes
1494 2329ffdd Jose A. Lopes
    if not self.adopt_disks and os_image is not None:
1495 2329ffdd Jose A. Lopes
      master = self.cfg.GetMasterNode()
1496 2329ffdd Jose A. Lopes
1497 2329ffdd Jose A. Lopes
      if not utils.IsUrl(os_image) and master != self.pnode.uuid:
1498 2329ffdd Jose A. Lopes
        ssh_port = self.pnode.ndparams.get(constants.ND_SSH_PORT)
1499 2329ffdd Jose A. Lopes
        srun = ssh.SshRunner(self.cfg.GetClusterName())
1500 2329ffdd Jose A. Lopes
        srun.CopyFileToNode(self.pnode.name, ssh_port, os_image)
1501 2329ffdd Jose A. Lopes
1502 2329ffdd Jose A. Lopes
      feedback_fn("* imaging instance disks...")
1503 2329ffdd Jose A. Lopes
      try:
1504 2329ffdd Jose A. Lopes
        ImageDisks(self, iobj, os_image)
1505 2329ffdd Jose A. Lopes
      except errors.OpExecError, err:
1506 2329ffdd Jose A. Lopes
        logging.exception("Imaging disks failed")
1507 2329ffdd Jose A. Lopes
        self.LogWarning("Imaging instance disks failed (%s)", err)
1508 2329ffdd Jose A. Lopes
        disk_abort = True
1509 2329ffdd Jose A. Lopes
1510 2329ffdd Jose A. Lopes
    self._RemoveDegradedDisks(feedback_fn, disk_abort, iobj)
1511 22b7f6f8 Thomas Thrainer
1512 1d4a4b26 Thomas Thrainer
    # instance disks are now active
1513 1d4a4b26 Thomas Thrainer
    iobj.disks_active = True
1514 1d4a4b26 Thomas Thrainer
1515 22b7f6f8 Thomas Thrainer
    # Release all node resource locks
1516 5eacbcae Thomas Thrainer
    ReleaseLocks(self, locking.LEVEL_NODE_RES)
1517 22b7f6f8 Thomas Thrainer
1518 22b7f6f8 Thomas Thrainer
    if iobj.disk_template != constants.DT_DISKLESS and not self.adopt_disks:
1519 22b7f6f8 Thomas Thrainer
      if self.op.mode == constants.INSTANCE_CREATE:
1520 1c4910f7 Jose A. Lopes
        os_image = objects.GetOSImage(self.op.osparams)
1521 1c4910f7 Jose A. Lopes
1522 1c4910f7 Jose A. Lopes
        if os_image is None and not self.op.no_install:
1523 22b7f6f8 Thomas Thrainer
          pause_sync = (iobj.disk_template in constants.DTS_INT_MIRROR and
1524 22b7f6f8 Thomas Thrainer
                        not self.op.wait_for_sync)
1525 22b7f6f8 Thomas Thrainer
          if pause_sync:
1526 22b7f6f8 Thomas Thrainer
            feedback_fn("* pausing disk sync to install instance OS")
1527 1c3231aa Thomas Thrainer
            result = self.rpc.call_blockdev_pause_resume_sync(self.pnode.uuid,
1528 22b7f6f8 Thomas Thrainer
                                                              (iobj.disks,
1529 22b7f6f8 Thomas Thrainer
                                                               iobj), True)
1530 22b7f6f8 Thomas Thrainer
            for idx, success in enumerate(result.payload):
1531 22b7f6f8 Thomas Thrainer
              if not success:
1532 22b7f6f8 Thomas Thrainer
                logging.warn("pause-sync of instance %s for disk %d failed",
1533 d0d7d7cf Thomas Thrainer
                             self.op.instance_name, idx)
1534 22b7f6f8 Thomas Thrainer
1535 22b7f6f8 Thomas Thrainer
          feedback_fn("* running the instance OS create scripts...")
1536 22b7f6f8 Thomas Thrainer
          # FIXME: pass debug option from opcode to backend
1537 22b7f6f8 Thomas Thrainer
          os_add_result = \
1538 6bce7ba2 Santi Raffa
            self.rpc.call_instance_os_add(self.pnode.uuid,
1539 6bce7ba2 Santi Raffa
                                          (iobj, self.op.osparams_secret),
1540 6bce7ba2 Santi Raffa
                                          False,
1541 22b7f6f8 Thomas Thrainer
                                          self.op.debug_level)
1542 22b7f6f8 Thomas Thrainer
          if pause_sync:
1543 22b7f6f8 Thomas Thrainer
            feedback_fn("* resuming disk sync")
1544 1c3231aa Thomas Thrainer
            result = self.rpc.call_blockdev_pause_resume_sync(self.pnode.uuid,
1545 22b7f6f8 Thomas Thrainer
                                                              (iobj.disks,
1546 22b7f6f8 Thomas Thrainer
                                                               iobj), False)
1547 22b7f6f8 Thomas Thrainer
            for idx, success in enumerate(result.payload):
1548 22b7f6f8 Thomas Thrainer
              if not success:
1549 22b7f6f8 Thomas Thrainer
                logging.warn("resume-sync of instance %s for disk %d failed",
1550 d0d7d7cf Thomas Thrainer
                             self.op.instance_name, idx)
1551 22b7f6f8 Thomas Thrainer
1552 22b7f6f8 Thomas Thrainer
          os_add_result.Raise("Could not add os for instance %s"
1553 d0d7d7cf Thomas Thrainer
                              " on node %s" % (self.op.instance_name,
1554 d0d7d7cf Thomas Thrainer
                                               self.pnode.name))
1555 22b7f6f8 Thomas Thrainer
1556 22b7f6f8 Thomas Thrainer
      else:
1557 22b7f6f8 Thomas Thrainer
        if self.op.mode == constants.INSTANCE_IMPORT:
1558 22b7f6f8 Thomas Thrainer
          feedback_fn("* running the instance OS import scripts...")
1559 22b7f6f8 Thomas Thrainer
1560 22b7f6f8 Thomas Thrainer
          transfers = []
1561 22b7f6f8 Thomas Thrainer
1562 22b7f6f8 Thomas Thrainer
          for idx, image in enumerate(self.src_images):
1563 22b7f6f8 Thomas Thrainer
            if not image:
1564 22b7f6f8 Thomas Thrainer
              continue
1565 22b7f6f8 Thomas Thrainer
1566 22b7f6f8 Thomas Thrainer
            # FIXME: pass debug option from opcode to backend
1567 22b7f6f8 Thomas Thrainer
            dt = masterd.instance.DiskTransfer("disk/%s" % idx,
1568 22b7f6f8 Thomas Thrainer
                                               constants.IEIO_FILE, (image, ),
1569 22b7f6f8 Thomas Thrainer
                                               constants.IEIO_SCRIPT,
1570 0c3d9c7c Thomas Thrainer
                                               ((iobj.disks[idx], iobj), idx),
1571 22b7f6f8 Thomas Thrainer
                                               None)
1572 22b7f6f8 Thomas Thrainer
            transfers.append(dt)
1573 22b7f6f8 Thomas Thrainer
1574 22b7f6f8 Thomas Thrainer
          import_result = \
1575 22b7f6f8 Thomas Thrainer
            masterd.instance.TransferInstanceData(self, feedback_fn,
1576 1c3231aa Thomas Thrainer
                                                  self.op.src_node_uuid,
1577 1c3231aa Thomas Thrainer
                                                  self.pnode.uuid,
1578 22b7f6f8 Thomas Thrainer
                                                  self.pnode.secondary_ip,
1579 51d7ac96 Thomas Thrainer
                                                  self.op.compress,
1580 22b7f6f8 Thomas Thrainer
                                                  iobj, transfers)
1581 22b7f6f8 Thomas Thrainer
          if not compat.all(import_result):
1582 22b7f6f8 Thomas Thrainer
            self.LogWarning("Some disks for instance %s on node %s were not"
1583 d0d7d7cf Thomas Thrainer
                            " imported successfully" % (self.op.instance_name,
1584 d0d7d7cf Thomas Thrainer
                                                        self.pnode.name))
1585 22b7f6f8 Thomas Thrainer
1586 22b7f6f8 Thomas Thrainer
          rename_from = self._old_instance_name
1587 22b7f6f8 Thomas Thrainer
1588 22b7f6f8 Thomas Thrainer
        elif self.op.mode == constants.INSTANCE_REMOTE_IMPORT:
1589 22b7f6f8 Thomas Thrainer
          feedback_fn("* preparing remote import...")
1590 22b7f6f8 Thomas Thrainer
          # The source cluster will stop the instance before attempting to make
1591 22b7f6f8 Thomas Thrainer
          # a connection. In some cases stopping an instance can take a long
1592 22b7f6f8 Thomas Thrainer
          # time, hence the shutdown timeout is added to the connection
1593 22b7f6f8 Thomas Thrainer
          # timeout.
1594 22b7f6f8 Thomas Thrainer
          connect_timeout = (constants.RIE_CONNECT_TIMEOUT +
1595 22b7f6f8 Thomas Thrainer
                             self.op.source_shutdown_timeout)
1596 22b7f6f8 Thomas Thrainer
          timeouts = masterd.instance.ImportExportTimeouts(connect_timeout)
1597 22b7f6f8 Thomas Thrainer
1598 1c3231aa Thomas Thrainer
          assert iobj.primary_node == self.pnode.uuid
1599 22b7f6f8 Thomas Thrainer
          disk_results = \
1600 22b7f6f8 Thomas Thrainer
            masterd.instance.RemoteImport(self, feedback_fn, iobj, self.pnode,
1601 22b7f6f8 Thomas Thrainer
                                          self.source_x509_ca,
1602 88acff3f Thomas Thrainer
                                          self._cds, self.op.compress, timeouts)
1603 22b7f6f8 Thomas Thrainer
          if not compat.all(disk_results):
1604 22b7f6f8 Thomas Thrainer
            # TODO: Should the instance still be started, even if some disks
1605 22b7f6f8 Thomas Thrainer
            # failed to import (valid for local imports, too)?
1606 22b7f6f8 Thomas Thrainer
            self.LogWarning("Some disks for instance %s on node %s were not"
1607 d0d7d7cf Thomas Thrainer
                            " imported successfully" % (self.op.instance_name,
1608 d0d7d7cf Thomas Thrainer
                                                        self.pnode.name))
1609 22b7f6f8 Thomas Thrainer
1610 22b7f6f8 Thomas Thrainer
          rename_from = self.source_instance_name
1611 22b7f6f8 Thomas Thrainer
1612 22b7f6f8 Thomas Thrainer
        else:
1613 22b7f6f8 Thomas Thrainer
          # also checked in the prereq part
1614 22b7f6f8 Thomas Thrainer
          raise errors.ProgrammerError("Unknown OS initialization mode '%s'"
1615 22b7f6f8 Thomas Thrainer
                                       % self.op.mode)
1616 22b7f6f8 Thomas Thrainer
1617 22b7f6f8 Thomas Thrainer
        # Run rename script on newly imported instance
1618 d0d7d7cf Thomas Thrainer
        assert iobj.name == self.op.instance_name
1619 d0d7d7cf Thomas Thrainer
        feedback_fn("Running rename script for %s" % self.op.instance_name)
1620 1c3231aa Thomas Thrainer
        result = self.rpc.call_instance_run_rename(self.pnode.uuid, iobj,
1621 22b7f6f8 Thomas Thrainer
                                                   rename_from,
1622 22b7f6f8 Thomas Thrainer
                                                   self.op.debug_level)
1623 c7dd65be Klaus Aehlig
        result.Warn("Failed to run rename script for %s on node %s" %
1624 d0d7d7cf Thomas Thrainer
                    (self.op.instance_name, self.pnode.name), self.LogWarning)
1625 22b7f6f8 Thomas Thrainer
1626 22b7f6f8 Thomas Thrainer
    assert not self.owned_locks(locking.LEVEL_NODE_RES)
1627 22b7f6f8 Thomas Thrainer
1628 22b7f6f8 Thomas Thrainer
    if self.op.start:
1629 22b7f6f8 Thomas Thrainer
      iobj.admin_state = constants.ADMINST_UP
1630 22b7f6f8 Thomas Thrainer
      self.cfg.Update(iobj, feedback_fn)
1631 d0d7d7cf Thomas Thrainer
      logging.info("Starting instance %s on node %s", self.op.instance_name,
1632 d0d7d7cf Thomas Thrainer
                   self.pnode.name)
1633 22b7f6f8 Thomas Thrainer
      feedback_fn("* starting instance...")
1634 1c3231aa Thomas Thrainer
      result = self.rpc.call_instance_start(self.pnode.uuid, (iobj, None, None),
1635 22b7f6f8 Thomas Thrainer
                                            False, self.op.reason)
1636 22b7f6f8 Thomas Thrainer
      result.Raise("Could not start instance")
1637 22b7f6f8 Thomas Thrainer
1638 b7a990e3 Hrvoje Ribicic
    return self.cfg.GetNodeNames(list(iobj.all_nodes))
1639 22b7f6f8 Thomas Thrainer
1640 22b7f6f8 Thomas Thrainer
1641 22b7f6f8 Thomas Thrainer
class LUInstanceRename(LogicalUnit):
1642 22b7f6f8 Thomas Thrainer
  """Rename an instance.
1643 22b7f6f8 Thomas Thrainer

1644 22b7f6f8 Thomas Thrainer
  """
1645 22b7f6f8 Thomas Thrainer
  HPATH = "instance-rename"
1646 22b7f6f8 Thomas Thrainer
  HTYPE = constants.HTYPE_INSTANCE
1647 22b7f6f8 Thomas Thrainer
1648 22b7f6f8 Thomas Thrainer
  def CheckArguments(self):
1649 22b7f6f8 Thomas Thrainer
    """Check arguments.
1650 22b7f6f8 Thomas Thrainer

1651 22b7f6f8 Thomas Thrainer
    """
1652 22b7f6f8 Thomas Thrainer
    if self.op.ip_check and not self.op.name_check:
1653 22b7f6f8 Thomas Thrainer
      # TODO: make the ip check more flexible and not depend on the name check
1654 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("IP address check requires a name check",
1655 22b7f6f8 Thomas Thrainer
                                 errors.ECODE_INVAL)
1656 22b7f6f8 Thomas Thrainer
1657 22b7f6f8 Thomas Thrainer
  def BuildHooksEnv(self):
1658 22b7f6f8 Thomas Thrainer
    """Build hooks env.
1659 22b7f6f8 Thomas Thrainer

1660 22b7f6f8 Thomas Thrainer
    This runs on master, primary and secondary nodes of the instance.
1661 22b7f6f8 Thomas Thrainer

1662 22b7f6f8 Thomas Thrainer
    """
1663 5eacbcae Thomas Thrainer
    env = BuildInstanceHookEnvByObject(self, self.instance)
1664 22b7f6f8 Thomas Thrainer
    env["INSTANCE_NEW_NAME"] = self.op.new_name
1665 22b7f6f8 Thomas Thrainer
    return env
1666 22b7f6f8 Thomas Thrainer
1667 22b7f6f8 Thomas Thrainer
  def BuildHooksNodes(self):
1668 22b7f6f8 Thomas Thrainer
    """Build hooks nodes.
1669 22b7f6f8 Thomas Thrainer

1670 22b7f6f8 Thomas Thrainer
    """
1671 22b7f6f8 Thomas Thrainer
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
1672 22b7f6f8 Thomas Thrainer
    return (nl, nl)
1673 22b7f6f8 Thomas Thrainer
1674 22b7f6f8 Thomas Thrainer
  def CheckPrereq(self):
1675 22b7f6f8 Thomas Thrainer
    """Check prerequisites.
1676 22b7f6f8 Thomas Thrainer

1677 22b7f6f8 Thomas Thrainer
    This checks that the instance is in the cluster and is not running.
1678 22b7f6f8 Thomas Thrainer

1679 22b7f6f8 Thomas Thrainer
    """
1680 da4a52a3 Thomas Thrainer
    (self.op.instance_uuid, self.op.instance_name) = \
1681 da4a52a3 Thomas Thrainer
      ExpandInstanceUuidAndName(self.cfg, self.op.instance_uuid,
1682 da4a52a3 Thomas Thrainer
                                self.op.instance_name)
1683 da4a52a3 Thomas Thrainer
    instance = self.cfg.GetInstanceInfo(self.op.instance_uuid)
1684 22b7f6f8 Thomas Thrainer
    assert instance is not None
1685 1f7c8208 Helga Velroyen
1686 1f7c8208 Helga Velroyen
    # It should actually not happen that an instance is running with a disabled
1687 1f7c8208 Helga Velroyen
    # disk template, but in case it does, the renaming of file-based instances
1688 1f7c8208 Helga Velroyen
    # will fail horribly. Thus, we test it before.
1689 1f7c8208 Helga Velroyen
    if (instance.disk_template in constants.DTS_FILEBASED and
1690 1f7c8208 Helga Velroyen
        self.op.new_name != instance.name):
1691 1f7c8208 Helga Velroyen
      CheckDiskTemplateEnabled(self.cfg.GetClusterInfo(),
1692 1f7c8208 Helga Velroyen
                               instance.disk_template)
1693 1f7c8208 Helga Velroyen
1694 5eacbcae Thomas Thrainer
    CheckNodeOnline(self, instance.primary_node)
1695 5eacbcae Thomas Thrainer
    CheckInstanceState(self, instance, INSTANCE_NOT_RUNNING,
1696 5eacbcae Thomas Thrainer
                       msg="cannot rename")
1697 22b7f6f8 Thomas Thrainer
    self.instance = instance
1698 22b7f6f8 Thomas Thrainer
1699 22b7f6f8 Thomas Thrainer
    new_name = self.op.new_name
1700 22b7f6f8 Thomas Thrainer
    if self.op.name_check:
1701 22b7f6f8 Thomas Thrainer
      hostname = _CheckHostnameSane(self, new_name)
1702 22b7f6f8 Thomas Thrainer
      new_name = self.op.new_name = hostname.name
1703 22b7f6f8 Thomas Thrainer
      if (self.op.ip_check and
1704 22b7f6f8 Thomas Thrainer
          netutils.TcpPing(hostname.ip, constants.DEFAULT_NODED_PORT)):
1705 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("IP %s of instance %s already in use" %
1706 22b7f6f8 Thomas Thrainer
                                   (hostname.ip, new_name),
1707 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_NOTUNIQUE)
1708 22b7f6f8 Thomas Thrainer
1709 da4a52a3 Thomas Thrainer
    instance_names = [inst.name for
1710 da4a52a3 Thomas Thrainer
                      inst in self.cfg.GetAllInstancesInfo().values()]
1711 da4a52a3 Thomas Thrainer
    if new_name in instance_names and new_name != instance.name:
1712 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
1713 22b7f6f8 Thomas Thrainer
                                 new_name, errors.ECODE_EXISTS)
1714 22b7f6f8 Thomas Thrainer
1715 22b7f6f8 Thomas Thrainer
  def Exec(self, feedback_fn):
1716 22b7f6f8 Thomas Thrainer
    """Rename the instance.
1717 22b7f6f8 Thomas Thrainer

1718 22b7f6f8 Thomas Thrainer
    """
1719 d0d7d7cf Thomas Thrainer
    old_name = self.instance.name
1720 22b7f6f8 Thomas Thrainer
1721 22b7f6f8 Thomas Thrainer
    rename_file_storage = False
1722 845b7ed1 Santi Raffa
    if (self.instance.disk_template in (constants.DT_FILE,
1723 845b7ed1 Santi Raffa
                                        constants.DT_SHARED_FILE) and
1724 d0d7d7cf Thomas Thrainer
        self.op.new_name != self.instance.name):
1725 d0d7d7cf Thomas Thrainer
      old_file_storage_dir = os.path.dirname(
1726 d0d7d7cf Thomas Thrainer
                               self.instance.disks[0].logical_id[1])
1727 22b7f6f8 Thomas Thrainer
      rename_file_storage = True
1728 22b7f6f8 Thomas Thrainer
1729 da4a52a3 Thomas Thrainer
    self.cfg.RenameInstance(self.instance.uuid, self.op.new_name)
1730 22b7f6f8 Thomas Thrainer
    # Change the instance lock. This is definitely safe while we hold the BGL.
1731 22b7f6f8 Thomas Thrainer
    # Otherwise the new lock would have to be added in acquired mode.
1732 22b7f6f8 Thomas Thrainer
    assert self.REQ_BGL
1733 22b7f6f8 Thomas Thrainer
    assert locking.BGL in self.owned_locks(locking.LEVEL_CLUSTER)
1734 22b7f6f8 Thomas Thrainer
1735 22b7f6f8 Thomas Thrainer
    # re-read the instance from the configuration after rename
1736 da4a52a3 Thomas Thrainer
    renamed_inst = self.cfg.GetInstanceInfo(self.instance.uuid)
1737 22b7f6f8 Thomas Thrainer
1738 22b7f6f8 Thomas Thrainer
    if rename_file_storage:
1739 d0d7d7cf Thomas Thrainer
      new_file_storage_dir = os.path.dirname(
1740 d0d7d7cf Thomas Thrainer
                               renamed_inst.disks[0].logical_id[1])
1741 d0d7d7cf Thomas Thrainer
      result = self.rpc.call_file_storage_dir_rename(renamed_inst.primary_node,
1742 22b7f6f8 Thomas Thrainer
                                                     old_file_storage_dir,
1743 22b7f6f8 Thomas Thrainer
                                                     new_file_storage_dir)
1744 22b7f6f8 Thomas Thrainer
      result.Raise("Could not rename on node %s directory '%s' to '%s'"
1745 22b7f6f8 Thomas Thrainer
                   " (but the instance has been renamed in Ganeti)" %
1746 d0d7d7cf Thomas Thrainer
                   (self.cfg.GetNodeName(renamed_inst.primary_node),
1747 1c3231aa Thomas Thrainer
                    old_file_storage_dir, new_file_storage_dir))
1748 22b7f6f8 Thomas Thrainer
1749 d0d7d7cf Thomas Thrainer
    StartInstanceDisks(self, renamed_inst, None)
1750 22b7f6f8 Thomas Thrainer
    # update info on disks
1751 d0d7d7cf Thomas Thrainer
    info = GetInstanceInfoText(renamed_inst)
1752 d0d7d7cf Thomas Thrainer
    for (idx, disk) in enumerate(renamed_inst.disks):
1753 d0d7d7cf Thomas Thrainer
      for node_uuid in renamed_inst.all_nodes:
1754 0c3d9c7c Thomas Thrainer
        result = self.rpc.call_blockdev_setinfo(node_uuid,
1755 0c3d9c7c Thomas Thrainer
                                                (disk, renamed_inst), info)
1756 1c3231aa Thomas Thrainer
        result.Warn("Error setting info on node %s for disk %s" %
1757 1c3231aa Thomas Thrainer
                    (self.cfg.GetNodeName(node_uuid), idx), self.LogWarning)
1758 22b7f6f8 Thomas Thrainer
    try:
1759 d0d7d7cf Thomas Thrainer
      result = self.rpc.call_instance_run_rename(renamed_inst.primary_node,
1760 d0d7d7cf Thomas Thrainer
                                                 renamed_inst, old_name,
1761 d0d7d7cf Thomas Thrainer
                                                 self.op.debug_level)
1762 c7dd65be Klaus Aehlig
      result.Warn("Could not run OS rename script for instance %s on node %s"
1763 c7dd65be Klaus Aehlig
                  " (but the instance has been renamed in Ganeti)" %
1764 d0d7d7cf Thomas Thrainer
                  (renamed_inst.name,
1765 d0d7d7cf Thomas Thrainer
                   self.cfg.GetNodeName(renamed_inst.primary_node)),
1766 1c3231aa Thomas Thrainer
                  self.LogWarning)
1767 22b7f6f8 Thomas Thrainer
    finally:
1768 d0d7d7cf Thomas Thrainer
      ShutdownInstanceDisks(self, renamed_inst)
1769 22b7f6f8 Thomas Thrainer
1770 d0d7d7cf Thomas Thrainer
    return renamed_inst.name
1771 22b7f6f8 Thomas Thrainer
1772 22b7f6f8 Thomas Thrainer
1773 22b7f6f8 Thomas Thrainer
class LUInstanceRemove(LogicalUnit):
1774 22b7f6f8 Thomas Thrainer
  """Remove an instance.
1775 22b7f6f8 Thomas Thrainer

1776 22b7f6f8 Thomas Thrainer
  """
1777 22b7f6f8 Thomas Thrainer
  HPATH = "instance-remove"
1778 22b7f6f8 Thomas Thrainer
  HTYPE = constants.HTYPE_INSTANCE
1779 22b7f6f8 Thomas Thrainer
  REQ_BGL = False
1780 22b7f6f8 Thomas Thrainer
1781 22b7f6f8 Thomas Thrainer
  def ExpandNames(self):
1782 22b7f6f8 Thomas Thrainer
    self._ExpandAndLockInstance()
1783 22b7f6f8 Thomas Thrainer
    self.needed_locks[locking.LEVEL_NODE] = []
1784 22b7f6f8 Thomas Thrainer
    self.needed_locks[locking.LEVEL_NODE_RES] = []
1785 22b7f6f8 Thomas Thrainer
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
1786 22b7f6f8 Thomas Thrainer
1787 22b7f6f8 Thomas Thrainer
  def DeclareLocks(self, level):
1788 22b7f6f8 Thomas Thrainer
    if level == locking.LEVEL_NODE:
1789 22b7f6f8 Thomas Thrainer
      self._LockInstancesNodes()
1790 22b7f6f8 Thomas Thrainer
    elif level == locking.LEVEL_NODE_RES:
1791 22b7f6f8 Thomas Thrainer
      # Copy node locks
1792 22b7f6f8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE_RES] = \
1793 5eacbcae Thomas Thrainer
        CopyLockList(self.needed_locks[locking.LEVEL_NODE])
1794 22b7f6f8 Thomas Thrainer
1795 22b7f6f8 Thomas Thrainer
  def BuildHooksEnv(self):
1796 22b7f6f8 Thomas Thrainer
    """Build hooks env.
1797 22b7f6f8 Thomas Thrainer

1798 22b7f6f8 Thomas Thrainer
    This runs on master, primary and secondary nodes of the instance.
1799 22b7f6f8 Thomas Thrainer

1800 22b7f6f8 Thomas Thrainer
    """
1801 5eacbcae Thomas Thrainer
    env = BuildInstanceHookEnvByObject(self, self.instance)
1802 22b7f6f8 Thomas Thrainer
    env["SHUTDOWN_TIMEOUT"] = self.op.shutdown_timeout
1803 22b7f6f8 Thomas Thrainer
    return env
1804 22b7f6f8 Thomas Thrainer
1805 22b7f6f8 Thomas Thrainer
  def BuildHooksNodes(self):
1806 22b7f6f8 Thomas Thrainer
    """Build hooks nodes.
1807 22b7f6f8 Thomas Thrainer

1808 22b7f6f8 Thomas Thrainer
    """
1809 22b7f6f8 Thomas Thrainer
    nl = [self.cfg.GetMasterNode()]
1810 22b7f6f8 Thomas Thrainer
    nl_post = list(self.instance.all_nodes) + nl
1811 22b7f6f8 Thomas Thrainer
    return (nl, nl_post)
1812 22b7f6f8 Thomas Thrainer
1813 22b7f6f8 Thomas Thrainer
  def CheckPrereq(self):
1814 22b7f6f8 Thomas Thrainer
    """Check prerequisites.
1815 22b7f6f8 Thomas Thrainer

1816 22b7f6f8 Thomas Thrainer
    This checks that the instance is in the cluster.
1817 22b7f6f8 Thomas Thrainer

1818 22b7f6f8 Thomas Thrainer
    """
1819 da4a52a3 Thomas Thrainer
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_uuid)
1820 22b7f6f8 Thomas Thrainer
    assert self.instance is not None, \
1821 22b7f6f8 Thomas Thrainer
      "Cannot retrieve locked instance %s" % self.op.instance_name
1822 22b7f6f8 Thomas Thrainer
1823 22b7f6f8 Thomas Thrainer
  def Exec(self, feedback_fn):
1824 22b7f6f8 Thomas Thrainer
    """Remove the instance.
1825 22b7f6f8 Thomas Thrainer

1826 22b7f6f8 Thomas Thrainer
    """
1827 d0d7d7cf Thomas Thrainer
    logging.info("Shutting down instance %s on node %s", self.instance.name,
1828 d0d7d7cf Thomas Thrainer
                 self.cfg.GetNodeName(self.instance.primary_node))
1829 22b7f6f8 Thomas Thrainer
1830 d0d7d7cf Thomas Thrainer
    result = self.rpc.call_instance_shutdown(self.instance.primary_node,
1831 d0d7d7cf Thomas Thrainer
                                             self.instance,
1832 22b7f6f8 Thomas Thrainer
                                             self.op.shutdown_timeout,
1833 22b7f6f8 Thomas Thrainer
                                             self.op.reason)
1834 c7dd65be Klaus Aehlig
    if self.op.ignore_failures:
1835 c7dd65be Klaus Aehlig
      result.Warn("Warning: can't shutdown instance", feedback_fn)
1836 c7dd65be Klaus Aehlig
    else:
1837 c7dd65be Klaus Aehlig
      result.Raise("Could not shutdown instance %s on node %s" %
1838 d0d7d7cf Thomas Thrainer
                   (self.instance.name,
1839 d0d7d7cf Thomas Thrainer
                    self.cfg.GetNodeName(self.instance.primary_node)))
1840 22b7f6f8 Thomas Thrainer
1841 22b7f6f8 Thomas Thrainer
    assert (self.owned_locks(locking.LEVEL_NODE) ==
1842 22b7f6f8 Thomas Thrainer
            self.owned_locks(locking.LEVEL_NODE_RES))
1843 d0d7d7cf Thomas Thrainer
    assert not (set(self.instance.all_nodes) -
1844 22b7f6f8 Thomas Thrainer
                self.owned_locks(locking.LEVEL_NODE)), \
1845 22b7f6f8 Thomas Thrainer
      "Not owning correct locks"
1846 22b7f6f8 Thomas Thrainer
1847 d0d7d7cf Thomas Thrainer
    RemoveInstance(self, feedback_fn, self.instance, self.op.ignore_failures)
1848 22b7f6f8 Thomas Thrainer
1849 22b7f6f8 Thomas Thrainer
1850 22b7f6f8 Thomas Thrainer
class LUInstanceMove(LogicalUnit):
1851 22b7f6f8 Thomas Thrainer
  """Move an instance by data-copying.
1852 22b7f6f8 Thomas Thrainer

1853 22b7f6f8 Thomas Thrainer
  """
1854 22b7f6f8 Thomas Thrainer
  HPATH = "instance-move"
1855 22b7f6f8 Thomas Thrainer
  HTYPE = constants.HTYPE_INSTANCE
1856 22b7f6f8 Thomas Thrainer
  REQ_BGL = False
1857 22b7f6f8 Thomas Thrainer
1858 22b7f6f8 Thomas Thrainer
  def ExpandNames(self):
1859 22b7f6f8 Thomas Thrainer
    self._ExpandAndLockInstance()
1860 1c3231aa Thomas Thrainer
    (self.op.target_node_uuid, self.op.target_node) = \
1861 1c3231aa Thomas Thrainer
      ExpandNodeUuidAndName(self.cfg, self.op.target_node_uuid,
1862 1c3231aa Thomas Thrainer
                            self.op.target_node)
1863 b9aae98b Thomas Thrainer
    self.needed_locks[locking.LEVEL_NODE] = [self.op.target_node_uuid]
1864 22b7f6f8 Thomas Thrainer
    self.needed_locks[locking.LEVEL_NODE_RES] = []
1865 22b7f6f8 Thomas Thrainer
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
1866 22b7f6f8 Thomas Thrainer
1867 22b7f6f8 Thomas Thrainer
  def DeclareLocks(self, level):
1868 22b7f6f8 Thomas Thrainer
    if level == locking.LEVEL_NODE:
1869 22b7f6f8 Thomas Thrainer
      self._LockInstancesNodes(primary_only=True)
1870 22b7f6f8 Thomas Thrainer
    elif level == locking.LEVEL_NODE_RES:
1871 22b7f6f8 Thomas Thrainer
      # Copy node locks
1872 22b7f6f8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE_RES] = \
1873 5eacbcae Thomas Thrainer
        CopyLockList(self.needed_locks[locking.LEVEL_NODE])
1874 22b7f6f8 Thomas Thrainer
1875 22b7f6f8 Thomas Thrainer
  def BuildHooksEnv(self):
1876 22b7f6f8 Thomas Thrainer
    """Build hooks env.
1877 22b7f6f8 Thomas Thrainer

1878 83266db6 Thomas Thrainer
    This runs on master, primary and target nodes of the instance.
1879 22b7f6f8 Thomas Thrainer

1880 22b7f6f8 Thomas Thrainer
    """
1881 22b7f6f8 Thomas Thrainer
    env = {
1882 22b7f6f8 Thomas Thrainer
      "TARGET_NODE": self.op.target_node,
1883 22b7f6f8 Thomas Thrainer
      "SHUTDOWN_TIMEOUT": self.op.shutdown_timeout,
1884 22b7f6f8 Thomas Thrainer
      }
1885 5eacbcae Thomas Thrainer
    env.update(BuildInstanceHookEnvByObject(self, self.instance))
1886 22b7f6f8 Thomas Thrainer
    return env
1887 22b7f6f8 Thomas Thrainer
1888 22b7f6f8 Thomas Thrainer
  def BuildHooksNodes(self):
1889 22b7f6f8 Thomas Thrainer
    """Build hooks nodes.
1890 22b7f6f8 Thomas Thrainer

1891 22b7f6f8 Thomas Thrainer
    """
1892 22b7f6f8 Thomas Thrainer
    nl = [
1893 22b7f6f8 Thomas Thrainer
      self.cfg.GetMasterNode(),
1894 22b7f6f8 Thomas Thrainer
      self.instance.primary_node,
1895 1c3231aa Thomas Thrainer
      self.op.target_node_uuid,
1896 22b7f6f8 Thomas Thrainer
      ]
1897 22b7f6f8 Thomas Thrainer
    return (nl, nl)
1898 22b7f6f8 Thomas Thrainer
1899 22b7f6f8 Thomas Thrainer
  def CheckPrereq(self):
1900 22b7f6f8 Thomas Thrainer
    """Check prerequisites.
1901 22b7f6f8 Thomas Thrainer

1902 22b7f6f8 Thomas Thrainer
    This checks that the instance is in the cluster.
1903 22b7f6f8 Thomas Thrainer

1904 22b7f6f8 Thomas Thrainer
    """
1905 da4a52a3 Thomas Thrainer
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_uuid)
1906 22b7f6f8 Thomas Thrainer
    assert self.instance is not None, \
1907 22b7f6f8 Thomas Thrainer
      "Cannot retrieve locked instance %s" % self.op.instance_name
1908 22b7f6f8 Thomas Thrainer
1909 d0d7d7cf Thomas Thrainer
    if self.instance.disk_template not in constants.DTS_COPYABLE:
1910 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Disk template %s not suitable for copying" %
1911 d0d7d7cf Thomas Thrainer
                                 self.instance.disk_template,
1912 d0d7d7cf Thomas Thrainer
                                 errors.ECODE_STATE)
1913 22b7f6f8 Thomas Thrainer
1914 1c3231aa Thomas Thrainer
    target_node = self.cfg.GetNodeInfo(self.op.target_node_uuid)
1915 1c3231aa Thomas Thrainer
    assert target_node is not None, \
1916 22b7f6f8 Thomas Thrainer
      "Cannot retrieve locked node %s" % self.op.target_node
1917 22b7f6f8 Thomas Thrainer
1918 1c3231aa Thomas Thrainer
    self.target_node_uuid = target_node.uuid
1919 d0d7d7cf Thomas Thrainer
    if target_node.uuid == self.instance.primary_node:
1920 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Instance %s is already on the node %s" %
1921 d0d7d7cf Thomas Thrainer
                                 (self.instance.name, target_node.name),
1922 22b7f6f8 Thomas Thrainer
                                 errors.ECODE_STATE)
1923 22b7f6f8 Thomas Thrainer
1924 d29f52a6 Thomas Thrainer
    cluster = self.cfg.GetClusterInfo()
1925 d29f52a6 Thomas Thrainer
    bep = cluster.FillBE(self.instance)
1926 22b7f6f8 Thomas Thrainer
1927 d0d7d7cf Thomas Thrainer
    for idx, dsk in enumerate(self.instance.disks):
1928 cd3b4ff4 Helga Velroyen
      if dsk.dev_type not in (constants.DT_PLAIN, constants.DT_FILE,
1929 8106dd64 Santi Raffa
                              constants.DT_SHARED_FILE, constants.DT_GLUSTER):
1930 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Instance disk %d has a complex layout,"
1931 22b7f6f8 Thomas Thrainer
                                   " cannot copy" % idx, errors.ECODE_STATE)
1932 22b7f6f8 Thomas Thrainer
1933 1c3231aa Thomas Thrainer
    CheckNodeOnline(self, target_node.uuid)
1934 1c3231aa Thomas Thrainer
    CheckNodeNotDrained(self, target_node.uuid)
1935 1c3231aa Thomas Thrainer
    CheckNodeVmCapable(self, target_node.uuid)
1936 1c3231aa Thomas Thrainer
    group_info = self.cfg.GetNodeGroup(target_node.group)
1937 22b7f6f8 Thomas Thrainer
    ipolicy = ganeti.masterd.instance.CalculateGroupIPolicy(cluster, group_info)
1938 d0d7d7cf Thomas Thrainer
    CheckTargetNodeIPolicy(self, ipolicy, self.instance, target_node, self.cfg,
1939 5eacbcae Thomas Thrainer
                           ignore=self.op.ignore_ipolicy)
1940 22b7f6f8 Thomas Thrainer
1941 d0d7d7cf Thomas Thrainer
    if self.instance.admin_state == constants.ADMINST_UP:
1942 83266db6 Thomas Thrainer
      # check memory requirements on the target node
1943 a295eb80 Helga Velroyen
      CheckNodeFreeMemory(
1944 1c3231aa Thomas Thrainer
          self, target_node.uuid, "failing over instance %s" %
1945 d0d7d7cf Thomas Thrainer
          self.instance.name, bep[constants.BE_MAXMEM],
1946 d0d7d7cf Thomas Thrainer
          self.instance.hypervisor,
1947 d29f52a6 Thomas Thrainer
          cluster.hvparams[self.instance.hypervisor])
1948 22b7f6f8 Thomas Thrainer
    else:
1949 22b7f6f8 Thomas Thrainer
      self.LogInfo("Not checking memory on the secondary node as"
1950 22b7f6f8 Thomas Thrainer
                   " instance will not be started")
1951 22b7f6f8 Thomas Thrainer
1952 22b7f6f8 Thomas Thrainer
    # check bridge existance
1953 d0d7d7cf Thomas Thrainer
    CheckInstanceBridgesExist(self, self.instance, node_uuid=target_node.uuid)
1954 22b7f6f8 Thomas Thrainer
1955 22b7f6f8 Thomas Thrainer
  def Exec(self, feedback_fn):
1956 22b7f6f8 Thomas Thrainer
    """Move an instance.
1957 22b7f6f8 Thomas Thrainer

1958 22b7f6f8 Thomas Thrainer
    The move is done by shutting it down on its present node, copying
1959 22b7f6f8 Thomas Thrainer
    the data over (slow) and starting it on the new node.
1960 22b7f6f8 Thomas Thrainer

1961 22b7f6f8 Thomas Thrainer
    """
1962 d0d7d7cf Thomas Thrainer
    source_node = self.cfg.GetNodeInfo(self.instance.primary_node)
1963 1c3231aa Thomas Thrainer
    target_node = self.cfg.GetNodeInfo(self.target_node_uuid)
1964 22b7f6f8 Thomas Thrainer
1965 22b7f6f8 Thomas Thrainer
    self.LogInfo("Shutting down instance %s on source node %s",
1966 d0d7d7cf Thomas Thrainer
                 self.instance.name, source_node.name)
1967 22b7f6f8 Thomas Thrainer
1968 22b7f6f8 Thomas Thrainer
    assert (self.owned_locks(locking.LEVEL_NODE) ==
1969 22b7f6f8 Thomas Thrainer
            self.owned_locks(locking.LEVEL_NODE_RES))
1970 22b7f6f8 Thomas Thrainer
1971 d0d7d7cf Thomas Thrainer
    result = self.rpc.call_instance_shutdown(source_node.uuid, self.instance,
1972 22b7f6f8 Thomas Thrainer
                                             self.op.shutdown_timeout,
1973 22b7f6f8 Thomas Thrainer
                                             self.op.reason)
1974 c7dd65be Klaus Aehlig
    if self.op.ignore_consistency:
1975 c7dd65be Klaus Aehlig
      result.Warn("Could not shutdown instance %s on node %s. Proceeding"
1976 c7dd65be Klaus Aehlig
                  " anyway. Please make sure node %s is down. Error details" %
1977 d0d7d7cf Thomas Thrainer
                  (self.instance.name, source_node.name, source_node.name),
1978 1c3231aa Thomas Thrainer
                  self.LogWarning)
1979 c7dd65be Klaus Aehlig
    else:
1980 c7dd65be Klaus Aehlig
      result.Raise("Could not shutdown instance %s on node %s" %
1981 d0d7d7cf Thomas Thrainer
                   (self.instance.name, source_node.name))
1982 22b7f6f8 Thomas Thrainer
1983 22b7f6f8 Thomas Thrainer
    # create the target disks
1984 22b7f6f8 Thomas Thrainer
    try:
1985 d0d7d7cf Thomas Thrainer
      CreateDisks(self, self.instance, target_node_uuid=target_node.uuid)
1986 22b7f6f8 Thomas Thrainer
    except errors.OpExecError:
1987 22b7f6f8 Thomas Thrainer
      self.LogWarning("Device creation failed")
1988 da4a52a3 Thomas Thrainer
      self.cfg.ReleaseDRBDMinors(self.instance.uuid)
1989 22b7f6f8 Thomas Thrainer
      raise
1990 22b7f6f8 Thomas Thrainer
1991 22b7f6f8 Thomas Thrainer
    errs = []
1992 063613aa Thomas Thrainer
    transfers = []
1993 063613aa Thomas Thrainer
    # activate, get path, create transfer jobs
1994 d0d7d7cf Thomas Thrainer
    for idx, disk in enumerate(self.instance.disks):
1995 063613aa Thomas Thrainer
      # FIXME: pass debug option from opcode to backend
1996 063613aa Thomas Thrainer
      dt = masterd.instance.DiskTransfer("disk/%s" % idx,
1997 063613aa Thomas Thrainer
                                         constants.IEIO_RAW_DISK,
1998 063613aa Thomas Thrainer
                                         (disk, self.instance),
1999 063613aa Thomas Thrainer
                                         constants.IEIO_RAW_DISK,
2000 063613aa Thomas Thrainer
                                         (disk, self.instance),
2001 063613aa Thomas Thrainer
                                         None)
2002 063613aa Thomas Thrainer
      transfers.append(dt)
2003 063613aa Thomas Thrainer
2004 063613aa Thomas Thrainer
    import_result = \
2005 063613aa Thomas Thrainer
      masterd.instance.TransferInstanceData(self, feedback_fn,
2006 063613aa Thomas Thrainer
                                            source_node.uuid,
2007 063613aa Thomas Thrainer
                                            target_node.uuid,
2008 063613aa Thomas Thrainer
                                            target_node.secondary_ip,
2009 f198cf91 Thomas Thrainer
                                            self.op.compress,
2010 063613aa Thomas Thrainer
                                            self.instance, transfers)
2011 063613aa Thomas Thrainer
    if not compat.all(import_result):
2012 063613aa Thomas Thrainer
      errs.append("Failed to transfer instance data")
2013 22b7f6f8 Thomas Thrainer
2014 22b7f6f8 Thomas Thrainer
    if errs:
2015 22b7f6f8 Thomas Thrainer
      self.LogWarning("Some disks failed to copy, aborting")
2016 22b7f6f8 Thomas Thrainer
      try:
2017 d0d7d7cf Thomas Thrainer
        RemoveDisks(self, self.instance, target_node_uuid=target_node.uuid)
2018 22b7f6f8 Thomas Thrainer
      finally:
2019 da4a52a3 Thomas Thrainer
        self.cfg.ReleaseDRBDMinors(self.instance.uuid)
2020 22b7f6f8 Thomas Thrainer
        raise errors.OpExecError("Errors during disk copy: %s" %
2021 22b7f6f8 Thomas Thrainer
                                 (",".join(errs),))
2022 22b7f6f8 Thomas Thrainer
2023 d0d7d7cf Thomas Thrainer
    self.instance.primary_node = target_node.uuid
2024 d0d7d7cf Thomas Thrainer
    self.cfg.Update(self.instance, feedback_fn)
2025 22b7f6f8 Thomas Thrainer
2026 22b7f6f8 Thomas Thrainer
    self.LogInfo("Removing the disks on the original node")
2027 d0d7d7cf Thomas Thrainer
    RemoveDisks(self, self.instance, target_node_uuid=source_node.uuid)
2028 22b7f6f8 Thomas Thrainer
2029 22b7f6f8 Thomas Thrainer
    # Only start the instance if it's marked as up
2030 d0d7d7cf Thomas Thrainer
    if self.instance.admin_state == constants.ADMINST_UP:
2031 22b7f6f8 Thomas Thrainer
      self.LogInfo("Starting instance %s on node %s",
2032 d0d7d7cf Thomas Thrainer
                   self.instance.name, target_node.name)
2033 22b7f6f8 Thomas Thrainer
2034 d0d7d7cf Thomas Thrainer
      disks_ok, _ = AssembleInstanceDisks(self, self.instance,
2035 5eacbcae Thomas Thrainer
                                          ignore_secondaries=True)
2036 22b7f6f8 Thomas Thrainer
      if not disks_ok:
2037 d0d7d7cf Thomas Thrainer
        ShutdownInstanceDisks(self, self.instance)
2038 22b7f6f8 Thomas Thrainer
        raise errors.OpExecError("Can't activate the instance's disks")
2039 22b7f6f8 Thomas Thrainer
2040 1c3231aa Thomas Thrainer
      result = self.rpc.call_instance_start(target_node.uuid,
2041 d0d7d7cf Thomas Thrainer
                                            (self.instance, None, None), False,
2042 22b7f6f8 Thomas Thrainer
                                            self.op.reason)
2043 22b7f6f8 Thomas Thrainer
      msg = result.fail_msg
2044 22b7f6f8 Thomas Thrainer
      if msg:
2045 d0d7d7cf Thomas Thrainer
        ShutdownInstanceDisks(self, self.instance)
2046 22b7f6f8 Thomas Thrainer
        raise errors.OpExecError("Could not start instance %s on node %s: %s" %
2047 d0d7d7cf Thomas Thrainer
                                 (self.instance.name, target_node.name, msg))
2048 22b7f6f8 Thomas Thrainer
2049 22b7f6f8 Thomas Thrainer
2050 22b7f6f8 Thomas Thrainer
class LUInstanceMultiAlloc(NoHooksLU):
2051 22b7f6f8 Thomas Thrainer
  """Allocates multiple instances at the same time.
2052 22b7f6f8 Thomas Thrainer

2053 22b7f6f8 Thomas Thrainer
  """
2054 22b7f6f8 Thomas Thrainer
  REQ_BGL = False
2055 22b7f6f8 Thomas Thrainer
2056 22b7f6f8 Thomas Thrainer
  def CheckArguments(self):
2057 22b7f6f8 Thomas Thrainer
    """Check arguments.
2058 22b7f6f8 Thomas Thrainer

2059 22b7f6f8 Thomas Thrainer
    """
2060 22b7f6f8 Thomas Thrainer
    nodes = []
2061 22b7f6f8 Thomas Thrainer
    for inst in self.op.instances:
2062 22b7f6f8 Thomas Thrainer
      if inst.iallocator is not None:
2063 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("iallocator are not allowed to be set on"
2064 22b7f6f8 Thomas Thrainer
                                   " instance objects", errors.ECODE_INVAL)
2065 22b7f6f8 Thomas Thrainer
      nodes.append(bool(inst.pnode))
2066 22b7f6f8 Thomas Thrainer
      if inst.disk_template in constants.DTS_INT_MIRROR:
2067 22b7f6f8 Thomas Thrainer
        nodes.append(bool(inst.snode))
2068 22b7f6f8 Thomas Thrainer
2069 22b7f6f8 Thomas Thrainer
    has_nodes = compat.any(nodes)
2070 22b7f6f8 Thomas Thrainer
    if compat.all(nodes) ^ has_nodes:
2071 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("There are instance objects providing"
2072 22b7f6f8 Thomas Thrainer
                                 " pnode/snode while others do not",
2073 22b7f6f8 Thomas Thrainer
                                 errors.ECODE_INVAL)
2074 22b7f6f8 Thomas Thrainer
2075 0c072225 Thomas Thrainer
    if not has_nodes and self.op.iallocator is None:
2076 22b7f6f8 Thomas Thrainer
      default_iallocator = self.cfg.GetDefaultIAllocator()
2077 0c072225 Thomas Thrainer
      if default_iallocator:
2078 22b7f6f8 Thomas Thrainer
        self.op.iallocator = default_iallocator
2079 22b7f6f8 Thomas Thrainer
      else:
2080 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("No iallocator or nodes on the instances"
2081 22b7f6f8 Thomas Thrainer
                                   " given and no cluster-wide default"
2082 22b7f6f8 Thomas Thrainer
                                   " iallocator found; please specify either"
2083 22b7f6f8 Thomas Thrainer
                                   " an iallocator or nodes on the instances"
2084 22b7f6f8 Thomas Thrainer
                                   " or set a cluster-wide default iallocator",
2085 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
2086 22b7f6f8 Thomas Thrainer
2087 22b7f6f8 Thomas Thrainer
    _CheckOpportunisticLocking(self.op)
2088 22b7f6f8 Thomas Thrainer
2089 22b7f6f8 Thomas Thrainer
    dups = utils.FindDuplicates([op.instance_name for op in self.op.instances])
2090 22b7f6f8 Thomas Thrainer
    if dups:
2091 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("There are duplicate instance names: %s" %
2092 22b7f6f8 Thomas Thrainer
                                 utils.CommaJoin(dups), errors.ECODE_INVAL)
2093 22b7f6f8 Thomas Thrainer
2094 22b7f6f8 Thomas Thrainer
  def ExpandNames(self):
2095 22b7f6f8 Thomas Thrainer
    """Calculate the locks.
2096 22b7f6f8 Thomas Thrainer

2097 22b7f6f8 Thomas Thrainer
    """
2098 5eacbcae Thomas Thrainer
    self.share_locks = ShareAll()
2099 22b7f6f8 Thomas Thrainer
    self.needed_locks = {
2100 22b7f6f8 Thomas Thrainer
      # iallocator will select nodes and even if no iallocator is used,
2101 22b7f6f8 Thomas Thrainer
      # collisions with LUInstanceCreate should be avoided
2102 22b7f6f8 Thomas Thrainer
      locking.LEVEL_NODE_ALLOC: locking.ALL_SET,
2103 22b7f6f8 Thomas Thrainer
      }
2104 22b7f6f8 Thomas Thrainer
2105 22b7f6f8 Thomas Thrainer
    if self.op.iallocator:
2106 22b7f6f8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
2107 22b7f6f8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE_RES] = locking.ALL_SET
2108 22b7f6f8 Thomas Thrainer
2109 22b7f6f8 Thomas Thrainer
      if self.op.opportunistic_locking:
2110 22b7f6f8 Thomas Thrainer
        self.opportunistic_locks[locking.LEVEL_NODE] = True
2111 22b7f6f8 Thomas Thrainer
    else:
2112 22b7f6f8 Thomas Thrainer
      nodeslist = []
2113 22b7f6f8 Thomas Thrainer
      for inst in self.op.instances:
2114 1c3231aa Thomas Thrainer
        (inst.pnode_uuid, inst.pnode) = \
2115 1c3231aa Thomas Thrainer
          ExpandNodeUuidAndName(self.cfg, inst.pnode_uuid, inst.pnode)
2116 6869f673 Thomas Thrainer
        nodeslist.append(inst.pnode_uuid)
2117 22b7f6f8 Thomas Thrainer
        if inst.snode is not None:
2118 1c3231aa Thomas Thrainer
          (inst.snode_uuid, inst.snode) = \
2119 1c3231aa Thomas Thrainer
            ExpandNodeUuidAndName(self.cfg, inst.snode_uuid, inst.snode)
2120 6869f673 Thomas Thrainer
          nodeslist.append(inst.snode_uuid)
2121 22b7f6f8 Thomas Thrainer
2122 22b7f6f8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE] = nodeslist
2123 22b7f6f8 Thomas Thrainer
      # Lock resources of instance's primary and secondary nodes (copy to
2124 22b7f6f8 Thomas Thrainer
      # prevent accidential modification)
2125 22b7f6f8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE_RES] = list(nodeslist)
2126 22b7f6f8 Thomas Thrainer
2127 4289f617 Thomas Thrainer
  def DeclareLocks(self, level):
2128 4289f617 Thomas Thrainer
    if level == locking.LEVEL_NODE_RES and \
2129 4289f617 Thomas Thrainer
      self.opportunistic_locks[locking.LEVEL_NODE]:
2130 4289f617 Thomas Thrainer
      # Even when using opportunistic locking, we require the same set of
2131 4289f617 Thomas Thrainer
      # NODE_RES locks as we got NODE locks
2132 4289f617 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE_RES] = \
2133 4289f617 Thomas Thrainer
        self.owned_locks(locking.LEVEL_NODE)
2134 4289f617 Thomas Thrainer
2135 22b7f6f8 Thomas Thrainer
  def CheckPrereq(self):
2136 22b7f6f8 Thomas Thrainer
    """Check prerequisite.
2137 22b7f6f8 Thomas Thrainer

2138 22b7f6f8 Thomas Thrainer
    """
2139 0c072225 Thomas Thrainer
    if self.op.iallocator:
2140 0c072225 Thomas Thrainer
      cluster = self.cfg.GetClusterInfo()
2141 0c072225 Thomas Thrainer
      default_vg = self.cfg.GetVGName()
2142 0c072225 Thomas Thrainer
      ec_id = self.proc.GetECId()
2143 22b7f6f8 Thomas Thrainer
2144 0c072225 Thomas Thrainer
      if self.op.opportunistic_locking:
2145 0c072225 Thomas Thrainer
        # Only consider nodes for which a lock is held
2146 804d72eb Thomas Thrainer
        node_whitelist = self.cfg.GetNodeNames(
2147 804d72eb Thomas Thrainer
                           list(self.owned_locks(locking.LEVEL_NODE)))
2148 0c072225 Thomas Thrainer
      else:
2149 0c072225 Thomas Thrainer
        node_whitelist = None
2150 22b7f6f8 Thomas Thrainer
2151 0c072225 Thomas Thrainer
      insts = [_CreateInstanceAllocRequest(op, ComputeDisks(op, default_vg),
2152 0c072225 Thomas Thrainer
                                           _ComputeNics(op, cluster, None,
2153 0c072225 Thomas Thrainer
                                                        self.cfg, ec_id),
2154 0c072225 Thomas Thrainer
                                           _ComputeFullBeParams(op, cluster),
2155 0c072225 Thomas Thrainer
                                           node_whitelist)
2156 0c072225 Thomas Thrainer
               for op in self.op.instances]
2157 22b7f6f8 Thomas Thrainer
2158 0c072225 Thomas Thrainer
      req = iallocator.IAReqMultiInstanceAlloc(instances=insts)
2159 0c072225 Thomas Thrainer
      ial = iallocator.IAllocator(self.cfg, self.rpc, req)
2160 22b7f6f8 Thomas Thrainer
2161 0c072225 Thomas Thrainer
      ial.Run(self.op.iallocator)
2162 22b7f6f8 Thomas Thrainer
2163 0c072225 Thomas Thrainer
      if not ial.success:
2164 0c072225 Thomas Thrainer
        raise errors.OpPrereqError("Can't compute nodes using"
2165 0c072225 Thomas Thrainer
                                   " iallocator '%s': %s" %
2166 0c072225 Thomas Thrainer
                                   (self.op.iallocator, ial.info),
2167 0c072225 Thomas Thrainer
                                   errors.ECODE_NORES)
2168 22b7f6f8 Thomas Thrainer
2169 0c072225 Thomas Thrainer
      self.ia_result = ial.result
2170 22b7f6f8 Thomas Thrainer
2171 22b7f6f8 Thomas Thrainer
    if self.op.dry_run:
2172 22b7f6f8 Thomas Thrainer
      self.dry_run_result = objects.FillDict(self._ConstructPartialResult(), {
2173 22b7f6f8 Thomas Thrainer
        constants.JOB_IDS_KEY: [],
2174 22b7f6f8 Thomas Thrainer
        })
2175 22b7f6f8 Thomas Thrainer
2176 22b7f6f8 Thomas Thrainer
  def _ConstructPartialResult(self):
2177 22b7f6f8 Thomas Thrainer
    """Contructs the partial result.
2178 22b7f6f8 Thomas Thrainer

2179 22b7f6f8 Thomas Thrainer
    """
2180 0c072225 Thomas Thrainer
    if self.op.iallocator:
2181 0c072225 Thomas Thrainer
      (allocatable, failed_insts) = self.ia_result
2182 0c072225 Thomas Thrainer
      allocatable_insts = map(compat.fst, allocatable)
2183 0c072225 Thomas Thrainer
    else:
2184 0c072225 Thomas Thrainer
      allocatable_insts = [op.instance_name for op in self.op.instances]
2185 0c072225 Thomas Thrainer
      failed_insts = []
2186 0c072225 Thomas Thrainer
2187 22b7f6f8 Thomas Thrainer
    return {
2188 1ca326c8 Thomas Thrainer
      constants.ALLOCATABLE_KEY: allocatable_insts,
2189 1ca326c8 Thomas Thrainer
      constants.FAILED_KEY: failed_insts,
2190 22b7f6f8 Thomas Thrainer
      }
2191 22b7f6f8 Thomas Thrainer
2192 22b7f6f8 Thomas Thrainer
  def Exec(self, feedback_fn):
2193 22b7f6f8 Thomas Thrainer
    """Executes the opcode.
2194 22b7f6f8 Thomas Thrainer

2195 22b7f6f8 Thomas Thrainer
    """
2196 22b7f6f8 Thomas Thrainer
    jobs = []
2197 0c072225 Thomas Thrainer
    if self.op.iallocator:
2198 0c072225 Thomas Thrainer
      op2inst = dict((op.instance_name, op) for op in self.op.instances)
2199 0c072225 Thomas Thrainer
      (allocatable, failed) = self.ia_result
2200 22b7f6f8 Thomas Thrainer
2201 804d72eb Thomas Thrainer
      for (name, node_names) in allocatable:
2202 0c072225 Thomas Thrainer
        op = op2inst.pop(name)
2203 22b7f6f8 Thomas Thrainer
2204 804d72eb Thomas Thrainer
        (op.pnode_uuid, op.pnode) = \
2205 804d72eb Thomas Thrainer
          ExpandNodeUuidAndName(self.cfg, None, node_names[0])
2206 804d72eb Thomas Thrainer
        if len(node_names) > 1:
2207 804d72eb Thomas Thrainer
          (op.snode_uuid, op.snode) = \
2208 804d72eb Thomas Thrainer
            ExpandNodeUuidAndName(self.cfg, None, node_names[1])
2209 22b7f6f8 Thomas Thrainer
2210 804d72eb Thomas Thrainer
          jobs.append([op])
2211 22b7f6f8 Thomas Thrainer
2212 804d72eb Thomas Thrainer
        missing = set(op2inst.keys()) - set(failed)
2213 804d72eb Thomas Thrainer
        assert not missing, \
2214 804d72eb Thomas Thrainer
          "Iallocator did return incomplete result: %s" % \
2215 804d72eb Thomas Thrainer
          utils.CommaJoin(missing)
2216 0c072225 Thomas Thrainer
    else:
2217 0c072225 Thomas Thrainer
      jobs.extend([op] for op in self.op.instances)
2218 22b7f6f8 Thomas Thrainer
2219 22b7f6f8 Thomas Thrainer
    return ResultWithJobs(jobs, **self._ConstructPartialResult())
2220 22b7f6f8 Thomas Thrainer
2221 22b7f6f8 Thomas Thrainer
2222 22b7f6f8 Thomas Thrainer
class _InstNicModPrivate:
2223 22b7f6f8 Thomas Thrainer
  """Data structure for network interface modifications.
2224 22b7f6f8 Thomas Thrainer

2225 22b7f6f8 Thomas Thrainer
  Used by L{LUInstanceSetParams}.
2226 22b7f6f8 Thomas Thrainer

2227 22b7f6f8 Thomas Thrainer
  """
2228 22b7f6f8 Thomas Thrainer
  def __init__(self):
2229 22b7f6f8 Thomas Thrainer
    self.params = None
2230 22b7f6f8 Thomas Thrainer
    self.filled = None
2231 22b7f6f8 Thomas Thrainer
2232 22b7f6f8 Thomas Thrainer
2233 5eacbcae Thomas Thrainer
def _PrepareContainerMods(mods, private_fn):
2234 22b7f6f8 Thomas Thrainer
  """Prepares a list of container modifications by adding a private data field.
2235 22b7f6f8 Thomas Thrainer

2236 22b7f6f8 Thomas Thrainer
  @type mods: list of tuples; (operation, index, parameters)
2237 22b7f6f8 Thomas Thrainer
  @param mods: List of modifications
2238 22b7f6f8 Thomas Thrainer
  @type private_fn: callable or None
2239 22b7f6f8 Thomas Thrainer
  @param private_fn: Callable for constructing a private data field for a
2240 22b7f6f8 Thomas Thrainer
    modification
2241 22b7f6f8 Thomas Thrainer
  @rtype: list
2242 22b7f6f8 Thomas Thrainer

2243 22b7f6f8 Thomas Thrainer
  """
2244 22b7f6f8 Thomas Thrainer
  if private_fn is None:
2245 22b7f6f8 Thomas Thrainer
    fn = lambda: None
2246 22b7f6f8 Thomas Thrainer
  else:
2247 22b7f6f8 Thomas Thrainer
    fn = private_fn
2248 22b7f6f8 Thomas Thrainer
2249 22b7f6f8 Thomas Thrainer
  return [(op, idx, params, fn()) for (op, idx, params) in mods]
2250 22b7f6f8 Thomas Thrainer
2251 22b7f6f8 Thomas Thrainer
2252 1c3231aa Thomas Thrainer
def _CheckNodesPhysicalCPUs(lu, node_uuids, requested, hypervisor_specs):
2253 22b7f6f8 Thomas Thrainer
  """Checks if nodes have enough physical CPUs
2254 22b7f6f8 Thomas Thrainer

2255 22b7f6f8 Thomas Thrainer
  This function checks if all given nodes have the needed number of
2256 22b7f6f8 Thomas Thrainer
  physical CPUs. In case any node has less CPUs or we cannot get the
2257 22b7f6f8 Thomas Thrainer
  information from the node, this function raises an OpPrereqError
2258 22b7f6f8 Thomas Thrainer
  exception.
2259 22b7f6f8 Thomas Thrainer

2260 22b7f6f8 Thomas Thrainer
  @type lu: C{LogicalUnit}
2261 22b7f6f8 Thomas Thrainer
  @param lu: a logical unit from which we get configuration data
2262 1c3231aa Thomas Thrainer
  @type node_uuids: C{list}
2263 1c3231aa Thomas Thrainer
  @param node_uuids: the list of node UUIDs to check
2264 22b7f6f8 Thomas Thrainer
  @type requested: C{int}
2265 22b7f6f8 Thomas Thrainer
  @param requested: the minimum acceptable number of physical CPUs
2266 a295eb80 Helga Velroyen
  @type hypervisor_specs: list of pairs (string, dict of strings)
2267 a295eb80 Helga Velroyen
  @param hypervisor_specs: list of hypervisor specifications in
2268 a295eb80 Helga Velroyen
      pairs (hypervisor_name, hvparams)
2269 22b7f6f8 Thomas Thrainer
  @raise errors.OpPrereqError: if the node doesn't have enough CPUs,
2270 22b7f6f8 Thomas Thrainer
      or we cannot check the node
2271 22b7f6f8 Thomas Thrainer

2272 22b7f6f8 Thomas Thrainer
  """
2273 da803ff1 Helga Velroyen
  nodeinfo = lu.rpc.call_node_info(node_uuids, None, hypervisor_specs)
2274 1c3231aa Thomas Thrainer
  for node_uuid in node_uuids:
2275 1c3231aa Thomas Thrainer
    info = nodeinfo[node_uuid]
2276 1c3231aa Thomas Thrainer
    node_name = lu.cfg.GetNodeName(node_uuid)
2277 1c3231aa Thomas Thrainer
    info.Raise("Cannot get current information from node %s" % node_name,
2278 22b7f6f8 Thomas Thrainer
               prereq=True, ecode=errors.ECODE_ENVIRON)
2279 22b7f6f8 Thomas Thrainer
    (_, _, (hv_info, )) = info.payload
2280 22b7f6f8 Thomas Thrainer
    num_cpus = hv_info.get("cpu_total", None)
2281 22b7f6f8 Thomas Thrainer
    if not isinstance(num_cpus, int):
2282 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Can't compute the number of physical CPUs"
2283 22b7f6f8 Thomas Thrainer
                                 " on node %s, result was '%s'" %
2284 1c3231aa Thomas Thrainer
                                 (node_name, num_cpus), errors.ECODE_ENVIRON)
2285 22b7f6f8 Thomas Thrainer
    if requested > num_cpus:
2286 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Node %s has %s physical CPUs, but %s are "
2287 1c3231aa Thomas Thrainer
                                 "required" % (node_name, num_cpus, requested),
2288 22b7f6f8 Thomas Thrainer
                                 errors.ECODE_NORES)
2289 22b7f6f8 Thomas Thrainer
2290 22b7f6f8 Thomas Thrainer
2291 22b7f6f8 Thomas Thrainer
def GetItemFromContainer(identifier, kind, container):
2292 22b7f6f8 Thomas Thrainer
  """Return the item refered by the identifier.
2293 22b7f6f8 Thomas Thrainer

2294 22b7f6f8 Thomas Thrainer
  @type identifier: string
2295 22b7f6f8 Thomas Thrainer
  @param identifier: Item index or name or UUID
2296 22b7f6f8 Thomas Thrainer
  @type kind: string
2297 22b7f6f8 Thomas Thrainer
  @param kind: One-word item description
2298 22b7f6f8 Thomas Thrainer
  @type container: list
2299 22b7f6f8 Thomas Thrainer
  @param container: Container to get the item from
2300 22b7f6f8 Thomas Thrainer

2301 22b7f6f8 Thomas Thrainer
  """
2302 22b7f6f8 Thomas Thrainer
  # Index
2303 22b7f6f8 Thomas Thrainer
  try:
2304 22b7f6f8 Thomas Thrainer
    idx = int(identifier)
2305 22b7f6f8 Thomas Thrainer
    if idx == -1:
2306 22b7f6f8 Thomas Thrainer
      # Append
2307 22b7f6f8 Thomas Thrainer
      absidx = len(container) - 1
2308 22b7f6f8 Thomas Thrainer
    elif idx < 0:
2309 22b7f6f8 Thomas Thrainer
      raise IndexError("Not accepting negative indices other than -1")
2310 22b7f6f8 Thomas Thrainer
    elif idx > len(container):
2311 22b7f6f8 Thomas Thrainer
      raise IndexError("Got %s index %s, but there are only %s" %
2312 22b7f6f8 Thomas Thrainer
                       (kind, idx, len(container)))
2313 22b7f6f8 Thomas Thrainer
    else:
2314 22b7f6f8 Thomas Thrainer
      absidx = idx
2315 22b7f6f8 Thomas Thrainer
    return (absidx, container[idx])
2316 22b7f6f8 Thomas Thrainer
  except ValueError:
2317 22b7f6f8 Thomas Thrainer
    pass
2318 22b7f6f8 Thomas Thrainer
2319 22b7f6f8 Thomas Thrainer
  for idx, item in enumerate(container):
2320 22b7f6f8 Thomas Thrainer
    if item.uuid == identifier or item.name == identifier:
2321 22b7f6f8 Thomas Thrainer
      return (idx, item)
2322 22b7f6f8 Thomas Thrainer
2323 22b7f6f8 Thomas Thrainer
  raise errors.OpPrereqError("Cannot find %s with identifier %s" %
2324 22b7f6f8 Thomas Thrainer
                             (kind, identifier), errors.ECODE_NOENT)
2325 22b7f6f8 Thomas Thrainer
2326 22b7f6f8 Thomas Thrainer
2327 5eacbcae Thomas Thrainer
def _ApplyContainerMods(kind, container, chgdesc, mods,
2328 922a9e65 Thomas Thrainer
                        create_fn, modify_fn, remove_fn,
2329 922a9e65 Thomas Thrainer
                        post_add_fn=None):
2330 22b7f6f8 Thomas Thrainer
  """Applies descriptions in C{mods} to C{container}.
2331 22b7f6f8 Thomas Thrainer

2332 22b7f6f8 Thomas Thrainer
  @type kind: string
2333 22b7f6f8 Thomas Thrainer
  @param kind: One-word item description
2334 22b7f6f8 Thomas Thrainer
  @type container: list
2335 22b7f6f8 Thomas Thrainer
  @param container: Container to modify
2336 22b7f6f8 Thomas Thrainer
  @type chgdesc: None or list
2337 22b7f6f8 Thomas Thrainer
  @param chgdesc: List of applied changes
2338 22b7f6f8 Thomas Thrainer
  @type mods: list
2339 5eacbcae Thomas Thrainer
  @param mods: Modifications as returned by L{_PrepareContainerMods}
2340 22b7f6f8 Thomas Thrainer
  @type create_fn: callable
2341 22b7f6f8 Thomas Thrainer
  @param create_fn: Callback for creating a new item (L{constants.DDM_ADD});
2342 22b7f6f8 Thomas Thrainer
    receives absolute item index, parameters and private data object as added
2343 5eacbcae Thomas Thrainer
    by L{_PrepareContainerMods}, returns tuple containing new item and changes
2344 22b7f6f8 Thomas Thrainer
    as list
2345 22b7f6f8 Thomas Thrainer
  @type modify_fn: callable
2346 22b7f6f8 Thomas Thrainer
  @param modify_fn: Callback for modifying an existing item
2347 22b7f6f8 Thomas Thrainer
    (L{constants.DDM_MODIFY}); receives absolute item index, item, parameters
2348 5eacbcae Thomas Thrainer
    and private data object as added by L{_PrepareContainerMods}, returns
2349 22b7f6f8 Thomas Thrainer
    changes as list
2350 22b7f6f8 Thomas Thrainer
  @type remove_fn: callable
2351 22b7f6f8 Thomas Thrainer
  @param remove_fn: Callback on removing item; receives absolute item index,
2352 5eacbcae Thomas Thrainer
    item and private data object as added by L{_PrepareContainerMods}
2353 922a9e65 Thomas Thrainer
  @type post_add_fn: callable
2354 922a9e65 Thomas Thrainer
  @param post_add_fn: Callable for post-processing a newly created item after
2355 922a9e65 Thomas Thrainer
    it has been put into the container. It receives the index of the new item
2356 922a9e65 Thomas Thrainer
    and the new item as parameters.
2357 22b7f6f8 Thomas Thrainer

2358 22b7f6f8 Thomas Thrainer
  """
2359 22b7f6f8 Thomas Thrainer
  for (op, identifier, params, private) in mods:
2360 22b7f6f8 Thomas Thrainer
    changes = None
2361 22b7f6f8 Thomas Thrainer
2362 22b7f6f8 Thomas Thrainer
    if op == constants.DDM_ADD:
2363 22b7f6f8 Thomas Thrainer
      # Calculate where item will be added
2364 22b7f6f8 Thomas Thrainer
      # When adding an item, identifier can only be an index
2365 22b7f6f8 Thomas Thrainer
      try:
2366 22b7f6f8 Thomas Thrainer
        idx = int(identifier)
2367 22b7f6f8 Thomas Thrainer
      except ValueError:
2368 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Only possitive integer or -1 is accepted as"
2369 22b7f6f8 Thomas Thrainer
                                   " identifier for %s" % constants.DDM_ADD,
2370 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
2371 22b7f6f8 Thomas Thrainer
      if idx == -1:
2372 22b7f6f8 Thomas Thrainer
        addidx = len(container)
2373 22b7f6f8 Thomas Thrainer
      else:
2374 22b7f6f8 Thomas Thrainer
        if idx < 0:
2375 22b7f6f8 Thomas Thrainer
          raise IndexError("Not accepting negative indices other than -1")
2376 22b7f6f8 Thomas Thrainer
        elif idx > len(container):
2377 22b7f6f8 Thomas Thrainer
          raise IndexError("Got %s index %s, but there are only %s" %
2378 22b7f6f8 Thomas Thrainer
                           (kind, idx, len(container)))
2379 22b7f6f8 Thomas Thrainer
        addidx = idx
2380 22b7f6f8 Thomas Thrainer
2381 22b7f6f8 Thomas Thrainer
      if create_fn is None:
2382 22b7f6f8 Thomas Thrainer
        item = params
2383 22b7f6f8 Thomas Thrainer
      else:
2384 22b7f6f8 Thomas Thrainer
        (item, changes) = create_fn(addidx, params, private)
2385 22b7f6f8 Thomas Thrainer
2386 22b7f6f8 Thomas Thrainer
      if idx == -1:
2387 22b7f6f8 Thomas Thrainer
        container.append(item)
2388 22b7f6f8 Thomas Thrainer
      else:
2389 22b7f6f8 Thomas Thrainer
        assert idx >= 0
2390 22b7f6f8 Thomas Thrainer
        assert idx <= len(container)
2391 22b7f6f8 Thomas Thrainer
        # list.insert does so before the specified index
2392 22b7f6f8 Thomas Thrainer
        container.insert(idx, item)
2393 922a9e65 Thomas Thrainer
2394 922a9e65 Thomas Thrainer
      if post_add_fn is not None:
2395 922a9e65 Thomas Thrainer
        post_add_fn(addidx, item)
2396 922a9e65 Thomas Thrainer
2397 22b7f6f8 Thomas Thrainer
    else:
2398 22b7f6f8 Thomas Thrainer
      # Retrieve existing item
2399 22b7f6f8 Thomas Thrainer
      (absidx, item) = GetItemFromContainer(identifier, kind, container)
2400 22b7f6f8 Thomas Thrainer
2401 22b7f6f8 Thomas Thrainer
      if op == constants.DDM_REMOVE:
2402 22b7f6f8 Thomas Thrainer
        assert not params
2403 22b7f6f8 Thomas Thrainer
2404 22b7f6f8 Thomas Thrainer
        changes = [("%s/%s" % (kind, absidx), "remove")]
2405 22b7f6f8 Thomas Thrainer
2406 e15a00dc Dimitris Aragiorgis
        if remove_fn is not None:
2407 e15a00dc Dimitris Aragiorgis
          msg = remove_fn(absidx, item, private)
2408 e15a00dc Dimitris Aragiorgis
          if msg:
2409 e15a00dc Dimitris Aragiorgis
            changes.append(("%s/%s" % (kind, absidx), msg))
2410 e15a00dc Dimitris Aragiorgis
2411 22b7f6f8 Thomas Thrainer
        assert container[absidx] == item
2412 22b7f6f8 Thomas Thrainer
        del container[absidx]
2413 22b7f6f8 Thomas Thrainer
      elif op == constants.DDM_MODIFY:
2414 22b7f6f8 Thomas Thrainer
        if modify_fn is not None:
2415 22b7f6f8 Thomas Thrainer
          changes = modify_fn(absidx, item, params, private)
2416 22b7f6f8 Thomas Thrainer
      else:
2417 22b7f6f8 Thomas Thrainer
        raise errors.ProgrammerError("Unhandled operation '%s'" % op)
2418 22b7f6f8 Thomas Thrainer
2419 22b7f6f8 Thomas Thrainer
    assert _TApplyContModsCbChanges(changes)
2420 22b7f6f8 Thomas Thrainer
2421 22b7f6f8 Thomas Thrainer
    if not (chgdesc is None or changes is None):
2422 22b7f6f8 Thomas Thrainer
      chgdesc.extend(changes)
2423 22b7f6f8 Thomas Thrainer
2424 22b7f6f8 Thomas Thrainer
2425 22b7f6f8 Thomas Thrainer
def _UpdateIvNames(base_index, disks):
2426 22b7f6f8 Thomas Thrainer
  """Updates the C{iv_name} attribute of disks.
2427 22b7f6f8 Thomas Thrainer

2428 22b7f6f8 Thomas Thrainer
  @type disks: list of L{objects.Disk}
2429 22b7f6f8 Thomas Thrainer

2430 22b7f6f8 Thomas Thrainer
  """
2431 22b7f6f8 Thomas Thrainer
  for (idx, disk) in enumerate(disks):
2432 22b7f6f8 Thomas Thrainer
    disk.iv_name = "disk/%s" % (base_index + idx, )
2433 22b7f6f8 Thomas Thrainer
2434 22b7f6f8 Thomas Thrainer
2435 22b7f6f8 Thomas Thrainer
class LUInstanceSetParams(LogicalUnit):
2436 22b7f6f8 Thomas Thrainer
  """Modifies an instances's parameters.
2437 22b7f6f8 Thomas Thrainer

2438 22b7f6f8 Thomas Thrainer
  """
2439 22b7f6f8 Thomas Thrainer
  HPATH = "instance-modify"
2440 22b7f6f8 Thomas Thrainer
  HTYPE = constants.HTYPE_INSTANCE
2441 22b7f6f8 Thomas Thrainer
  REQ_BGL = False
2442 22b7f6f8 Thomas Thrainer
2443 22b7f6f8 Thomas Thrainer
  @staticmethod
2444 22b7f6f8 Thomas Thrainer
  def _UpgradeDiskNicMods(kind, mods, verify_fn):
2445 22b7f6f8 Thomas Thrainer
    assert ht.TList(mods)
2446 22b7f6f8 Thomas Thrainer
    assert not mods or len(mods[0]) in (2, 3)
2447 22b7f6f8 Thomas Thrainer
2448 22b7f6f8 Thomas Thrainer
    if mods and len(mods[0]) == 2:
2449 22b7f6f8 Thomas Thrainer
      result = []
2450 22b7f6f8 Thomas Thrainer
2451 22b7f6f8 Thomas Thrainer
      addremove = 0
2452 22b7f6f8 Thomas Thrainer
      for op, params in mods:
2453 22b7f6f8 Thomas Thrainer
        if op in (constants.DDM_ADD, constants.DDM_REMOVE):
2454 22b7f6f8 Thomas Thrainer
          result.append((op, -1, params))
2455 22b7f6f8 Thomas Thrainer
          addremove += 1
2456 22b7f6f8 Thomas Thrainer
2457 22b7f6f8 Thomas Thrainer
          if addremove > 1:
2458 22b7f6f8 Thomas Thrainer
            raise errors.OpPrereqError("Only one %s add or remove operation is"
2459 22b7f6f8 Thomas Thrainer
                                       " supported at a time" % kind,
2460 22b7f6f8 Thomas Thrainer
                                       errors.ECODE_INVAL)
2461 22b7f6f8 Thomas Thrainer
        else:
2462 22b7f6f8 Thomas Thrainer
          result.append((constants.DDM_MODIFY, op, params))
2463 22b7f6f8 Thomas Thrainer
2464 22b7f6f8 Thomas Thrainer
      assert verify_fn(result)
2465 22b7f6f8 Thomas Thrainer
    else:
2466 22b7f6f8 Thomas Thrainer
      result = mods
2467 22b7f6f8 Thomas Thrainer
2468 22b7f6f8 Thomas Thrainer
    return result
2469 22b7f6f8 Thomas Thrainer
2470 22b7f6f8 Thomas Thrainer
  @staticmethod
2471 22b7f6f8 Thomas Thrainer
  def _CheckMods(kind, mods, key_types, item_fn):
2472 22b7f6f8 Thomas Thrainer
    """Ensures requested disk/NIC modifications are valid.
2473 22b7f6f8 Thomas Thrainer

2474 22b7f6f8 Thomas Thrainer
    """
2475 22b7f6f8 Thomas Thrainer
    for (op, _, params) in mods:
2476 22b7f6f8 Thomas Thrainer
      assert ht.TDict(params)
2477 22b7f6f8 Thomas Thrainer
2478 22b7f6f8 Thomas Thrainer
      # If 'key_types' is an empty dict, we assume we have an
2479 22b7f6f8 Thomas Thrainer
      # 'ext' template and thus do not ForceDictType
2480 22b7f6f8 Thomas Thrainer
      if key_types:
2481 22b7f6f8 Thomas Thrainer
        utils.ForceDictType(params, key_types)
2482 22b7f6f8 Thomas Thrainer
2483 22b7f6f8 Thomas Thrainer
      if op == constants.DDM_REMOVE:
2484 22b7f6f8 Thomas Thrainer
        if params:
2485 22b7f6f8 Thomas Thrainer
          raise errors.OpPrereqError("No settings should be passed when"
2486 22b7f6f8 Thomas Thrainer
                                     " removing a %s" % kind,
2487 22b7f6f8 Thomas Thrainer
                                     errors.ECODE_INVAL)
2488 22b7f6f8 Thomas Thrainer
      elif op in (constants.DDM_ADD, constants.DDM_MODIFY):
2489 22b7f6f8 Thomas Thrainer
        item_fn(op, params)
2490 22b7f6f8 Thomas Thrainer
      else:
2491 22b7f6f8 Thomas Thrainer
        raise errors.ProgrammerError("Unhandled operation '%s'" % op)
2492 22b7f6f8 Thomas Thrainer
2493 affe1792 Klaus Aehlig
  def _VerifyDiskModification(self, op, params, excl_stor):
2494 22b7f6f8 Thomas Thrainer
    """Verifies a disk modification.
2495 22b7f6f8 Thomas Thrainer

2496 22b7f6f8 Thomas Thrainer
    """
2497 22b7f6f8 Thomas Thrainer
    if op == constants.DDM_ADD:
2498 22b7f6f8 Thomas Thrainer
      mode = params.setdefault(constants.IDISK_MODE, constants.DISK_RDWR)
2499 22b7f6f8 Thomas Thrainer
      if mode not in constants.DISK_ACCESS_SET:
2500 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Invalid disk access mode '%s'" % mode,
2501 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
2502 22b7f6f8 Thomas Thrainer
2503 22b7f6f8 Thomas Thrainer
      size = params.get(constants.IDISK_SIZE, None)
2504 22b7f6f8 Thomas Thrainer
      if size is None:
2505 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Required disk parameter '%s' missing" %
2506 22b7f6f8 Thomas Thrainer
                                   constants.IDISK_SIZE, errors.ECODE_INVAL)
2507 34956ece Thomas Thrainer
      size = int(size)
2508 22b7f6f8 Thomas Thrainer
2509 22b7f6f8 Thomas Thrainer
      params[constants.IDISK_SIZE] = size
2510 22b7f6f8 Thomas Thrainer
      name = params.get(constants.IDISK_NAME, None)
2511 22b7f6f8 Thomas Thrainer
      if name is not None and name.lower() == constants.VALUE_NONE:
2512 22b7f6f8 Thomas Thrainer
        params[constants.IDISK_NAME] = None
2513 22b7f6f8 Thomas Thrainer
2514 7c848a6a Bernardo Dal Seno
      CheckSpindlesExclusiveStorage(params, excl_stor, True)
2515 3f3ea14c Bernardo Dal Seno
2516 22b7f6f8 Thomas Thrainer
    elif op == constants.DDM_MODIFY:
2517 22b7f6f8 Thomas Thrainer
      if constants.IDISK_SIZE in params:
2518 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Disk size change not possible, use"
2519 22b7f6f8 Thomas Thrainer
                                   " grow-disk", errors.ECODE_INVAL)
2520 c5c72215 Dimitris Aragiorgis
2521 c5c72215 Dimitris Aragiorgis
      # Disk modification supports changing only the disk name and mode.
2522 c5c72215 Dimitris Aragiorgis
      # Changing arbitrary parameters is allowed only for ext disk template",
2523 c5c72215 Dimitris Aragiorgis
      if self.instance.disk_template != constants.DT_EXT:
2524 c5c72215 Dimitris Aragiorgis
        utils.ForceDictType(params, constants.MODIFIABLE_IDISK_PARAMS_TYPES)
2525 c5c72215 Dimitris Aragiorgis
2526 22b7f6f8 Thomas Thrainer
      name = params.get(constants.IDISK_NAME, None)
2527 22b7f6f8 Thomas Thrainer
      if name is not None and name.lower() == constants.VALUE_NONE:
2528 22b7f6f8 Thomas Thrainer
        params[constants.IDISK_NAME] = None
2529 22b7f6f8 Thomas Thrainer
2530 22b7f6f8 Thomas Thrainer
  @staticmethod
2531 22b7f6f8 Thomas Thrainer
  def _VerifyNicModification(op, params):
2532 22b7f6f8 Thomas Thrainer
    """Verifies a network interface modification.
2533 22b7f6f8 Thomas Thrainer

2534 22b7f6f8 Thomas Thrainer
    """
2535 22b7f6f8 Thomas Thrainer
    if op in (constants.DDM_ADD, constants.DDM_MODIFY):
2536 22b7f6f8 Thomas Thrainer
      ip = params.get(constants.INIC_IP, None)
2537 22b7f6f8 Thomas Thrainer
      name = params.get(constants.INIC_NAME, None)
2538 22b7f6f8 Thomas Thrainer
      req_net = params.get(constants.INIC_NETWORK, None)
2539 22b7f6f8 Thomas Thrainer
      link = params.get(constants.NIC_LINK, None)
2540 22b7f6f8 Thomas Thrainer
      mode = params.get(constants.NIC_MODE, None)
2541 22b7f6f8 Thomas Thrainer
      if name is not None and name.lower() == constants.VALUE_NONE:
2542 22b7f6f8 Thomas Thrainer
        params[constants.INIC_NAME] = None
2543 22b7f6f8 Thomas Thrainer
      if req_net is not None:
2544 22b7f6f8 Thomas Thrainer
        if req_net.lower() == constants.VALUE_NONE:
2545 22b7f6f8 Thomas Thrainer
          params[constants.INIC_NETWORK] = None
2546 22b7f6f8 Thomas Thrainer
          req_net = None
2547 22b7f6f8 Thomas Thrainer
        elif link is not None or mode is not None:
2548 22b7f6f8 Thomas Thrainer
          raise errors.OpPrereqError("If network is given"
2549 22b7f6f8 Thomas Thrainer
                                     " mode or link should not",
2550 22b7f6f8 Thomas Thrainer
                                     errors.ECODE_INVAL)
2551 22b7f6f8 Thomas Thrainer
2552 22b7f6f8 Thomas Thrainer
      if op == constants.DDM_ADD:
2553 22b7f6f8 Thomas Thrainer
        macaddr = params.get(constants.INIC_MAC, None)
2554 22b7f6f8 Thomas Thrainer
        if macaddr is None:
2555 22b7f6f8 Thomas Thrainer
          params[constants.INIC_MAC] = constants.VALUE_AUTO
2556 22b7f6f8 Thomas Thrainer
2557 22b7f6f8 Thomas Thrainer
      if ip is not None:
2558 22b7f6f8 Thomas Thrainer
        if ip.lower() == constants.VALUE_NONE:
2559 22b7f6f8 Thomas Thrainer
          params[constants.INIC_IP] = None
2560 22b7f6f8 Thomas Thrainer
        else:
2561 22b7f6f8 Thomas Thrainer
          if ip.lower() == constants.NIC_IP_POOL:
2562 22b7f6f8 Thomas Thrainer
            if op == constants.DDM_ADD and req_net is None:
2563 22b7f6f8 Thomas Thrainer
              raise errors.OpPrereqError("If ip=pool, parameter network"
2564 22b7f6f8 Thomas Thrainer
                                         " cannot be none",
2565 22b7f6f8 Thomas Thrainer
                                         errors.ECODE_INVAL)
2566 22b7f6f8 Thomas Thrainer
          else:
2567 22b7f6f8 Thomas Thrainer
            if not netutils.IPAddress.IsValid(ip):
2568 22b7f6f8 Thomas Thrainer
              raise errors.OpPrereqError("Invalid IP address '%s'" % ip,
2569 22b7f6f8 Thomas Thrainer
                                         errors.ECODE_INVAL)
2570 22b7f6f8 Thomas Thrainer
2571 22b7f6f8 Thomas Thrainer
      if constants.INIC_MAC in params:
2572 22b7f6f8 Thomas Thrainer
        macaddr = params[constants.INIC_MAC]
2573 22b7f6f8 Thomas Thrainer
        if macaddr not in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
2574 22b7f6f8 Thomas Thrainer
          macaddr = utils.NormalizeAndValidateMac(macaddr)
2575 22b7f6f8 Thomas Thrainer
2576 22b7f6f8 Thomas Thrainer
        if op == constants.DDM_MODIFY and macaddr == constants.VALUE_AUTO:
2577 22b7f6f8 Thomas Thrainer
          raise errors.OpPrereqError("'auto' is not a valid MAC address when"
2578 22b7f6f8 Thomas Thrainer
                                     " modifying an existing NIC",
2579 22b7f6f8 Thomas Thrainer
                                     errors.ECODE_INVAL)
2580 22b7f6f8 Thomas Thrainer
2581 22b7f6f8 Thomas Thrainer
  def CheckArguments(self):
2582 22b7f6f8 Thomas Thrainer
    if not (self.op.nics or self.op.disks or self.op.disk_template or
2583 22b7f6f8 Thomas Thrainer
            self.op.hvparams or self.op.beparams or self.op.os_name or
2584 5eae613c Thomas Thrainer
            self.op.osparams or self.op.offline is not None or
2585 93f1e606 Jose A. Lopes
            self.op.runtime_mem or self.op.pnode or self.op.osparams_private or
2586 93f1e606 Jose A. Lopes
            self.op.instance_communication is not None):
2587 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("No changes submitted", errors.ECODE_INVAL)
2588 22b7f6f8 Thomas Thrainer
2589 22b7f6f8 Thomas Thrainer
    if self.op.hvparams:
2590 5eacbcae Thomas Thrainer
      CheckParamsNotGlobal(self.op.hvparams, constants.HVC_GLOBALS,
2591 5eacbcae Thomas Thrainer
                           "hypervisor", "instance", "cluster")
2592 22b7f6f8 Thomas Thrainer
2593 22b7f6f8 Thomas Thrainer
    self.op.disks = self._UpgradeDiskNicMods(
2594 72cd5493 Jose A. Lopes
      "disk", self.op.disks, ht.TSetParamsMods(ht.TIDiskParams))
2595 22b7f6f8 Thomas Thrainer
    self.op.nics = self._UpgradeDiskNicMods(
2596 72cd5493 Jose A. Lopes
      "NIC", self.op.nics, ht.TSetParamsMods(ht.TINicParams))
2597 22b7f6f8 Thomas Thrainer
2598 22b7f6f8 Thomas Thrainer
    if self.op.disks and self.op.disk_template is not None:
2599 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Disk template conversion and other disk"
2600 22b7f6f8 Thomas Thrainer
                                 " changes not supported at the same time",
2601 22b7f6f8 Thomas Thrainer
                                 errors.ECODE_INVAL)
2602 22b7f6f8 Thomas Thrainer
2603 22b7f6f8 Thomas Thrainer
    if (self.op.disk_template and
2604 22b7f6f8 Thomas Thrainer
        self.op.disk_template in constants.DTS_INT_MIRROR and
2605 22b7f6f8 Thomas Thrainer
        self.op.remote_node is None):
2606 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Changing the disk template to a mirrored"
2607 22b7f6f8 Thomas Thrainer
                                 " one requires specifying a secondary node",
2608 22b7f6f8 Thomas Thrainer
                                 errors.ECODE_INVAL)
2609 22b7f6f8 Thomas Thrainer
2610 22b7f6f8 Thomas Thrainer
    # Check NIC modifications
2611 22b7f6f8 Thomas Thrainer
    self._CheckMods("NIC", self.op.nics, constants.INIC_PARAMS_TYPES,
2612 22b7f6f8 Thomas Thrainer
                    self._VerifyNicModification)
2613 22b7f6f8 Thomas Thrainer
2614 22b7f6f8 Thomas Thrainer
    if self.op.pnode:
2615 1c3231aa Thomas Thrainer
      (self.op.pnode_uuid, self.op.pnode) = \
2616 1c3231aa Thomas Thrainer
        ExpandNodeUuidAndName(self.cfg, self.op.pnode_uuid, self.op.pnode)
2617 22b7f6f8 Thomas Thrainer
2618 22b7f6f8 Thomas Thrainer
  def ExpandNames(self):
2619 22b7f6f8 Thomas Thrainer
    self._ExpandAndLockInstance()
2620 22b7f6f8 Thomas Thrainer
    self.needed_locks[locking.LEVEL_NODEGROUP] = []
2621 22b7f6f8 Thomas Thrainer
    # Can't even acquire node locks in shared mode as upcoming changes in
2622 22b7f6f8 Thomas Thrainer
    # Ganeti 2.6 will start to modify the node object on disk conversion
2623 22b7f6f8 Thomas Thrainer
    self.needed_locks[locking.LEVEL_NODE] = []
2624 22b7f6f8 Thomas Thrainer
    self.needed_locks[locking.LEVEL_NODE_RES] = []
2625 22b7f6f8 Thomas Thrainer
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
2626 22b7f6f8 Thomas Thrainer
    # Look node group to look up the ipolicy
2627 22b7f6f8 Thomas Thrainer
    self.share_locks[locking.LEVEL_NODEGROUP] = 1
2628 22b7f6f8 Thomas Thrainer
2629 22b7f6f8 Thomas Thrainer
  def DeclareLocks(self, level):
2630 22b7f6f8 Thomas Thrainer
    if level == locking.LEVEL_NODEGROUP:
2631 22b7f6f8 Thomas Thrainer
      assert not self.needed_locks[locking.LEVEL_NODEGROUP]
2632 22b7f6f8 Thomas Thrainer
      # Acquire locks for the instance's nodegroups optimistically. Needs
2633 22b7f6f8 Thomas Thrainer
      # to be verified in CheckPrereq
2634 22b7f6f8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODEGROUP] = \
2635 da4a52a3 Thomas Thrainer
        self.cfg.GetInstanceNodeGroups(self.op.instance_uuid)
2636 22b7f6f8 Thomas Thrainer
    elif level == locking.LEVEL_NODE:
2637 22b7f6f8 Thomas Thrainer
      self._LockInstancesNodes()
2638 22b7f6f8 Thomas Thrainer
      if self.op.disk_template and self.op.remote_node:
2639 1c3231aa Thomas Thrainer
        (self.op.remote_node_uuid, self.op.remote_node) = \
2640 1c3231aa Thomas Thrainer
          ExpandNodeUuidAndName(self.cfg, self.op.remote_node_uuid,
2641 1c3231aa Thomas Thrainer
                                self.op.remote_node)
2642 1c3231aa Thomas Thrainer
        self.needed_locks[locking.LEVEL_NODE].append(self.op.remote_node_uuid)
2643 22b7f6f8 Thomas Thrainer
    elif level == locking.LEVEL_NODE_RES and self.op.disk_template:
2644 22b7f6f8 Thomas Thrainer
      # Copy node locks
2645 22b7f6f8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE_RES] = \
2646 5eacbcae Thomas Thrainer
        CopyLockList(self.needed_locks[locking.LEVEL_NODE])
2647 22b7f6f8 Thomas Thrainer
2648 22b7f6f8 Thomas Thrainer
  def BuildHooksEnv(self):
2649 22b7f6f8 Thomas Thrainer
    """Build hooks env.
2650 22b7f6f8 Thomas Thrainer

2651 22b7f6f8 Thomas Thrainer
    This runs on the master, primary and secondaries.
2652 22b7f6f8 Thomas Thrainer

2653 22b7f6f8 Thomas Thrainer
    """
2654 22b7f6f8 Thomas Thrainer
    args = {}
2655 22b7f6f8 Thomas Thrainer
    if constants.BE_MINMEM in self.be_new:
2656 22b7f6f8 Thomas Thrainer
      args["minmem"] = self.be_new[constants.BE_MINMEM]
2657 22b7f6f8 Thomas Thrainer
    if constants.BE_MAXMEM in self.be_new:
2658 22b7f6f8 Thomas Thrainer
      args["maxmem"] = self.be_new[constants.BE_MAXMEM]
2659 22b7f6f8 Thomas Thrainer
    if constants.BE_VCPUS in self.be_new:
2660 22b7f6f8 Thomas Thrainer
      args["vcpus"] = self.be_new[constants.BE_VCPUS]
2661 22b7f6f8 Thomas Thrainer
    # TODO: export disk changes. Note: _BuildInstanceHookEnv* don't export disk
2662 22b7f6f8 Thomas Thrainer
    # information at all.
2663 22b7f6f8 Thomas Thrainer
2664 22b7f6f8 Thomas Thrainer
    if self._new_nics is not None:
2665 22b7f6f8 Thomas Thrainer
      nics = []
2666 22b7f6f8 Thomas Thrainer
2667 22b7f6f8 Thomas Thrainer
      for nic in self._new_nics:
2668 22b7f6f8 Thomas Thrainer
        n = copy.deepcopy(nic)
2669 22b7f6f8 Thomas Thrainer
        nicparams = self.cluster.SimpleFillNIC(n.nicparams)
2670 22b7f6f8 Thomas Thrainer
        n.nicparams = nicparams
2671 5eacbcae Thomas Thrainer
        nics.append(NICToTuple(self, n))
2672 22b7f6f8 Thomas Thrainer
2673 22b7f6f8 Thomas Thrainer
      args["nics"] = nics
2674 22b7f6f8 Thomas Thrainer
2675 5eacbcae Thomas Thrainer
    env = BuildInstanceHookEnvByObject(self, self.instance, override=args)
2676 22b7f6f8 Thomas Thrainer
    if self.op.disk_template:
2677 22b7f6f8 Thomas Thrainer
      env["NEW_DISK_TEMPLATE"] = self.op.disk_template
2678 22b7f6f8 Thomas Thrainer
    if self.op.runtime_mem:
2679 22b7f6f8 Thomas Thrainer
      env["RUNTIME_MEMORY"] = self.op.runtime_mem
2680 22b7f6f8 Thomas Thrainer
2681 22b7f6f8 Thomas Thrainer
    return env
2682 22b7f6f8 Thomas Thrainer
2683 22b7f6f8 Thomas Thrainer
  def BuildHooksNodes(self):
2684 22b7f6f8 Thomas Thrainer
    """Build hooks nodes.
2685 22b7f6f8 Thomas Thrainer

2686 22b7f6f8 Thomas Thrainer
    """
2687 22b7f6f8 Thomas Thrainer
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
2688 22b7f6f8 Thomas Thrainer
    return (nl, nl)
2689 22b7f6f8 Thomas Thrainer
2690 22b7f6f8 Thomas Thrainer
  def _PrepareNicModification(self, params, private, old_ip, old_net_uuid,
2691 1c3231aa Thomas Thrainer
                              old_params, cluster, pnode_uuid):
2692 22b7f6f8 Thomas Thrainer
2693 22b7f6f8 Thomas Thrainer
    update_params_dict = dict([(key, params[key])
2694 22b7f6f8 Thomas Thrainer
                               for key in constants.NICS_PARAMETERS
2695 22b7f6f8 Thomas Thrainer
                               if key in params])
2696 22b7f6f8 Thomas Thrainer
2697 22b7f6f8 Thomas Thrainer
    req_link = update_params_dict.get(constants.NIC_LINK, None)
2698 22b7f6f8 Thomas Thrainer
    req_mode = update_params_dict.get(constants.NIC_MODE, None)
2699 22b7f6f8 Thomas Thrainer
2700 22b7f6f8 Thomas Thrainer
    new_net_uuid = None
2701 22b7f6f8 Thomas Thrainer
    new_net_uuid_or_name = params.get(constants.INIC_NETWORK, old_net_uuid)
2702 22b7f6f8 Thomas Thrainer
    if new_net_uuid_or_name:
2703 22b7f6f8 Thomas Thrainer
      new_net_uuid = self.cfg.LookupNetwork(new_net_uuid_or_name)
2704 22b7f6f8 Thomas Thrainer
      new_net_obj = self.cfg.GetNetwork(new_net_uuid)
2705 22b7f6f8 Thomas Thrainer
2706 22b7f6f8 Thomas Thrainer
    if old_net_uuid:
2707 22b7f6f8 Thomas Thrainer
      old_net_obj = self.cfg.GetNetwork(old_net_uuid)
2708 22b7f6f8 Thomas Thrainer
2709 22b7f6f8 Thomas Thrainer
    if new_net_uuid:
2710 1c3231aa Thomas Thrainer
      netparams = self.cfg.GetGroupNetParams(new_net_uuid, pnode_uuid)
2711 22b7f6f8 Thomas Thrainer
      if not netparams:
2712 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("No netparams found for the network"
2713 22b7f6f8 Thomas Thrainer
                                   " %s, probably not connected" %
2714 22b7f6f8 Thomas Thrainer
                                   new_net_obj.name, errors.ECODE_INVAL)
2715 22b7f6f8 Thomas Thrainer
      new_params = dict(netparams)
2716 22b7f6f8 Thomas Thrainer
    else:
2717 5eacbcae Thomas Thrainer
      new_params = GetUpdatedParams(old_params, update_params_dict)
2718 22b7f6f8 Thomas Thrainer
2719 22b7f6f8 Thomas Thrainer
    utils.ForceDictType(new_params, constants.NICS_PARAMETER_TYPES)
2720 22b7f6f8 Thomas Thrainer
2721 22b7f6f8 Thomas Thrainer
    new_filled_params = cluster.SimpleFillNIC(new_params)
2722 22b7f6f8 Thomas Thrainer
    objects.NIC.CheckParameterSyntax(new_filled_params)
2723 22b7f6f8 Thomas Thrainer
2724 22b7f6f8 Thomas Thrainer
    new_mode = new_filled_params[constants.NIC_MODE]
2725 22b7f6f8 Thomas Thrainer
    if new_mode == constants.NIC_MODE_BRIDGED:
2726 22b7f6f8 Thomas Thrainer
      bridge = new_filled_params[constants.NIC_LINK]
2727 1c3231aa Thomas Thrainer
      msg = self.rpc.call_bridges_exist(pnode_uuid, [bridge]).fail_msg
2728 22b7f6f8 Thomas Thrainer
      if msg:
2729 1c3231aa Thomas Thrainer
        msg = "Error checking bridges on node '%s': %s" % \
2730 1c3231aa Thomas Thrainer
                (self.cfg.GetNodeName(pnode_uuid), msg)
2731 22b7f6f8 Thomas Thrainer
        if self.op.force:
2732 22b7f6f8 Thomas Thrainer
          self.warn.append(msg)
2733 22b7f6f8 Thomas Thrainer
        else:
2734 22b7f6f8 Thomas Thrainer
          raise errors.OpPrereqError(msg, errors.ECODE_ENVIRON)
2735 22b7f6f8 Thomas Thrainer
2736 22b7f6f8 Thomas Thrainer
    elif new_mode == constants.NIC_MODE_ROUTED:
2737 22b7f6f8 Thomas Thrainer
      ip = params.get(constants.INIC_IP, old_ip)
2738 22b7f6f8 Thomas Thrainer
      if ip is None:
2739 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Cannot set the NIC IP address to None"
2740 22b7f6f8 Thomas Thrainer
                                   " on a routed NIC", errors.ECODE_INVAL)
2741 22b7f6f8 Thomas Thrainer
2742 22b7f6f8 Thomas Thrainer
    elif new_mode == constants.NIC_MODE_OVS:
2743 22b7f6f8 Thomas Thrainer
      # TODO: check OVS link
2744 22b7f6f8 Thomas Thrainer
      self.LogInfo("OVS links are currently not checked for correctness")
2745 22b7f6f8 Thomas Thrainer
2746 22b7f6f8 Thomas Thrainer
    if constants.INIC_MAC in params:
2747 22b7f6f8 Thomas Thrainer
      mac = params[constants.INIC_MAC]
2748 22b7f6f8 Thomas Thrainer
      if mac is None:
2749 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Cannot unset the NIC MAC address",
2750 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
2751 22b7f6f8 Thomas Thrainer
      elif mac in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
2752 22b7f6f8 Thomas Thrainer
        # otherwise generate the MAC address
2753 22b7f6f8 Thomas Thrainer
        params[constants.INIC_MAC] = \
2754 22b7f6f8 Thomas Thrainer
          self.cfg.GenerateMAC(new_net_uuid, self.proc.GetECId())
2755 22b7f6f8 Thomas Thrainer
      else:
2756 22b7f6f8 Thomas Thrainer
        # or validate/reserve the current one
2757 22b7f6f8 Thomas Thrainer
        try:
2758 22b7f6f8 Thomas Thrainer
          self.cfg.ReserveMAC(mac, self.proc.GetECId())
2759 22b7f6f8 Thomas Thrainer
        except errors.ReservationError:
2760 22b7f6f8 Thomas Thrainer
          raise errors.OpPrereqError("MAC address '%s' already in use"
2761 22b7f6f8 Thomas Thrainer
                                     " in cluster" % mac,
2762 22b7f6f8 Thomas Thrainer
                                     errors.ECODE_NOTUNIQUE)
2763 22b7f6f8 Thomas Thrainer
    elif new_net_uuid != old_net_uuid:
2764 22b7f6f8 Thomas Thrainer
2765 22b7f6f8 Thomas Thrainer
      def get_net_prefix(net_uuid):
2766 22b7f6f8 Thomas Thrainer
        mac_prefix = None
2767 22b7f6f8 Thomas Thrainer
        if net_uuid:
2768 22b7f6f8 Thomas Thrainer
          nobj = self.cfg.GetNetwork(net_uuid)
2769 22b7f6f8 Thomas Thrainer
          mac_prefix = nobj.mac_prefix
2770 22b7f6f8 Thomas Thrainer
2771 22b7f6f8 Thomas Thrainer
        return mac_prefix
2772 22b7f6f8 Thomas Thrainer
2773 22b7f6f8 Thomas Thrainer
      new_prefix = get_net_prefix(new_net_uuid)
2774 22b7f6f8 Thomas Thrainer
      old_prefix = get_net_prefix(old_net_uuid)
2775 22b7f6f8 Thomas Thrainer
      if old_prefix != new_prefix:
2776 22b7f6f8 Thomas Thrainer
        params[constants.INIC_MAC] = \
2777 22b7f6f8 Thomas Thrainer
          self.cfg.GenerateMAC(new_net_uuid, self.proc.GetECId())
2778 22b7f6f8 Thomas Thrainer
2779 22b7f6f8 Thomas Thrainer
    # if there is a change in (ip, network) tuple
2780 22b7f6f8 Thomas Thrainer
    new_ip = params.get(constants.INIC_IP, old_ip)
2781 22b7f6f8 Thomas Thrainer
    if (new_ip, new_net_uuid) != (old_ip, old_net_uuid):
2782 22b7f6f8 Thomas Thrainer
      if new_ip:
2783 22b7f6f8 Thomas Thrainer
        # if IP is pool then require a network and generate one IP
2784 22b7f6f8 Thomas Thrainer
        if new_ip.lower() == constants.NIC_IP_POOL:
2785 22b7f6f8 Thomas Thrainer
          if new_net_uuid:
2786 22b7f6f8 Thomas Thrainer
            try:
2787 22b7f6f8 Thomas Thrainer
              new_ip = self.cfg.GenerateIp(new_net_uuid, self.proc.GetECId())
2788 22b7f6f8 Thomas Thrainer
            except errors.ReservationError:
2789 22b7f6f8 Thomas Thrainer
              raise errors.OpPrereqError("Unable to get a free IP"
2790 22b7f6f8 Thomas Thrainer
                                         " from the address pool",
2791 22b7f6f8 Thomas Thrainer
                                         errors.ECODE_STATE)
2792 22b7f6f8 Thomas Thrainer
            self.LogInfo("Chose IP %s from network %s",
2793 22b7f6f8 Thomas Thrainer
                         new_ip,
2794 22b7f6f8 Thomas Thrainer
                         new_net_obj.name)
2795 22b7f6f8 Thomas Thrainer
            params[constants.INIC_IP] = new_ip
2796 22b7f6f8 Thomas Thrainer
          else:
2797 22b7f6f8 Thomas Thrainer
            raise errors.OpPrereqError("ip=pool, but no network found",
2798 22b7f6f8 Thomas Thrainer
                                       errors.ECODE_INVAL)
2799 22b7f6f8 Thomas Thrainer
        # Reserve new IP if in the new network if any
2800 22b7f6f8 Thomas Thrainer
        elif new_net_uuid:
2801 22b7f6f8 Thomas Thrainer
          try:
2802 031d2db1 Dimitris Aragiorgis
            self.cfg.ReserveIp(new_net_uuid, new_ip, self.proc.GetECId(),
2803 031d2db1 Dimitris Aragiorgis
                               check=self.op.conflicts_check)
2804 22b7f6f8 Thomas Thrainer
            self.LogInfo("Reserving IP %s in network %s",
2805 22b7f6f8 Thomas Thrainer
                         new_ip, new_net_obj.name)
2806 22b7f6f8 Thomas Thrainer
          except errors.ReservationError:
2807 22b7f6f8 Thomas Thrainer
            raise errors.OpPrereqError("IP %s not available in network %s" %
2808 22b7f6f8 Thomas Thrainer
                                       (new_ip, new_net_obj.name),
2809 22b7f6f8 Thomas Thrainer
                                       errors.ECODE_NOTUNIQUE)
2810 22b7f6f8 Thomas Thrainer
        # new network is None so check if new IP is a conflicting IP
2811 22b7f6f8 Thomas Thrainer
        elif self.op.conflicts_check:
2812 1c3231aa Thomas Thrainer
          _CheckForConflictingIp(self, new_ip, pnode_uuid)
2813 22b7f6f8 Thomas Thrainer
2814 22b7f6f8 Thomas Thrainer
      # release old IP if old network is not None
2815 22b7f6f8 Thomas Thrainer
      if old_ip and old_net_uuid:
2816 22b7f6f8 Thomas Thrainer
        try:
2817 22b7f6f8 Thomas Thrainer
          self.cfg.ReleaseIp(old_net_uuid, old_ip, self.proc.GetECId())
2818 22b7f6f8 Thomas Thrainer
        except errors.AddressPoolError:
2819 22b7f6f8 Thomas Thrainer
          logging.warning("Release IP %s not contained in network %s",
2820 22b7f6f8 Thomas Thrainer
                          old_ip, old_net_obj.name)
2821 22b7f6f8 Thomas Thrainer
2822 22b7f6f8 Thomas Thrainer
    # there are no changes in (ip, network) tuple and old network is not None
2823 22b7f6f8 Thomas Thrainer
    elif (old_net_uuid is not None and
2824 22b7f6f8 Thomas Thrainer
          (req_link is not None or req_mode is not None)):
2825 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Not allowed to change link or mode of"
2826 22b7f6f8 Thomas Thrainer
                                 " a NIC that is connected to a network",
2827 22b7f6f8 Thomas Thrainer
                                 errors.ECODE_INVAL)
2828 22b7f6f8 Thomas Thrainer
2829 22b7f6f8 Thomas Thrainer
    private.params = new_params
2830 22b7f6f8 Thomas Thrainer
    private.filled = new_filled_params
2831 22b7f6f8 Thomas Thrainer
2832 22b7f6f8 Thomas Thrainer
  def _PreCheckDiskTemplate(self, pnode_info):
2833 22b7f6f8 Thomas Thrainer
    """CheckPrereq checks related to a new disk template."""
2834 22b7f6f8 Thomas Thrainer
    # Arguments are passed to avoid configuration lookups
2835 d0d7d7cf Thomas Thrainer
    pnode_uuid = self.instance.primary_node
2836 d0d7d7cf Thomas Thrainer
    if self.instance.disk_template == self.op.disk_template:
2837 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Instance already has disk template %s" %
2838 d0d7d7cf Thomas Thrainer
                                 self.instance.disk_template,
2839 d0d7d7cf Thomas Thrainer
                                 errors.ECODE_INVAL)
2840 22b7f6f8 Thomas Thrainer
2841 7bb0c47f Thomas Thrainer
    if not self.cluster.IsDiskTemplateEnabled(self.op.disk_template):
2842 9d276e93 Helga Velroyen
      raise errors.OpPrereqError("Disk template '%s' is not enabled for this"
2843 7bb0c47f Thomas Thrainer
                                 " cluster." % self.op.disk_template)
2844 9d276e93 Helga Velroyen
2845 d0d7d7cf Thomas Thrainer
    if (self.instance.disk_template,
2846 22b7f6f8 Thomas Thrainer
        self.op.disk_template) not in self._DISK_CONVERSIONS:
2847 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Unsupported disk template conversion from"
2848 d0d7d7cf Thomas Thrainer
                                 " %s to %s" % (self.instance.disk_template,
2849 22b7f6f8 Thomas Thrainer
                                                self.op.disk_template),
2850 22b7f6f8 Thomas Thrainer
                                 errors.ECODE_INVAL)
2851 d0d7d7cf Thomas Thrainer
    CheckInstanceState(self, self.instance, INSTANCE_DOWN,
2852 5eacbcae Thomas Thrainer
                       msg="cannot change disk template")
2853 22b7f6f8 Thomas Thrainer
    if self.op.disk_template in constants.DTS_INT_MIRROR:
2854 1c3231aa Thomas Thrainer
      if self.op.remote_node_uuid == pnode_uuid:
2855 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Given new secondary node %s is the same"
2856 22b7f6f8 Thomas Thrainer
                                   " as the primary node of the instance" %
2857 22b7f6f8 Thomas Thrainer
                                   self.op.remote_node, errors.ECODE_STATE)
2858 1c3231aa Thomas Thrainer
      CheckNodeOnline(self, self.op.remote_node_uuid)
2859 1c3231aa Thomas Thrainer
      CheckNodeNotDrained(self, self.op.remote_node_uuid)
2860 22b7f6f8 Thomas Thrainer
      # FIXME: here we assume that the old instance type is DT_PLAIN
2861 d0d7d7cf Thomas Thrainer
      assert self.instance.disk_template == constants.DT_PLAIN
2862 22b7f6f8 Thomas Thrainer
      disks = [{constants.IDISK_SIZE: d.size,
2863 22b7f6f8 Thomas Thrainer
                constants.IDISK_VG: d.logical_id[0]}
2864 d0d7d7cf Thomas Thrainer
               for d in self.instance.disks]
2865 5eacbcae Thomas Thrainer
      required = ComputeDiskSizePerVG(self.op.disk_template, disks)
2866 1c3231aa Thomas Thrainer
      CheckNodesFreeDiskPerVG(self, [self.op.remote_node_uuid], required)
2867 22b7f6f8 Thomas Thrainer
2868 1c3231aa Thomas Thrainer
      snode_info = self.cfg.GetNodeInfo(self.op.remote_node_uuid)
2869 22b7f6f8 Thomas Thrainer
      snode_group = self.cfg.GetNodeGroup(snode_info.group)
2870 d0d7d7cf Thomas Thrainer
      ipolicy = ganeti.masterd.instance.CalculateGroupIPolicy(self.cluster,
2871 22b7f6f8 Thomas Thrainer
                                                              snode_group)
2872 d0d7d7cf Thomas Thrainer
      CheckTargetNodeIPolicy(self, ipolicy, self.instance, snode_info, self.cfg,
2873 5eacbcae Thomas Thrainer
                             ignore=self.op.ignore_ipolicy)
2874 22b7f6f8 Thomas Thrainer
      if pnode_info.group != snode_info.group:
2875 22b7f6f8 Thomas Thrainer
        self.LogWarning("The primary and secondary nodes are in two"
2876 22b7f6f8 Thomas Thrainer
                        " different node groups; the disk parameters"
2877 22b7f6f8 Thomas Thrainer
                        " from the first disk's node group will be"
2878 22b7f6f8 Thomas Thrainer
                        " used")
2879 22b7f6f8 Thomas Thrainer
2880 22b7f6f8 Thomas Thrainer
    if not self.op.disk_template in constants.DTS_EXCL_STORAGE:
2881 22b7f6f8 Thomas Thrainer
      # Make sure none of the nodes require exclusive storage
2882 22b7f6f8 Thomas Thrainer
      nodes = [pnode_info]
2883 22b7f6f8 Thomas Thrainer
      if self.op.disk_template in constants.DTS_INT_MIRROR:
2884 22b7f6f8 Thomas Thrainer
        assert snode_info
2885 22b7f6f8 Thomas Thrainer
        nodes.append(snode_info)
2886 5eacbcae Thomas Thrainer
      has_es = lambda n: IsExclusiveStorageEnabledNode(self.cfg, n)
2887 22b7f6f8 Thomas Thrainer
      if compat.any(map(has_es, nodes)):
2888 22b7f6f8 Thomas Thrainer
        errmsg = ("Cannot convert disk template from %s to %s when exclusive"
2889 d0d7d7cf Thomas Thrainer
                  " storage is enabled" % (self.instance.disk_template,
2890 22b7f6f8 Thomas Thrainer
                                           self.op.disk_template))
2891 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError(errmsg, errors.ECODE_STATE)
2892 22b7f6f8 Thomas Thrainer
2893 1bb99a33 Bernardo Dal Seno
  def _PreCheckDisks(self, ispec):
2894 1bb99a33 Bernardo Dal Seno
    """CheckPrereq checks related to disk changes.
2895 22b7f6f8 Thomas Thrainer

2896 1bb99a33 Bernardo Dal Seno
    @type ispec: dict
2897 1bb99a33 Bernardo Dal Seno
    @param ispec: instance specs to be updated with the new disks
2898 22b7f6f8 Thomas Thrainer

2899 22b7f6f8 Thomas Thrainer
    """
2900 d0d7d7cf Thomas Thrainer
    self.diskparams = self.cfg.GetInstanceDiskParams(self.instance)
2901 22b7f6f8 Thomas Thrainer
2902 3f3ea14c Bernardo Dal Seno
    excl_stor = compat.any(
2903 d0d7d7cf Thomas Thrainer
      rpc.GetExclusiveStorageForNodes(self.cfg,
2904 d0d7d7cf Thomas Thrainer
                                      self.instance.all_nodes).values()
2905 3f3ea14c Bernardo Dal Seno
      )
2906 3f3ea14c Bernardo Dal Seno
2907 22b7f6f8 Thomas Thrainer
    # Check disk modifications. This is done here and not in CheckArguments
2908 22b7f6f8 Thomas Thrainer
    # (as with NICs), because we need to know the instance's disk template
2909 3f3ea14c Bernardo Dal Seno
    ver_fn = lambda op, par: self._VerifyDiskModification(op, par, excl_stor)
2910 d0d7d7cf Thomas Thrainer
    if self.instance.disk_template == constants.DT_EXT:
2911 3f3ea14c Bernardo Dal Seno
      self._CheckMods("disk", self.op.disks, {}, ver_fn)
2912 22b7f6f8 Thomas Thrainer
    else:
2913 22b7f6f8 Thomas Thrainer
      self._CheckMods("disk", self.op.disks, constants.IDISK_PARAMS_TYPES,
2914 3f3ea14c Bernardo Dal Seno
                      ver_fn)
2915 22b7f6f8 Thomas Thrainer
2916 5eacbcae Thomas Thrainer
    self.diskmod = _PrepareContainerMods(self.op.disks, None)
2917 22b7f6f8 Thomas Thrainer
2918 22b7f6f8 Thomas Thrainer
    # Check the validity of the `provider' parameter
2919 d0d7d7cf Thomas Thrainer
    if self.instance.disk_template in constants.DT_EXT:
2920 22b7f6f8 Thomas Thrainer
      for mod in self.diskmod:
2921 22b7f6f8 Thomas Thrainer
        ext_provider = mod[2].get(constants.IDISK_PROVIDER, None)
2922 22b7f6f8 Thomas Thrainer
        if mod[0] == constants.DDM_ADD:
2923 22b7f6f8 Thomas Thrainer
          if ext_provider is None:
2924 22b7f6f8 Thomas Thrainer
            raise errors.OpPrereqError("Instance template is '%s' and parameter"
2925 22b7f6f8 Thomas Thrainer
                                       " '%s' missing, during disk add" %
2926 22b7f6f8 Thomas Thrainer
                                       (constants.DT_EXT,
2927 22b7f6f8 Thomas Thrainer
                                        constants.IDISK_PROVIDER),
2928 22b7f6f8 Thomas Thrainer
                                       errors.ECODE_NOENT)
2929 22b7f6f8 Thomas Thrainer
        elif mod[0] == constants.DDM_MODIFY:
2930 22b7f6f8 Thomas Thrainer
          if ext_provider:
2931 22b7f6f8 Thomas Thrainer
            raise errors.OpPrereqError("Parameter '%s' is invalid during disk"
2932 22b7f6f8 Thomas Thrainer
                                       " modification" %
2933 22b7f6f8 Thomas Thrainer
                                       constants.IDISK_PROVIDER,
2934 22b7f6f8 Thomas Thrainer
                                       errors.ECODE_INVAL)
2935 22b7f6f8 Thomas Thrainer
    else:
2936 22b7f6f8 Thomas Thrainer
      for mod in self.diskmod:
2937 22b7f6f8 Thomas Thrainer
        ext_provider = mod[2].get(constants.IDISK_PROVIDER, None)
2938 22b7f6f8 Thomas Thrainer
        if ext_provider is not None:
2939 22b7f6f8 Thomas Thrainer
          raise errors.OpPrereqError("Parameter '%s' is only valid for"
2940 22b7f6f8 Thomas Thrainer
                                     " instances of type '%s'" %
2941 22b7f6f8 Thomas Thrainer
                                     (constants.IDISK_PROVIDER,
2942 22b7f6f8 Thomas Thrainer
                                      constants.DT_EXT),
2943 22b7f6f8 Thomas Thrainer
                                     errors.ECODE_INVAL)
2944 22b7f6f8 Thomas Thrainer
2945 3c260845 Thomas Thrainer
    if not self.op.wait_for_sync and self.instance.disks_active:
2946 3c260845 Thomas Thrainer
      for mod in self.diskmod:
2947 3c260845 Thomas Thrainer
        if mod[0] == constants.DDM_ADD:
2948 3c260845 Thomas Thrainer
          raise errors.OpPrereqError("Can't add a disk to an instance with"
2949 3c260845 Thomas Thrainer
                                     " activated disks and"
2950 3c260845 Thomas Thrainer
                                     " --no-wait-for-sync given.",
2951 3c260845 Thomas Thrainer
                                     errors.ECODE_INVAL)
2952 3c260845 Thomas Thrainer
2953 d0d7d7cf Thomas Thrainer
    if self.op.disks and self.instance.disk_template == constants.DT_DISKLESS:
2954 1bb99a33 Bernardo Dal Seno
      raise errors.OpPrereqError("Disk operations not supported for"
2955 1bb99a33 Bernardo Dal Seno
                                 " diskless instances", errors.ECODE_INVAL)
2956 1bb99a33 Bernardo Dal Seno
2957 1bb99a33 Bernardo Dal Seno
    def _PrepareDiskMod(_, disk, params, __):
2958 1bb99a33 Bernardo Dal Seno
      disk.name = params.get(constants.IDISK_NAME, None)
2959 1bb99a33 Bernardo Dal Seno
2960 1bb99a33 Bernardo Dal Seno
    # Verify disk changes (operating on a copy)
2961 d0d7d7cf Thomas Thrainer
    disks = copy.deepcopy(self.instance.disks)
2962 1bb99a33 Bernardo Dal Seno
    _ApplyContainerMods("disk", disks, None, self.diskmod, None,
2963 1bb99a33 Bernardo Dal Seno
                        _PrepareDiskMod, None)
2964 1bb99a33 Bernardo Dal Seno
    utils.ValidateDeviceNames("disk", disks)
2965 1bb99a33 Bernardo Dal Seno
    if len(disks) > constants.MAX_DISKS:
2966 1bb99a33 Bernardo Dal Seno
      raise errors.OpPrereqError("Instance has too many disks (%d), cannot add"
2967 1bb99a33 Bernardo Dal Seno
                                 " more" % constants.MAX_DISKS,
2968 1bb99a33 Bernardo Dal Seno
                                 errors.ECODE_STATE)
2969 d0d7d7cf Thomas Thrainer
    disk_sizes = [disk.size for disk in self.instance.disks]
2970 1bb99a33 Bernardo Dal Seno
    disk_sizes.extend(params["size"] for (op, idx, params, private) in
2971 1bb99a33 Bernardo Dal Seno
                      self.diskmod if op == constants.DDM_ADD)
2972 1bb99a33 Bernardo Dal Seno
    ispec[constants.ISPEC_DISK_COUNT] = len(disk_sizes)
2973 1bb99a33 Bernardo Dal Seno
    ispec[constants.ISPEC_DISK_SIZE] = disk_sizes
2974 1bb99a33 Bernardo Dal Seno
2975 1bb99a33 Bernardo Dal Seno
    if self.op.offline is not None and self.op.offline:
2976 d0d7d7cf Thomas Thrainer
      CheckInstanceState(self, self.instance, CAN_CHANGE_INSTANCE_OFFLINE,
2977 1bb99a33 Bernardo Dal Seno
                         msg="can't change to offline")
2978 1bb99a33 Bernardo Dal Seno
2979 9808764a Jose A. Lopes
  @staticmethod
2980 9808764a Jose A. Lopes
  def _InstanceCommunicationDDM(cfg, instance_communication, instance):
2981 9808764a Jose A. Lopes
    """Create a NIC mod that adds or removes the instance
2982 9808764a Jose A. Lopes
    communication NIC to a running instance.
2983 9808764a Jose A. Lopes

2984 9808764a Jose A. Lopes
    The NICS are dynamically created using the Dynamic Device
2985 9808764a Jose A. Lopes
    Modification (DDM).  This function produces a NIC modification
2986 9808764a Jose A. Lopes
    (mod) that inserts an additional NIC meant for instance
2987 9808764a Jose A. Lopes
    communication in or removes an existing instance communication NIC
2988 9808764a Jose A. Lopes
    from a running instance, using DDM.
2989 9808764a Jose A. Lopes

2990 9808764a Jose A. Lopes
    @type cfg: L{config.ConfigWriter}
2991 9808764a Jose A. Lopes
    @param cfg: cluster configuration
2992 9808764a Jose A. Lopes

2993 9808764a Jose A. Lopes
    @type instance_communication: boolean
2994 9808764a Jose A. Lopes
    @param instance_communication: whether instance communication is
2995 9808764a Jose A. Lopes
                                   enabled or disabled
2996 9808764a Jose A. Lopes

2997 9808764a Jose A. Lopes
    @type instance: L{objects.Instance}
2998 9808764a Jose A. Lopes
    @param instance: instance to which the NIC mod will be applied to
2999 9808764a Jose A. Lopes

3000 9808764a Jose A. Lopes
    @rtype: (L{constants.DDM_ADD}, -1, parameters) or
3001 9808764a Jose A. Lopes
            (L{constants.DDM_REMOVE}, -1, parameters) or
3002 9808764a Jose A. Lopes
            L{None}
3003 9808764a Jose A. Lopes
    @return: DDM mod containing an action to add or remove the NIC, or
3004 9808764a Jose A. Lopes
             None if nothing needs to be done
3005 9808764a Jose A. Lopes

3006 9808764a Jose A. Lopes
    """
3007 e25625ab Jose A. Lopes
    nic_name = _ComputeInstanceCommunicationNIC(instance.name)
3008 9808764a Jose A. Lopes
3009 9808764a Jose A. Lopes
    instance_communication_nic = None
3010 9808764a Jose A. Lopes
3011 9808764a Jose A. Lopes
    for nic in instance.nics:
3012 9808764a Jose A. Lopes
      if nic.name == nic_name:
3013 9808764a Jose A. Lopes
        instance_communication_nic = nic
3014 9808764a Jose A. Lopes
        break
3015 9808764a Jose A. Lopes
3016 9808764a Jose A. Lopes
    if instance_communication and not instance_communication_nic:
3017 9808764a Jose A. Lopes
      action = constants.DDM_ADD
3018 9808764a Jose A. Lopes
      params = {constants.INIC_NAME: nic_name,
3019 9808764a Jose A. Lopes
                constants.INIC_MAC: constants.VALUE_GENERATE,
3020 9808764a Jose A. Lopes
                constants.INIC_IP: constants.NIC_IP_POOL,
3021 9808764a Jose A. Lopes
                constants.INIC_NETWORK:
3022 9808764a Jose A. Lopes
                  cfg.GetInstanceCommunicationNetwork()}
3023 9808764a Jose A. Lopes
    elif not instance_communication and instance_communication_nic:
3024 9808764a Jose A. Lopes
      action = constants.DDM_REMOVE
3025 9808764a Jose A. Lopes
      params = None
3026 9808764a Jose A. Lopes
    else:
3027 9808764a Jose A. Lopes
      action = None
3028 9808764a Jose A. Lopes
      params = None
3029 9808764a Jose A. Lopes
3030 9808764a Jose A. Lopes
    if action is not None:
3031 9808764a Jose A. Lopes
      return (action, -1, params)
3032 9808764a Jose A. Lopes
    else:
3033 9808764a Jose A. Lopes
      return None
3034 9808764a Jose A. Lopes
3035 1bb99a33 Bernardo Dal Seno
  def CheckPrereq(self):
3036 1bb99a33 Bernardo Dal Seno
    """Check prerequisites.
3037 1bb99a33 Bernardo Dal Seno

3038 1bb99a33 Bernardo Dal Seno
    This only checks the instance list against the existing names.
3039 1bb99a33 Bernardo Dal Seno

3040 1bb99a33 Bernardo Dal Seno
    """
3041 1bb99a33 Bernardo Dal Seno
    assert self.op.instance_name in self.owned_locks(locking.LEVEL_INSTANCE)
3042 da4a52a3 Thomas Thrainer
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_uuid)
3043 d0d7d7cf Thomas Thrainer
    self.cluster = self.cfg.GetClusterInfo()
3044 9c8f7bf4 Helga Velroyen
    cluster_hvparams = self.cluster.hvparams[self.instance.hypervisor]
3045 1bb99a33 Bernardo Dal Seno
3046 1bb99a33 Bernardo Dal Seno
    assert self.instance is not None, \
3047 1bb99a33 Bernardo Dal Seno
      "Cannot retrieve locked instance %s" % self.op.instance_name
3048 1bb99a33 Bernardo Dal Seno
3049 d0d7d7cf Thomas Thrainer
    pnode_uuid = self.instance.primary_node
3050 1bb99a33 Bernardo Dal Seno
3051 1bb99a33 Bernardo Dal Seno
    self.warn = []
3052 1bb99a33 Bernardo Dal Seno
3053 1c3231aa Thomas Thrainer
    if (self.op.pnode_uuid is not None and self.op.pnode_uuid != pnode_uuid and
3054 1bb99a33 Bernardo Dal Seno
        not self.op.force):
3055 1bb99a33 Bernardo Dal Seno
      # verify that the instance is not up
3056 0bbec3af Helga Velroyen
      instance_info = self.rpc.call_instance_info(
3057 d0d7d7cf Thomas Thrainer
          pnode_uuid, self.instance.name, self.instance.hypervisor,
3058 9c8f7bf4 Helga Velroyen
          cluster_hvparams)
3059 1bb99a33 Bernardo Dal Seno
      if instance_info.fail_msg:
3060 1bb99a33 Bernardo Dal Seno
        self.warn.append("Can't get instance runtime information: %s" %
3061 1bb99a33 Bernardo Dal Seno
                         instance_info.fail_msg)
3062 1bb99a33 Bernardo Dal Seno
      elif instance_info.payload:
3063 1c3231aa Thomas Thrainer
        raise errors.OpPrereqError("Instance is still running on %s" %
3064 1c3231aa Thomas Thrainer
                                   self.cfg.GetNodeName(pnode_uuid),
3065 1bb99a33 Bernardo Dal Seno
                                   errors.ECODE_STATE)
3066 1bb99a33 Bernardo Dal Seno
3067 1c3231aa Thomas Thrainer
    assert pnode_uuid in self.owned_locks(locking.LEVEL_NODE)
3068 d0d7d7cf Thomas Thrainer
    node_uuids = list(self.instance.all_nodes)
3069 1c3231aa Thomas Thrainer
    pnode_info = self.cfg.GetNodeInfo(pnode_uuid)
3070 1bb99a33 Bernardo Dal Seno
3071 1bb99a33 Bernardo Dal Seno
    #_CheckInstanceNodeGroups(self.cfg, self.op.instance_name, owned_groups)
3072 1bb99a33 Bernardo Dal Seno
    assert pnode_info.group in self.owned_locks(locking.LEVEL_NODEGROUP)
3073 1bb99a33 Bernardo Dal Seno
    group_info = self.cfg.GetNodeGroup(pnode_info.group)
3074 1bb99a33 Bernardo Dal Seno
3075 1bb99a33 Bernardo Dal Seno
    # dictionary with instance information after the modification
3076 1bb99a33 Bernardo Dal Seno
    ispec = {}
3077 1bb99a33 Bernardo Dal Seno
3078 96ed3a3e Dimitris Aragiorgis
    if self.op.hotplug or self.op.hotplug_if_possible:
3079 24711492 Dimitris Aragiorgis
      result = self.rpc.call_hotplug_supported(self.instance.primary_node,
3080 24711492 Dimitris Aragiorgis
                                               self.instance)
3081 96ed3a3e Dimitris Aragiorgis
      if result.fail_msg:
3082 96ed3a3e Dimitris Aragiorgis
        if self.op.hotplug:
3083 96ed3a3e Dimitris Aragiorgis
          result.Raise("Hotplug is not possible: %s" % result.fail_msg,
3084 96ed3a3e Dimitris Aragiorgis
                       prereq=True)
3085 96ed3a3e Dimitris Aragiorgis
        else:
3086 96ed3a3e Dimitris Aragiorgis
          self.LogWarning(result.fail_msg)
3087 96ed3a3e Dimitris Aragiorgis
          self.op.hotplug = False
3088 96ed3a3e Dimitris Aragiorgis
          self.LogInfo("Modification will take place without hotplugging.")
3089 96ed3a3e Dimitris Aragiorgis
      else:
3090 96ed3a3e Dimitris Aragiorgis
        self.op.hotplug = True
3091 24711492 Dimitris Aragiorgis
3092 1bb99a33 Bernardo Dal Seno
    # Prepare NIC modifications
3093 9808764a Jose A. Lopes
    # add or remove NIC for instance communication
3094 9808764a Jose A. Lopes
    if self.op.instance_communication is not None:
3095 9808764a Jose A. Lopes
      mod = self._InstanceCommunicationDDM(self.cfg,
3096 9808764a Jose A. Lopes
                                           self.op.instance_communication,
3097 9808764a Jose A. Lopes
                                           self.instance)
3098 9808764a Jose A. Lopes
      if mod is not None:
3099 9808764a Jose A. Lopes
        self.op.nics.append(mod)
3100 9808764a Jose A. Lopes
3101 1bb99a33 Bernardo Dal Seno
    self.nicmod = _PrepareContainerMods(self.op.nics, _InstNicModPrivate)
3102 1bb99a33 Bernardo Dal Seno
3103 22b7f6f8 Thomas Thrainer
    # OS change
3104 22b7f6f8 Thomas Thrainer
    if self.op.os_name and not self.op.force:
3105 d0d7d7cf Thomas Thrainer
      CheckNodeHasOS(self, self.instance.primary_node, self.op.os_name,
3106 5eacbcae Thomas Thrainer
                     self.op.force_variant)
3107 22b7f6f8 Thomas Thrainer
      instance_os = self.op.os_name
3108 22b7f6f8 Thomas Thrainer
    else:
3109 d0d7d7cf Thomas Thrainer
      instance_os = self.instance.os
3110 22b7f6f8 Thomas Thrainer
3111 22b7f6f8 Thomas Thrainer
    assert not (self.op.disk_template and self.op.disks), \
3112 22b7f6f8 Thomas Thrainer
      "Can't modify disk template and apply disk changes at the same time"
3113 22b7f6f8 Thomas Thrainer
3114 22b7f6f8 Thomas Thrainer
    if self.op.disk_template:
3115 22b7f6f8 Thomas Thrainer
      self._PreCheckDiskTemplate(pnode_info)
3116 22b7f6f8 Thomas Thrainer
3117 1bb99a33 Bernardo Dal Seno
    self._PreCheckDisks(ispec)
3118 1bb99a33 Bernardo Dal Seno
3119 22b7f6f8 Thomas Thrainer
    # hvparams processing
3120 22b7f6f8 Thomas Thrainer
    if self.op.hvparams:
3121 d0d7d7cf Thomas Thrainer
      hv_type = self.instance.hypervisor
3122 d0d7d7cf Thomas Thrainer
      i_hvdict = GetUpdatedParams(self.instance.hvparams, self.op.hvparams)
3123 22b7f6f8 Thomas Thrainer
      utils.ForceDictType(i_hvdict, constants.HVS_PARAMETER_TYPES)
3124 d0d7d7cf Thomas Thrainer
      hv_new = self.cluster.SimpleFillHV(hv_type, self.instance.os, i_hvdict)
3125 22b7f6f8 Thomas Thrainer
3126 22b7f6f8 Thomas Thrainer
      # local check
3127 22b7f6f8 Thomas Thrainer
      hypervisor.GetHypervisorClass(hv_type).CheckParameterSyntax(hv_new)
3128 d0d7d7cf Thomas Thrainer
      CheckHVParams(self, node_uuids, self.instance.hypervisor, hv_new)
3129 22b7f6f8 Thomas Thrainer
      self.hv_proposed = self.hv_new = hv_new # the new actual values
3130 22b7f6f8 Thomas Thrainer
      self.hv_inst = i_hvdict # the new dict (without defaults)
3131 22b7f6f8 Thomas Thrainer
    else:
3132 d0d7d7cf Thomas Thrainer
      self.hv_proposed = self.cluster.SimpleFillHV(self.instance.hypervisor,
3133 d0d7d7cf Thomas Thrainer
                                                   self.instance.os,
3134 d0d7d7cf Thomas Thrainer
                                                   self.instance.hvparams)
3135 22b7f6f8 Thomas Thrainer
      self.hv_new = self.hv_inst = {}
3136 22b7f6f8 Thomas Thrainer
3137 22b7f6f8 Thomas Thrainer
    # beparams processing
3138 22b7f6f8 Thomas Thrainer
    if self.op.beparams:
3139 d0d7d7cf Thomas Thrainer
      i_bedict = GetUpdatedParams(self.instance.beparams, self.op.beparams,
3140 5eacbcae Thomas Thrainer
                                  use_none=True)
3141 22b7f6f8 Thomas Thrainer
      objects.UpgradeBeParams(i_bedict)
3142 22b7f6f8 Thomas Thrainer
      utils.ForceDictType(i_bedict, constants.BES_PARAMETER_TYPES)
3143 d0d7d7cf Thomas Thrainer
      be_new = self.cluster.SimpleFillBE(i_bedict)
3144 22b7f6f8 Thomas Thrainer
      self.be_proposed = self.be_new = be_new # the new actual values
3145 22b7f6f8 Thomas Thrainer
      self.be_inst = i_bedict # the new dict (without defaults)
3146 22b7f6f8 Thomas Thrainer
    else:
3147 22b7f6f8 Thomas Thrainer
      self.be_new = self.be_inst = {}
3148 d0d7d7cf Thomas Thrainer
      self.be_proposed = self.cluster.SimpleFillBE(self.instance.beparams)
3149 d0d7d7cf Thomas Thrainer
    be_old = self.cluster.FillBE(self.instance)
3150 22b7f6f8 Thomas Thrainer
3151 22b7f6f8 Thomas Thrainer
    # CPU param validation -- checking every time a parameter is
3152 22b7f6f8 Thomas Thrainer
    # changed to cover all cases where either CPU mask or vcpus have
3153 22b7f6f8 Thomas Thrainer
    # changed
3154 22b7f6f8 Thomas Thrainer
    if (constants.BE_VCPUS in self.be_proposed and
3155 22b7f6f8 Thomas Thrainer
        constants.HV_CPU_MASK in self.hv_proposed):
3156 22b7f6f8 Thomas Thrainer
      cpu_list = \
3157 22b7f6f8 Thomas Thrainer
        utils.ParseMultiCpuMask(self.hv_proposed[constants.HV_CPU_MASK])
3158 22b7f6f8 Thomas Thrainer
      # Verify mask is consistent with number of vCPUs. Can skip this
3159 22b7f6f8 Thomas Thrainer
      # test if only 1 entry in the CPU mask, which means same mask
3160 22b7f6f8 Thomas Thrainer
      # is applied to all vCPUs.
3161 22b7f6f8 Thomas Thrainer
      if (len(cpu_list) > 1 and
3162 22b7f6f8 Thomas Thrainer
          len(cpu_list) != self.be_proposed[constants.BE_VCPUS]):
3163 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Number of vCPUs [%d] does not match the"
3164 22b7f6f8 Thomas Thrainer
                                   " CPU mask [%s]" %
3165 22b7f6f8 Thomas Thrainer
                                   (self.be_proposed[constants.BE_VCPUS],
3166 22b7f6f8 Thomas Thrainer
                                    self.hv_proposed[constants.HV_CPU_MASK]),
3167 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
3168 22b7f6f8 Thomas Thrainer
3169 22b7f6f8 Thomas Thrainer
      # Only perform this test if a new CPU mask is given
3170 22b7f6f8 Thomas Thrainer
      if constants.HV_CPU_MASK in self.hv_new:
3171 22b7f6f8 Thomas Thrainer
        # Calculate the largest CPU number requested
3172 22b7f6f8 Thomas Thrainer
        max_requested_cpu = max(map(max, cpu_list))
3173 22b7f6f8 Thomas Thrainer
        # Check that all of the instance's nodes have enough physical CPUs to
3174 22b7f6f8 Thomas Thrainer
        # satisfy the requested CPU mask
3175 d0d7d7cf Thomas Thrainer
        hvspecs = [(self.instance.hypervisor,
3176 d0d7d7cf Thomas Thrainer
                    self.cfg.GetClusterInfo()
3177 d0d7d7cf Thomas Thrainer
                      .hvparams[self.instance.hypervisor])]
3178 d0d7d7cf Thomas Thrainer
        _CheckNodesPhysicalCPUs(self, self.instance.all_nodes,
3179 a295eb80 Helga Velroyen
                                max_requested_cpu + 1,
3180 a295eb80 Helga Velroyen
                                hvspecs)
3181 22b7f6f8 Thomas Thrainer
3182 22b7f6f8 Thomas Thrainer
    # osparams processing
3183 6bce7ba2 Santi Raffa
    if self.op.osparams or self.op.osparams_private:
3184 1a182390 Santi Raffa
      public_parms = self.op.osparams or {}
3185 6bce7ba2 Santi Raffa
      private_parms = self.op.osparams_private or {}
3186 1a182390 Santi Raffa
      dupe_keys = utils.GetRepeatedKeys(public_parms, private_parms)
3187 1a182390 Santi Raffa
3188 1a182390 Santi Raffa
      if dupe_keys:
3189 1a182390 Santi Raffa
        raise errors.OpPrereqError("OS parameters repeated multiple times: %s" %
3190 1a182390 Santi Raffa
                                   utils.CommaJoin(dupe_keys))
3191 1a182390 Santi Raffa
3192 1a182390 Santi Raffa
      self.os_inst = GetUpdatedParams(self.instance.osparams,
3193 1a182390 Santi Raffa
                                      public_parms)
3194 1a182390 Santi Raffa
      self.os_inst_private = GetUpdatedParams(self.instance.osparams_private,
3195 1a182390 Santi Raffa
                                              private_parms)
3196 1a182390 Santi Raffa
3197 1a182390 Santi Raffa
      CheckOSParams(self, True, node_uuids, instance_os,
3198 1a182390 Santi Raffa
                    objects.FillDict(self.os_inst,
3199 1a182390 Santi Raffa
                                     self.os_inst_private))
3200 1a182390 Santi Raffa
3201 22b7f6f8 Thomas Thrainer
    else:
3202 22b7f6f8 Thomas Thrainer
      self.os_inst = {}
3203 1a182390 Santi Raffa
      self.os_inst_private = {}
3204 22b7f6f8 Thomas Thrainer
3205 22b7f6f8 Thomas Thrainer
    #TODO(dynmem): do the appropriate check involving MINMEM
3206 22b7f6f8 Thomas Thrainer
    if (constants.BE_MAXMEM in self.op.beparams and not self.op.force and
3207 22b7f6f8 Thomas Thrainer
        be_new[constants.BE_MAXMEM] > be_old[constants.BE_MAXMEM]):
3208 1c3231aa Thomas Thrainer
      mem_check_list = [pnode_uuid]
3209 22b7f6f8 Thomas Thrainer
      if be_new[constants.BE_AUTO_BALANCE]:
3210 22b7f6f8 Thomas Thrainer
        # either we changed auto_balance to yes or it was from before
3211 d0d7d7cf Thomas Thrainer
        mem_check_list.extend(self.instance.secondary_nodes)
3212 a295eb80 Helga Velroyen
      instance_info = self.rpc.call_instance_info(
3213 d0d7d7cf Thomas Thrainer
          pnode_uuid, self.instance.name, self.instance.hypervisor,
3214 9c8f7bf4 Helga Velroyen
          cluster_hvparams)
3215 d0d7d7cf Thomas Thrainer
      hvspecs = [(self.instance.hypervisor,
3216 9c8f7bf4 Helga Velroyen
                  cluster_hvparams)]
3217 22b7f6f8 Thomas Thrainer
      nodeinfo = self.rpc.call_node_info(mem_check_list, None,
3218 da803ff1 Helga Velroyen
                                         hvspecs)
3219 1c3231aa Thomas Thrainer
      pninfo = nodeinfo[pnode_uuid]
3220 22b7f6f8 Thomas Thrainer
      msg = pninfo.fail_msg
3221 22b7f6f8 Thomas Thrainer
      if msg:
3222 22b7f6f8 Thomas Thrainer
        # Assume the primary node is unreachable and go ahead
3223 22b7f6f8 Thomas Thrainer
        self.warn.append("Can't get info from primary node %s: %s" %
3224 1c3231aa Thomas Thrainer
                         (self.cfg.GetNodeName(pnode_uuid), msg))
3225 22b7f6f8 Thomas Thrainer
      else:
3226 22b7f6f8 Thomas Thrainer
        (_, _, (pnhvinfo, )) = pninfo.payload
3227 22b7f6f8 Thomas Thrainer
        if not isinstance(pnhvinfo.get("memory_free", None), int):
3228 22b7f6f8 Thomas Thrainer
          self.warn.append("Node data from primary node %s doesn't contain"
3229 1c3231aa Thomas Thrainer
                           " free memory information" %
3230 1c3231aa Thomas Thrainer
                           self.cfg.GetNodeName(pnode_uuid))
3231 22b7f6f8 Thomas Thrainer
        elif instance_info.fail_msg:
3232 22b7f6f8 Thomas Thrainer
          self.warn.append("Can't get instance runtime information: %s" %
3233 22b7f6f8 Thomas Thrainer
                           instance_info.fail_msg)
3234 22b7f6f8 Thomas Thrainer
        else:
3235 22b7f6f8 Thomas Thrainer
          if instance_info.payload:
3236 22b7f6f8 Thomas Thrainer
            current_mem = int(instance_info.payload["memory"])
3237 22b7f6f8 Thomas Thrainer
          else:
3238 22b7f6f8 Thomas Thrainer
            # Assume instance not running
3239 22b7f6f8 Thomas Thrainer
            # (there is a slight race condition here, but it's not very
3240 22b7f6f8 Thomas Thrainer
            # probable, and we have no other way to check)
3241 22b7f6f8 Thomas Thrainer
            # TODO: Describe race condition
3242 22b7f6f8 Thomas Thrainer
            current_mem = 0
3243 22b7f6f8 Thomas Thrainer
          #TODO(dynmem): do the appropriate check involving MINMEM
3244 22b7f6f8 Thomas Thrainer
          miss_mem = (be_new[constants.BE_MAXMEM] - current_mem -
3245 22b7f6f8 Thomas Thrainer
                      pnhvinfo["memory_free"])
3246 22b7f6f8 Thomas Thrainer
          if miss_mem > 0:
3247 22b7f6f8 Thomas Thrainer
            raise errors.OpPrereqError("This change will prevent the instance"
3248 22b7f6f8 Thomas Thrainer
                                       " from starting, due to %d MB of memory"
3249 22b7f6f8 Thomas Thrainer
                                       " missing on its primary node" %
3250 22b7f6f8 Thomas Thrainer
                                       miss_mem, errors.ECODE_NORES)
3251 22b7f6f8 Thomas Thrainer
3252 22b7f6f8 Thomas Thrainer
      if be_new[constants.BE_AUTO_BALANCE]:
3253 1c3231aa Thomas Thrainer
        for node_uuid, nres in nodeinfo.items():
3254 d0d7d7cf Thomas Thrainer
          if node_uuid not in self.instance.secondary_nodes:
3255 22b7f6f8 Thomas Thrainer
            continue
3256 1c3231aa Thomas Thrainer
          nres.Raise("Can't get info from secondary node %s" %
3257 1c3231aa Thomas Thrainer
                     self.cfg.GetNodeName(node_uuid), prereq=True,
3258 1c3231aa Thomas Thrainer
                     ecode=errors.ECODE_STATE)
3259 22b7f6f8 Thomas Thrainer
          (_, _, (nhvinfo, )) = nres.payload
3260 22b7f6f8 Thomas Thrainer
          if not isinstance(nhvinfo.get("memory_free", None), int):
3261 22b7f6f8 Thomas Thrainer
            raise errors.OpPrereqError("Secondary node %s didn't return free"
3262 1c3231aa Thomas Thrainer
                                       " memory information" %
3263 1c3231aa Thomas Thrainer
                                       self.cfg.GetNodeName(node_uuid),
3264 22b7f6f8 Thomas Thrainer
                                       errors.ECODE_STATE)
3265 22b7f6f8 Thomas Thrainer
          #TODO(dynmem): do the appropriate check involving MINMEM
3266 22b7f6f8 Thomas Thrainer
          elif be_new[constants.BE_MAXMEM] > nhvinfo["memory_free"]:
3267 22b7f6f8 Thomas Thrainer
            raise errors.OpPrereqError("This change will prevent the instance"
3268 22b7f6f8 Thomas Thrainer
                                       " from failover to its secondary node"
3269 1c3231aa Thomas Thrainer
                                       " %s, due to not enough memory" %
3270 1c3231aa Thomas Thrainer
                                       self.cfg.GetNodeName(node_uuid),
3271 22b7f6f8 Thomas Thrainer
                                       errors.ECODE_STATE)
3272 22b7f6f8 Thomas Thrainer
3273 22b7f6f8 Thomas Thrainer
    if self.op.runtime_mem:
3274 0bbec3af Helga Velroyen
      remote_info = self.rpc.call_instance_info(
3275 d0d7d7cf Thomas Thrainer
         self.instance.primary_node, self.instance.name,
3276 b666a94c Helga Velroyen
         self.instance.hypervisor,
3277 9c8f7bf4 Helga Velroyen
         cluster_hvparams)
3278 1c3231aa Thomas Thrainer
      remote_info.Raise("Error checking node %s" %
3279 d0d7d7cf Thomas Thrainer
                        self.cfg.GetNodeName(self.instance.primary_node))
3280 22b7f6f8 Thomas Thrainer
      if not remote_info.payload: # not running already
3281 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Instance %s is not running" %
3282 d0d7d7cf Thomas Thrainer
                                   self.instance.name, errors.ECODE_STATE)
3283 22b7f6f8 Thomas Thrainer
3284 22b7f6f8 Thomas Thrainer
      current_memory = remote_info.payload["memory"]
3285 22b7f6f8 Thomas Thrainer
      if (not self.op.force and
3286 22b7f6f8 Thomas Thrainer
           (self.op.runtime_mem > self.be_proposed[constants.BE_MAXMEM] or
3287 22b7f6f8 Thomas Thrainer
            self.op.runtime_mem < self.be_proposed[constants.BE_MINMEM])):
3288 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError("Instance %s must have memory between %d"
3289 22b7f6f8 Thomas Thrainer
                                   " and %d MB of memory unless --force is"
3290 22b7f6f8 Thomas Thrainer
                                   " given" %
3291 d0d7d7cf Thomas Thrainer
                                   (self.instance.name,
3292 22b7f6f8 Thomas Thrainer
                                    self.be_proposed[constants.BE_MINMEM],
3293 22b7f6f8 Thomas Thrainer
                                    self.be_proposed[constants.BE_MAXMEM]),
3294 22b7f6f8 Thomas Thrainer
                                   errors.ECODE_INVAL)
3295 22b7f6f8 Thomas Thrainer
3296 22b7f6f8 Thomas Thrainer
      delta = self.op.runtime_mem - current_memory
3297 22b7f6f8 Thomas Thrainer
      if delta > 0:
3298 a295eb80 Helga Velroyen
        CheckNodeFreeMemory(
3299 d0d7d7cf Thomas Thrainer
            self, self.instance.primary_node,
3300 d0d7d7cf Thomas Thrainer
            "ballooning memory for instance %s" % self.instance.name, delta,
3301 d0d7d7cf Thomas Thrainer
            self.instance.hypervisor,
3302 d0d7d7cf Thomas Thrainer
            self.cfg.GetClusterInfo().hvparams[self.instance.hypervisor])
3303 d0d7d7cf Thomas Thrainer
3304 d0d7d7cf Thomas Thrainer
    # make self.cluster visible in the functions below
3305 d0d7d7cf Thomas Thrainer
    cluster = self.cluster
3306 22b7f6f8 Thomas Thrainer
3307 22b7f6f8 Thomas Thrainer
    def _PrepareNicCreate(_, params, private):
3308 22b7f6f8 Thomas Thrainer
      self._PrepareNicModification(params, private, None, None,
3309 1c3231aa Thomas Thrainer
                                   {}, cluster, pnode_uuid)
3310 22b7f6f8 Thomas Thrainer
      return (None, None)
3311 22b7f6f8 Thomas Thrainer
3312 22b7f6f8 Thomas Thrainer
    def _PrepareNicMod(_, nic, params, private):
3313 22b7f6f8 Thomas Thrainer
      self._PrepareNicModification(params, private, nic.ip, nic.network,
3314 1c3231aa Thomas Thrainer
                                   nic.nicparams, cluster, pnode_uuid)
3315 22b7f6f8 Thomas Thrainer
      return None
3316 22b7f6f8 Thomas Thrainer
3317 22b7f6f8 Thomas Thrainer
    def _PrepareNicRemove(_, params, __):
3318 22b7f6f8 Thomas Thrainer
      ip = params.ip
3319 22b7f6f8 Thomas Thrainer
      net = params.network
3320 22b7f6f8 Thomas Thrainer
      if net is not None and ip is not None:
3321 22b7f6f8 Thomas Thrainer
        self.cfg.ReleaseIp(net, ip, self.proc.GetECId())
3322 22b7f6f8 Thomas Thrainer
3323 22b7f6f8 Thomas Thrainer
    # Verify NIC changes (operating on copy)
3324 ebe70850 Jose A. Lopes
    nics = [nic.Copy() for nic in self.instance.nics]
3325 5eacbcae Thomas Thrainer
    _ApplyContainerMods("NIC", nics, None, self.nicmod,
3326 5eacbcae Thomas Thrainer
                        _PrepareNicCreate, _PrepareNicMod, _PrepareNicRemove)
3327 22b7f6f8 Thomas Thrainer
    if len(nics) > constants.MAX_NICS:
3328 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Instance has too many network interfaces"
3329 22b7f6f8 Thomas Thrainer
                                 " (%d), cannot add more" % constants.MAX_NICS,
3330 22b7f6f8 Thomas Thrainer
                                 errors.ECODE_STATE)
3331 22b7f6f8 Thomas Thrainer
3332 22b7f6f8 Thomas Thrainer
    # Pre-compute NIC changes (necessary to use result in hooks)
3333 22b7f6f8 Thomas Thrainer
    self._nic_chgdesc = []
3334 22b7f6f8 Thomas Thrainer
    if self.nicmod:
3335 22b7f6f8 Thomas Thrainer
      # Operate on copies as this is still in prereq
3336 d0d7d7cf Thomas Thrainer
      nics = [nic.Copy() for nic in self.instance.nics]
3337 5eacbcae Thomas Thrainer
      _ApplyContainerMods("NIC", nics, self._nic_chgdesc, self.nicmod,
3338 ba924970 Dimitris Aragiorgis
                          self._CreateNewNic, self._ApplyNicMods,
3339 ba924970 Dimitris Aragiorgis
                          self._RemoveNic)
3340 22b7f6f8 Thomas Thrainer
      # Verify that NIC names are unique and valid
3341 22b7f6f8 Thomas Thrainer
      utils.ValidateDeviceNames("NIC", nics)
3342 22b7f6f8 Thomas Thrainer
      self._new_nics = nics
3343 22b7f6f8 Thomas Thrainer
      ispec[constants.ISPEC_NIC_COUNT] = len(self._new_nics)
3344 22b7f6f8 Thomas Thrainer
    else:
3345 22b7f6f8 Thomas Thrainer
      self._new_nics = None
3346 d0d7d7cf Thomas Thrainer
      ispec[constants.ISPEC_NIC_COUNT] = len(self.instance.nics)
3347 22b7f6f8 Thomas Thrainer
3348 22b7f6f8 Thomas Thrainer
    if not self.op.ignore_ipolicy:
3349 d0d7d7cf Thomas Thrainer
      ipolicy = ganeti.masterd.instance.CalculateGroupIPolicy(self.cluster,
3350 22b7f6f8 Thomas Thrainer
                                                              group_info)
3351 22b7f6f8 Thomas Thrainer
3352 22b7f6f8 Thomas Thrainer
      # Fill ispec with backend parameters
3353 22b7f6f8 Thomas Thrainer
      ispec[constants.ISPEC_SPINDLE_USE] = \
3354 22b7f6f8 Thomas Thrainer
        self.be_new.get(constants.BE_SPINDLE_USE, None)
3355 22b7f6f8 Thomas Thrainer
      ispec[constants.ISPEC_CPU_COUNT] = self.be_new.get(constants.BE_VCPUS,
3356 22b7f6f8 Thomas Thrainer
                                                         None)
3357 22b7f6f8 Thomas Thrainer
3358 22b7f6f8 Thomas Thrainer
      # Copy ispec to verify parameters with min/max values separately
3359 22b7f6f8 Thomas Thrainer
      if self.op.disk_template:
3360 22b7f6f8 Thomas Thrainer
        new_disk_template = self.op.disk_template
3361 22b7f6f8 Thomas Thrainer
      else:
3362 d0d7d7cf Thomas Thrainer
        new_disk_template = self.instance.disk_template
3363 22b7f6f8 Thomas Thrainer
      ispec_max = ispec.copy()
3364 22b7f6f8 Thomas Thrainer
      ispec_max[constants.ISPEC_MEM_SIZE] = \
3365 22b7f6f8 Thomas Thrainer
        self.be_new.get(constants.BE_MAXMEM, None)
3366 22b7f6f8 Thomas Thrainer
      res_max = _ComputeIPolicyInstanceSpecViolation(ipolicy, ispec_max,
3367 22b7f6f8 Thomas Thrainer
                                                     new_disk_template)
3368 22b7f6f8 Thomas Thrainer
      ispec_min = ispec.copy()
3369 22b7f6f8 Thomas Thrainer
      ispec_min[constants.ISPEC_MEM_SIZE] = \
3370 22b7f6f8 Thomas Thrainer
        self.be_new.get(constants.BE_MINMEM, None)
3371 22b7f6f8 Thomas Thrainer
      res_min = _ComputeIPolicyInstanceSpecViolation(ipolicy, ispec_min,
3372 22b7f6f8 Thomas Thrainer
                                                     new_disk_template)
3373 22b7f6f8 Thomas Thrainer
3374 22b7f6f8 Thomas Thrainer
      if (res_max or res_min):
3375 22b7f6f8 Thomas Thrainer
        # FIXME: Improve error message by including information about whether
3376 22b7f6f8 Thomas Thrainer
        # the upper or lower limit of the parameter fails the ipolicy.
3377 22b7f6f8 Thomas Thrainer
        msg = ("Instance allocation to group %s (%s) violates policy: %s" %
3378 22b7f6f8 Thomas Thrainer
               (group_info, group_info.name,
3379 22b7f6f8 Thomas Thrainer
                utils.CommaJoin(set(res_max + res_min))))
3380 22b7f6f8 Thomas Thrainer
        raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
3381 22b7f6f8 Thomas Thrainer
3382 22b7f6f8 Thomas Thrainer
  def _ConvertPlainToDrbd(self, feedback_fn):
3383 22b7f6f8 Thomas Thrainer
    """Converts an instance from plain to drbd.
3384 22b7f6f8 Thomas Thrainer

3385 22b7f6f8 Thomas Thrainer
    """
3386 22b7f6f8 Thomas Thrainer
    feedback_fn("Converting template to drbd")
3387 d0d7d7cf Thomas Thrainer
    pnode_uuid = self.instance.primary_node
3388 1c3231aa Thomas Thrainer
    snode_uuid = self.op.remote_node_uuid
3389 22b7f6f8 Thomas Thrainer
3390 d0d7d7cf Thomas Thrainer
    assert self.instance.disk_template == constants.DT_PLAIN
3391 22b7f6f8 Thomas Thrainer
3392 22b7f6f8 Thomas Thrainer
    # create a fake disk info for _GenerateDiskTemplate
3393 22b7f6f8 Thomas Thrainer
    disk_info = [{constants.IDISK_SIZE: d.size, constants.IDISK_MODE: d.mode,
3394 22b7f6f8 Thomas Thrainer
                  constants.IDISK_VG: d.logical_id[0],
3395 22b7f6f8 Thomas Thrainer
                  constants.IDISK_NAME: d.name}
3396 d0d7d7cf Thomas Thrainer
                 for d in self.instance.disks]
3397 5eacbcae Thomas Thrainer
    new_disks = GenerateDiskTemplate(self, self.op.disk_template,
3398 da4a52a3 Thomas Thrainer
                                     self.instance.uuid, pnode_uuid,
3399 d0d7d7cf Thomas Thrainer
                                     [snode_uuid], disk_info, None, None, 0,
3400 d0d7d7cf Thomas Thrainer
                                     feedback_fn, self.diskparams)
3401 0c3d9c7c Thomas Thrainer
    anno_disks = rpc.AnnotateDiskParams(new_disks, self.diskparams)
3402 1c3231aa Thomas Thrainer
    p_excl_stor = IsExclusiveStorageEnabledNodeUuid(self.cfg, pnode_uuid)
3403 1c3231aa Thomas Thrainer
    s_excl_stor = IsExclusiveStorageEnabledNodeUuid(self.cfg, snode_uuid)
3404 d0d7d7cf Thomas Thrainer
    info = GetInstanceInfoText(self.instance)
3405 22b7f6f8 Thomas Thrainer
    feedback_fn("Creating additional volumes...")
3406 22b7f6f8 Thomas Thrainer
    # first, create the missing data and meta devices
3407 22b7f6f8 Thomas Thrainer
    for disk in anno_disks:
3408 22b7f6f8 Thomas Thrainer
      # unfortunately this is... not too nice
3409 d0d7d7cf Thomas Thrainer
      CreateSingleBlockDev(self, pnode_uuid, self.instance, disk.children[1],
3410 5eacbcae Thomas Thrainer
                           info, True, p_excl_stor)
3411 22b7f6f8 Thomas Thrainer
      for child in disk.children:
3412 d0d7d7cf Thomas Thrainer
        CreateSingleBlockDev(self, snode_uuid, self.instance, child, info, True,
3413 5eacbcae Thomas Thrainer
                             s_excl_stor)
3414 22b7f6f8 Thomas Thrainer
    # at this stage, all new LVs have been created, we can rename the
3415 22b7f6f8 Thomas Thrainer
    # old ones
3416 22b7f6f8 Thomas Thrainer
    feedback_fn("Renaming original volumes...")
3417 22b7f6f8 Thomas Thrainer
    rename_list = [(o, n.children[0].logical_id)
3418 d0d7d7cf Thomas Thrainer
                   for (o, n) in zip(self.instance.disks, new_disks)]
3419 1c3231aa Thomas Thrainer
    result = self.rpc.call_blockdev_rename(pnode_uuid, rename_list)
3420 22b7f6f8 Thomas Thrainer
    result.Raise("Failed to rename original LVs")
3421 22b7f6f8 Thomas Thrainer
3422 22b7f6f8 Thomas Thrainer
    feedback_fn("Initializing DRBD devices...")
3423 22b7f6f8 Thomas Thrainer
    # all child devices are in place, we can now create the DRBD devices
3424 22b7f6f8 Thomas Thrainer
    try:
3425 22b7f6f8 Thomas Thrainer
      for disk in anno_disks:
3426 1c3231aa Thomas Thrainer
        for (node_uuid, excl_stor) in [(pnode_uuid, p_excl_stor),
3427 1c3231aa Thomas Thrainer
                                       (snode_uuid, s_excl_stor)]:
3428 1c3231aa Thomas Thrainer
          f_create = node_uuid == pnode_uuid
3429 d0d7d7cf Thomas Thrainer
          CreateSingleBlockDev(self, node_uuid, self.instance, disk, info,
3430 d0d7d7cf Thomas Thrainer
                               f_create, excl_stor)
3431 22b7f6f8 Thomas Thrainer
    except errors.GenericError, e:
3432 22b7f6f8 Thomas Thrainer
      feedback_fn("Initializing of DRBD devices failed;"
3433 22b7f6f8 Thomas Thrainer
                  " renaming back original volumes...")
3434 22b7f6f8 Thomas Thrainer
      rename_back_list = [(n.children[0], o.logical_id)
3435 d0d7d7cf Thomas Thrainer
                          for (n, o) in zip(new_disks, self.instance.disks)]
3436 1c3231aa Thomas Thrainer
      result = self.rpc.call_blockdev_rename(pnode_uuid, rename_back_list)
3437 22b7f6f8 Thomas Thrainer
      result.Raise("Failed to rename LVs back after error %s" % str(e))
3438 22b7f6f8 Thomas Thrainer
      raise
3439 22b7f6f8 Thomas Thrainer
3440 22b7f6f8 Thomas Thrainer
    # at this point, the instance has been modified
3441 d0d7d7cf Thomas Thrainer
    self.instance.disk_template = constants.DT_DRBD8
3442 d0d7d7cf Thomas Thrainer
    self.instance.disks = new_disks
3443 d0d7d7cf Thomas Thrainer
    self.cfg.Update(self.instance, feedback_fn)
3444 22b7f6f8 Thomas Thrainer
3445 22b7f6f8 Thomas Thrainer
    # Release node locks while waiting for sync
3446 5eacbcae Thomas Thrainer
    ReleaseLocks(self, locking.LEVEL_NODE)
3447 22b7f6f8 Thomas Thrainer
3448 22b7f6f8 Thomas Thrainer
    # disks are created, waiting for sync
3449 d0d7d7cf Thomas Thrainer
    disk_abort = not WaitForSync(self, self.instance,
3450 5eacbcae Thomas Thrainer
                                 oneshot=not self.op.wait_for_sync)
3451 22b7f6f8 Thomas Thrainer
    if disk_abort:
3452 22b7f6f8 Thomas Thrainer
      raise errors.OpExecError("There are some degraded disks for"
3453 22b7f6f8 Thomas Thrainer
                               " this instance, please cleanup manually")
3454 22b7f6f8 Thomas Thrainer
3455 22b7f6f8 Thomas Thrainer
    # Node resource locks will be released by caller
3456 22b7f6f8 Thomas Thrainer
3457 22b7f6f8 Thomas Thrainer
  def _ConvertDrbdToPlain(self, feedback_fn):
3458 22b7f6f8 Thomas Thrainer
    """Converts an instance from drbd to plain.
3459 22b7f6f8 Thomas Thrainer

3460 22b7f6f8 Thomas Thrainer
    """
3461 d0d7d7cf Thomas Thrainer
    assert len(self.instance.secondary_nodes) == 1
3462 d0d7d7cf Thomas Thrainer
    assert self.instance.disk_template == constants.DT_DRBD8
3463 22b7f6f8 Thomas Thrainer
3464 d0d7d7cf Thomas Thrainer
    pnode_uuid = self.instance.primary_node
3465 d0d7d7cf Thomas Thrainer
    snode_uuid = self.instance.secondary_nodes[0]
3466 22b7f6f8 Thomas Thrainer
    feedback_fn("Converting template to plain")
3467 22b7f6f8 Thomas Thrainer
3468 d0d7d7cf Thomas Thrainer
    old_disks = AnnotateDiskParams(self.instance, self.instance.disks, self.cfg)
3469 d0d7d7cf Thomas Thrainer
    new_disks = [d.children[0] for d in self.instance.disks]
3470 22b7f6f8 Thomas Thrainer
3471 22b7f6f8 Thomas Thrainer
    # copy over size, mode and name
3472 22b7f6f8 Thomas Thrainer
    for parent, child in zip(old_disks, new_disks):
3473 22b7f6f8 Thomas Thrainer
      child.size = parent.size
3474 22b7f6f8 Thomas Thrainer
      child.mode = parent.mode
3475 22b7f6f8 Thomas Thrainer
      child.name = parent.name
3476 22b7f6f8 Thomas Thrainer
3477 22b7f6f8 Thomas Thrainer
    # this is a DRBD disk, return its port to the pool
3478 22b7f6f8 Thomas Thrainer
    # NOTE: this must be done right before the call to cfg.Update!
3479 22b7f6f8 Thomas Thrainer
    for disk in old_disks:
3480 22b7f6f8 Thomas Thrainer
      tcp_port = disk.logical_id[2]
3481 22b7f6f8 Thomas Thrainer
      self.cfg.AddTcpUdpPort(tcp_port)
3482 22b7f6f8 Thomas Thrainer
3483 22b7f6f8 Thomas Thrainer
    # update instance structure
3484 d0d7d7cf Thomas Thrainer
    self.instance.disks = new_disks
3485 d0d7d7cf Thomas Thrainer
    self.instance.disk_template = constants.DT_PLAIN
3486 d0d7d7cf Thomas Thrainer
    _UpdateIvNames(0, self.instance.disks)
3487 d0d7d7cf Thomas Thrainer
    self.cfg.Update(self.instance, feedback_fn)
3488 22b7f6f8 Thomas Thrainer
3489 22b7f6f8 Thomas Thrainer
    # Release locks in case removing disks takes a while
3490 5eacbcae Thomas Thrainer
    ReleaseLocks(self, locking.LEVEL_NODE)
3491 22b7f6f8 Thomas Thrainer
3492 22b7f6f8 Thomas Thrainer
    feedback_fn("Removing volumes on the secondary node...")
3493 22b7f6f8 Thomas Thrainer
    for disk in old_disks:
3494 0c3d9c7c Thomas Thrainer
      result = self.rpc.call_blockdev_remove(snode_uuid, (disk, self.instance))
3495 aefc2f89 Thomas Thrainer
      result.Warn("Could not remove block device %s on node %s,"
3496 aefc2f89 Thomas Thrainer
                  " continuing anyway" %
3497 aefc2f89 Thomas Thrainer
                  (disk.iv_name, self.cfg.GetNodeName(snode_uuid)),
3498 aefc2f89 Thomas Thrainer
                  self.LogWarning)
3499 22b7f6f8 Thomas Thrainer
3500 22b7f6f8 Thomas Thrainer
    feedback_fn("Removing unneeded volumes on the primary node...")
3501 22b7f6f8 Thomas Thrainer
    for idx, disk in enumerate(old_disks):
3502 22b7f6f8 Thomas Thrainer
      meta = disk.children[1]
3503 0c3d9c7c Thomas Thrainer
      result = self.rpc.call_blockdev_remove(pnode_uuid, (meta, self.instance))
3504 aefc2f89 Thomas Thrainer
      result.Warn("Could not remove metadata for disk %d on node %s,"
3505 aefc2f89 Thomas Thrainer
                  " continuing anyway" %
3506 aefc2f89 Thomas Thrainer
                  (idx, self.cfg.GetNodeName(pnode_uuid)),
3507 aefc2f89 Thomas Thrainer
                  self.LogWarning)
3508 22b7f6f8 Thomas Thrainer
3509 ba924970 Dimitris Aragiorgis
  def _HotplugDevice(self, action, dev_type, device, extra, seq):
3510 ba924970 Dimitris Aragiorgis
    self.LogInfo("Trying to hotplug device...")
3511 e15a00dc Dimitris Aragiorgis
    msg = "hotplug:"
3512 ba924970 Dimitris Aragiorgis
    result = self.rpc.call_hotplug_device(self.instance.primary_node,
3513 ba924970 Dimitris Aragiorgis
                                          self.instance, action, dev_type,
3514 51951d38 Dimitris Aragiorgis
                                          (device, self.instance),
3515 51951d38 Dimitris Aragiorgis
                                          extra, seq)
3516 ba924970 Dimitris Aragiorgis
    if result.fail_msg:
3517 ba924970 Dimitris Aragiorgis
      self.LogWarning("Could not hotplug device: %s" % result.fail_msg)
3518 ba924970 Dimitris Aragiorgis
      self.LogInfo("Continuing execution..")
3519 e15a00dc Dimitris Aragiorgis
      msg += "failed"
3520 ba924970 Dimitris Aragiorgis
    else:
3521 ba924970 Dimitris Aragiorgis
      self.LogInfo("Hotplug done.")
3522 e15a00dc Dimitris Aragiorgis
      msg += "done"
3523 e15a00dc Dimitris Aragiorgis
    return msg
3524 ba924970 Dimitris Aragiorgis
3525 22b7f6f8 Thomas Thrainer
  def _CreateNewDisk(self, idx, params, _):
3526 22b7f6f8 Thomas Thrainer
    """Creates a new disk.
3527 22b7f6f8 Thomas Thrainer

3528 22b7f6f8 Thomas Thrainer
    """
3529 22b7f6f8 Thomas Thrainer
    # add a new disk
3530 d0d7d7cf Thomas Thrainer
    if self.instance.disk_template in constants.DTS_FILEBASED:
3531 d0d7d7cf Thomas Thrainer
      (file_driver, file_path) = self.instance.disks[0].logical_id
3532 22b7f6f8 Thomas Thrainer
      file_path = os.path.dirname(file_path)
3533 22b7f6f8 Thomas Thrainer
    else:
3534 22b7f6f8 Thomas Thrainer
      file_driver = file_path = None
3535 22b7f6f8 Thomas Thrainer
3536 22b7f6f8 Thomas Thrainer
    disk = \
3537 d0d7d7cf Thomas Thrainer
      GenerateDiskTemplate(self, self.instance.disk_template,
3538 da4a52a3 Thomas Thrainer
                           self.instance.uuid, self.instance.primary_node,
3539 d0d7d7cf Thomas Thrainer
                           self.instance.secondary_nodes, [params], file_path,
3540 d0d7d7cf Thomas Thrainer
                           file_driver, idx, self.Log, self.diskparams)[0]
3541 22b7f6f8 Thomas Thrainer
3542 d0d7d7cf Thomas Thrainer
    new_disks = CreateDisks(self, self.instance, disks=[disk])
3543 22b7f6f8 Thomas Thrainer
3544 22b7f6f8 Thomas Thrainer
    if self.cluster.prealloc_wipe_disks:
3545 22b7f6f8 Thomas Thrainer
      # Wipe new disk
3546 d0d7d7cf Thomas Thrainer
      WipeOrCleanupDisks(self, self.instance,
3547 a365b47f Bernardo Dal Seno
                         disks=[(idx, disk, 0)],
3548 a365b47f Bernardo Dal Seno
                         cleanup=new_disks)
3549 22b7f6f8 Thomas Thrainer
3550 e15a00dc Dimitris Aragiorgis
    changes = [
3551 e15a00dc Dimitris Aragiorgis
      ("disk/%d" % idx,
3552 b15d5bd3 Petr Pudlak
       "add:size=%s,mode=%s" % (disk.size, disk.mode)),
3553 e15a00dc Dimitris Aragiorgis
      ]
3554 ba924970 Dimitris Aragiorgis
    if self.op.hotplug:
3555 ba924970 Dimitris Aragiorgis
      result = self.rpc.call_blockdev_assemble(self.instance.primary_node,
3556 ba924970 Dimitris Aragiorgis
                                               (disk, self.instance),
3557 ba924970 Dimitris Aragiorgis
                                               self.instance.name, True, idx)
3558 ba924970 Dimitris Aragiorgis
      if result.fail_msg:
3559 e15a00dc Dimitris Aragiorgis
        changes.append(("disk/%d" % idx, "assemble:failed"))
3560 ba924970 Dimitris Aragiorgis
        self.LogWarning("Can't assemble newly created disk %d: %s",
3561 ba924970 Dimitris Aragiorgis
                        idx, result.fail_msg)
3562 ba924970 Dimitris Aragiorgis
      else:
3563 ba924970 Dimitris Aragiorgis
        _, link_name = result.payload
3564 e15a00dc Dimitris Aragiorgis
        msg = self._HotplugDevice(constants.HOTPLUG_ACTION_ADD,
3565 e15a00dc Dimitris Aragiorgis
                                  constants.HOTPLUG_TARGET_DISK,
3566 e15a00dc Dimitris Aragiorgis
                                  disk, link_name, idx)
3567 e15a00dc Dimitris Aragiorgis
        changes.append(("disk/%d" % idx, msg))
3568 ba924970 Dimitris Aragiorgis
3569 e15a00dc Dimitris Aragiorgis
    return (disk, changes)
3570 22b7f6f8 Thomas Thrainer
3571 922a9e65 Thomas Thrainer
  def _PostAddDisk(self, _, disk):
3572 922a9e65 Thomas Thrainer
    if not WaitForSync(self, self.instance, disks=[disk],
3573 922a9e65 Thomas Thrainer
                       oneshot=not self.op.wait_for_sync):
3574 922a9e65 Thomas Thrainer
      raise errors.OpExecError("Failed to sync disks of %s" %
3575 922a9e65 Thomas Thrainer
                               self.instance.name)
3576 922a9e65 Thomas Thrainer
3577 3c260845 Thomas Thrainer
    # the disk is active at this point, so deactivate it if the instance disks
3578 3c260845 Thomas Thrainer
    # are supposed to be inactive
3579 3c260845 Thomas Thrainer
    if not self.instance.disks_active:
3580 3c260845 Thomas Thrainer
      ShutdownInstanceDisks(self, self.instance, disks=[disk])
3581 3c260845 Thomas Thrainer
3582 c5c72215 Dimitris Aragiorgis
  def _ModifyDisk(self, idx, disk, params, _):
3583 22b7f6f8 Thomas Thrainer
    """Modifies a disk.
3584 22b7f6f8 Thomas Thrainer

3585 22b7f6f8 Thomas Thrainer
    """
3586 22b7f6f8 Thomas Thrainer
    changes = []
3587 4eef428e Dimitris Aragiorgis
    if constants.IDISK_MODE in params:
3588 4eef428e Dimitris Aragiorgis
      disk.mode = params.get(constants.IDISK_MODE)
3589 22b7f6f8 Thomas Thrainer
      changes.append(("disk.mode/%d" % idx, disk.mode))
3590 22b7f6f8 Thomas Thrainer
3591 4eef428e Dimitris Aragiorgis
    if constants.IDISK_NAME in params:
3592 4eef428e Dimitris Aragiorgis
      disk.name = params.get(constants.IDISK_NAME)
3593 4eef428e Dimitris Aragiorgis
      changes.append(("disk.name/%d" % idx, disk.name))
3594 22b7f6f8 Thomas Thrainer
3595 c5c72215 Dimitris Aragiorgis
    # Modify arbitrary params in case instance template is ext
3596 c5c72215 Dimitris Aragiorgis
    for key, value in params.iteritems():
3597 c5c72215 Dimitris Aragiorgis
      if (key not in constants.MODIFIABLE_IDISK_PARAMS and
3598 c5c72215 Dimitris Aragiorgis
          self.instance.disk_template == constants.DT_EXT):
3599 e228ab9c Dimitris Aragiorgis
        # stolen from GetUpdatedParams: default means reset/delete
3600 e228ab9c Dimitris Aragiorgis
        if value.lower() == constants.VALUE_DEFAULT:
3601 e228ab9c Dimitris Aragiorgis
          try:
3602 e228ab9c Dimitris Aragiorgis
            del disk.params[key]
3603 e228ab9c Dimitris Aragiorgis
          except KeyError:
3604 e228ab9c Dimitris Aragiorgis
            pass
3605 e228ab9c Dimitris Aragiorgis
        else:
3606 e228ab9c Dimitris Aragiorgis
          disk.params[key] = value
3607 c5c72215 Dimitris Aragiorgis
        changes.append(("disk.params:%s/%d" % (key, idx), value))
3608 22b7f6f8 Thomas Thrainer
3609 22b7f6f8 Thomas Thrainer
    return changes
3610 22b7f6f8 Thomas Thrainer
3611 22b7f6f8 Thomas Thrainer
  def _RemoveDisk(self, idx, root, _):
3612 22b7f6f8 Thomas Thrainer
    """Removes a disk.
3613 22b7f6f8 Thomas Thrainer

3614 22b7f6f8 Thomas Thrainer
    """
3615 e15a00dc Dimitris Aragiorgis
    hotmsg = ""
3616 ba924970 Dimitris Aragiorgis
    if self.op.hotplug:
3617 e15a00dc Dimitris Aragiorgis
      hotmsg = self._HotplugDevice(constants.HOTPLUG_ACTION_REMOVE,
3618 e15a00dc Dimitris Aragiorgis
                                   constants.HOTPLUG_TARGET_DISK,
3619 e15a00dc Dimitris Aragiorgis
                                   root, None, idx)
3620 ba924970 Dimitris Aragiorgis
      ShutdownInstanceDisks(self, self.instance, [root])
3621 ba924970 Dimitris Aragiorgis
3622 5eacbcae Thomas Thrainer
    (anno_disk,) = AnnotateDiskParams(self.instance, [root], self.cfg)
3623 1c3231aa Thomas Thrainer
    for node_uuid, disk in anno_disk.ComputeNodeTree(
3624 1c3231aa Thomas Thrainer
                             self.instance.primary_node):
3625 0c3d9c7c Thomas Thrainer
      msg = self.rpc.call_blockdev_remove(node_uuid, (disk, self.instance)) \
3626 0c3d9c7c Thomas Thrainer
              .fail_msg
3627 22b7f6f8 Thomas Thrainer
      if msg:
3628 22b7f6f8 Thomas Thrainer
        self.LogWarning("Could not remove disk/%d on node '%s': %s,"
3629 1c3231aa Thomas Thrainer
                        " continuing anyway", idx,
3630 1c3231aa Thomas Thrainer
                        self.cfg.GetNodeName(node_uuid), msg)
3631 22b7f6f8 Thomas Thrainer
3632 22b7f6f8 Thomas Thrainer
    # if this is a DRBD disk, return its port to the pool
3633 66a37e7a Helga Velroyen
    if root.dev_type in constants.DTS_DRBD:
3634 22b7f6f8 Thomas Thrainer
      self.cfg.AddTcpUdpPort(root.logical_id[2])
3635 22b7f6f8 Thomas Thrainer
3636 e15a00dc Dimitris Aragiorgis
    return hotmsg
3637 e15a00dc Dimitris Aragiorgis
3638 22b7f6f8 Thomas Thrainer
  def _CreateNewNic(self, idx, params, private):
3639 22b7f6f8 Thomas Thrainer
    """Creates data structure for a new network interface.
3640 22b7f6f8 Thomas Thrainer

3641 22b7f6f8 Thomas Thrainer
    """
3642 22b7f6f8 Thomas Thrainer
    mac = params[constants.INIC_MAC]
3643 22b7f6f8 Thomas Thrainer
    ip = params.get(constants.INIC_IP, None)
3644 22b7f6f8 Thomas Thrainer
    net = params.get(constants.INIC_NETWORK, None)
3645 22b7f6f8 Thomas Thrainer
    name = params.get(constants.INIC_NAME, None)
3646 22b7f6f8 Thomas Thrainer
    net_uuid = self.cfg.LookupNetwork(net)
3647 22b7f6f8 Thomas Thrainer
    #TODO: not private.filled?? can a nic have no nicparams??
3648 22b7f6f8 Thomas Thrainer
    nicparams = private.filled
3649 22b7f6f8 Thomas Thrainer
    nobj = objects.NIC(mac=mac, ip=ip, network=net_uuid, name=name,
3650 22b7f6f8 Thomas Thrainer
                       nicparams=nicparams)
3651 22b7f6f8 Thomas Thrainer
    nobj.uuid = self.cfg.GenerateUniqueID(self.proc.GetECId())
3652 22b7f6f8 Thomas Thrainer
3653 e15a00dc Dimitris Aragiorgis
    changes = [
3654 22b7f6f8 Thomas Thrainer
      ("nic.%d" % idx,
3655 22b7f6f8 Thomas Thrainer
       "add:mac=%s,ip=%s,mode=%s,link=%s,network=%s" %
3656 22b7f6f8 Thomas Thrainer
       (mac, ip, private.filled[constants.NIC_MODE],
3657 ba924970 Dimitris Aragiorgis
       private.filled[constants.NIC_LINK], net)),
3658 ba924970 Dimitris Aragiorgis
      ]
3659 ba924970 Dimitris Aragiorgis
3660 e15a00dc Dimitris Aragiorgis
    if self.op.hotplug:
3661 e15a00dc Dimitris Aragiorgis
      msg = self._HotplugDevice(constants.HOTPLUG_ACTION_ADD,
3662 e15a00dc Dimitris Aragiorgis
                                constants.HOTPLUG_TARGET_NIC,
3663 e15a00dc Dimitris Aragiorgis
                                nobj, None, idx)
3664 e15a00dc Dimitris Aragiorgis
      changes.append(("nic.%d" % idx, msg))
3665 e15a00dc Dimitris Aragiorgis
3666 e15a00dc Dimitris Aragiorgis
    return (nobj, changes)
3667 22b7f6f8 Thomas Thrainer
3668 22b7f6f8 Thomas Thrainer
  def _ApplyNicMods(self, idx, nic, params, private):
3669 22b7f6f8 Thomas Thrainer
    """Modifies a network interface.
3670 22b7f6f8 Thomas Thrainer

3671 22b7f6f8 Thomas Thrainer
    """
3672 22b7f6f8 Thomas Thrainer
    changes = []
3673 22b7f6f8 Thomas Thrainer
3674 22b7f6f8 Thomas Thrainer
    for key in [constants.INIC_MAC, constants.INIC_IP, constants.INIC_NAME]:
3675 22b7f6f8 Thomas Thrainer
      if key in params:
3676 22b7f6f8 Thomas Thrainer
        changes.append(("nic.%s/%d" % (key, idx), params[key]))
3677 22b7f6f8 Thomas Thrainer
        setattr(nic, key, params[key])
3678 22b7f6f8 Thomas Thrainer
3679 22b7f6f8 Thomas Thrainer
    new_net = params.get(constants.INIC_NETWORK, nic.network)
3680 22b7f6f8 Thomas Thrainer
    new_net_uuid = self.cfg.LookupNetwork(new_net)
3681 22b7f6f8 Thomas Thrainer
    if new_net_uuid != nic.network:
3682 22b7f6f8 Thomas Thrainer
      changes.append(("nic.network/%d" % idx, new_net))
3683 22b7f6f8 Thomas Thrainer
      nic.network = new_net_uuid
3684 22b7f6f8 Thomas Thrainer
3685 22b7f6f8 Thomas Thrainer
    if private.filled:
3686 22b7f6f8 Thomas Thrainer
      nic.nicparams = private.filled
3687 22b7f6f8 Thomas Thrainer
3688 22b7f6f8 Thomas Thrainer
      for (key, val) in nic.nicparams.items():
3689 22b7f6f8 Thomas Thrainer
        changes.append(("nic.%s/%d" % (key, idx), val))
3690 22b7f6f8 Thomas Thrainer
3691 ba924970 Dimitris Aragiorgis
    if self.op.hotplug:
3692 e15a00dc Dimitris Aragiorgis
      msg = self._HotplugDevice(constants.HOTPLUG_ACTION_MODIFY,
3693 e15a00dc Dimitris Aragiorgis
                                constants.HOTPLUG_TARGET_NIC,
3694 e15a00dc Dimitris Aragiorgis
                                nic, None, idx)
3695 e15a00dc Dimitris Aragiorgis
      changes.append(("nic/%d" % idx, msg))
3696 ba924970 Dimitris Aragiorgis
3697 22b7f6f8 Thomas Thrainer
    return changes
3698 22b7f6f8 Thomas Thrainer
3699 ba924970 Dimitris Aragiorgis
  def _RemoveNic(self, idx, nic, _):
3700 ba924970 Dimitris Aragiorgis
    if self.op.hotplug:
3701 e15a00dc Dimitris Aragiorgis
      return self._HotplugDevice(constants.HOTPLUG_ACTION_REMOVE,
3702 e15a00dc Dimitris Aragiorgis
                                 constants.HOTPLUG_TARGET_NIC,
3703 e15a00dc Dimitris Aragiorgis
                                 nic, None, idx)
3704 ba924970 Dimitris Aragiorgis
3705 22b7f6f8 Thomas Thrainer
  def Exec(self, feedback_fn):
3706 22b7f6f8 Thomas Thrainer
    """Modifies an instance.
3707 22b7f6f8 Thomas Thrainer

3708 22b7f6f8 Thomas Thrainer
    All parameters take effect only at the next restart of the instance.
3709 22b7f6f8 Thomas Thrainer

3710 22b7f6f8 Thomas Thrainer
    """
3711 22b7f6f8 Thomas Thrainer
    # Process here the warnings from CheckPrereq, as we don't have a
3712 22b7f6f8 Thomas Thrainer
    # feedback_fn there.
3713 22b7f6f8 Thomas Thrainer
    # TODO: Replace with self.LogWarning
3714 22b7f6f8 Thomas Thrainer
    for warn in self.warn:
3715 22b7f6f8 Thomas Thrainer
      feedback_fn("WARNING: %s" % warn)
3716 22b7f6f8 Thomas Thrainer
3717 22b7f6f8 Thomas Thrainer
    assert ((self.op.disk_template is None) ^
3718 22b7f6f8 Thomas Thrainer
            bool(self.owned_locks(locking.LEVEL_NODE_RES))), \
3719 22b7f6f8 Thomas Thrainer
      "Not owning any node resource locks"
3720 22b7f6f8 Thomas Thrainer
3721 22b7f6f8 Thomas Thrainer
    result = []
3722 22b7f6f8 Thomas Thrainer
3723 22b7f6f8 Thomas Thrainer
    # New primary node
3724 1c3231aa Thomas Thrainer
    if self.op.pnode_uuid:
3725 d0d7d7cf Thomas Thrainer
      self.instance.primary_node = self.op.pnode_uuid
3726 22b7f6f8 Thomas Thrainer
3727 22b7f6f8 Thomas Thrainer
    # runtime memory
3728 22b7f6f8 Thomas Thrainer
    if self.op.runtime_mem:
3729 d0d7d7cf Thomas Thrainer
      rpcres = self.rpc.call_instance_balloon_memory(self.instance.primary_node,
3730 d0d7d7cf Thomas Thrainer
                                                     self.instance,
3731 22b7f6f8 Thomas Thrainer
                                                     self.op.runtime_mem)
3732 22b7f6f8 Thomas Thrainer
      rpcres.Raise("Cannot modify instance runtime memory")
3733 22b7f6f8 Thomas Thrainer
      result.append(("runtime_memory", self.op.runtime_mem))
3734 22b7f6f8 Thomas Thrainer
3735 22b7f6f8 Thomas Thrainer
    # Apply disk changes
3736 d0d7d7cf Thomas Thrainer
    _ApplyContainerMods("disk", self.instance.disks, result, self.diskmod,
3737 5eacbcae Thomas Thrainer
                        self._CreateNewDisk, self._ModifyDisk,
3738 922a9e65 Thomas Thrainer
                        self._RemoveDisk, post_add_fn=self._PostAddDisk)
3739 d0d7d7cf Thomas Thrainer
    _UpdateIvNames(0, self.instance.disks)
3740 22b7f6f8 Thomas Thrainer
3741 22b7f6f8 Thomas Thrainer
    if self.op.disk_template:
3742 22b7f6f8 Thomas Thrainer
      if __debug__:
3743 d0d7d7cf Thomas Thrainer
        check_nodes = set(self.instance.all_nodes)
3744 1c3231aa Thomas Thrainer
        if self.op.remote_node_uuid:
3745 1c3231aa Thomas Thrainer
          check_nodes.add(self.op.remote_node_uuid)
3746 22b7f6f8 Thomas Thrainer
        for level in [locking.LEVEL_NODE, locking.LEVEL_NODE_RES]:
3747 22b7f6f8 Thomas Thrainer
          owned = self.owned_locks(level)
3748 22b7f6f8 Thomas Thrainer
          assert not (check_nodes - owned), \
3749 22b7f6f8 Thomas Thrainer
            ("Not owning the correct locks, owning %r, expected at least %r" %
3750 22b7f6f8 Thomas Thrainer
             (owned, check_nodes))
3751 22b7f6f8 Thomas Thrainer
3752 d0d7d7cf Thomas Thrainer
      r_shut = ShutdownInstanceDisks(self, self.instance)
3753 22b7f6f8 Thomas Thrainer
      if not r_shut:
3754 22b7f6f8 Thomas Thrainer
        raise errors.OpExecError("Cannot shutdown instance disks, unable to"
3755 22b7f6f8 Thomas Thrainer
                                 " proceed with disk template conversion")
3756 d0d7d7cf Thomas Thrainer
      mode = (self.instance.disk_template, self.op.disk_template)
3757 22b7f6f8 Thomas Thrainer
      try:
3758 22b7f6f8 Thomas Thrainer
        self._DISK_CONVERSIONS[mode](self, feedback_fn)
3759 22b7f6f8 Thomas Thrainer
      except:
3760 da4a52a3 Thomas Thrainer
        self.cfg.ReleaseDRBDMinors(self.instance.uuid)
3761 22b7f6f8 Thomas Thrainer
        raise
3762 22b7f6f8 Thomas Thrainer
      result.append(("disk_template", self.op.disk_template))
3763 22b7f6f8 Thomas Thrainer
3764 d0d7d7cf Thomas Thrainer
      assert self.instance.disk_template == self.op.disk_template, \
3765 22b7f6f8 Thomas Thrainer
        ("Expected disk template '%s', found '%s'" %
3766 d0d7d7cf Thomas Thrainer
         (self.op.disk_template, self.instance.disk_template))
3767 22b7f6f8 Thomas Thrainer
3768 22b7f6f8 Thomas Thrainer
    # Release node and resource locks if there are any (they might already have
3769 22b7f6f8 Thomas Thrainer
    # been released during disk conversion)
3770 5eacbcae Thomas Thrainer
    ReleaseLocks(self, locking.LEVEL_NODE)
3771 5eacbcae Thomas Thrainer
    ReleaseLocks(self, locking.LEVEL_NODE_RES)
3772 22b7f6f8 Thomas Thrainer
3773 22b7f6f8 Thomas Thrainer
    # Apply NIC changes
3774 22b7f6f8 Thomas Thrainer
    if self._new_nics is not None:
3775 d0d7d7cf Thomas Thrainer
      self.instance.nics = self._new_nics
3776 22b7f6f8 Thomas Thrainer
      result.extend(self._nic_chgdesc)
3777 22b7f6f8 Thomas Thrainer
3778 22b7f6f8 Thomas Thrainer
    # hvparams changes
3779 22b7f6f8 Thomas Thrainer
    if self.op.hvparams:
3780 d0d7d7cf Thomas Thrainer
      self.instance.hvparams = self.hv_inst
3781 22b7f6f8 Thomas Thrainer
      for key, val in self.op.hvparams.iteritems():
3782 22b7f6f8 Thomas Thrainer
        result.append(("hv/%s" % key, val))
3783 22b7f6f8 Thomas Thrainer
3784 22b7f6f8 Thomas Thrainer
    # beparams changes
3785 22b7f6f8 Thomas Thrainer
    if self.op.beparams:
3786 d0d7d7cf Thomas Thrainer
      self.instance.beparams = self.be_inst
3787 22b7f6f8 Thomas Thrainer
      for key, val in self.op.beparams.iteritems():
3788 22b7f6f8 Thomas Thrainer
        result.append(("be/%s" % key, val))
3789 22b7f6f8 Thomas Thrainer
3790 22b7f6f8 Thomas Thrainer
    # OS change
3791 22b7f6f8 Thomas Thrainer
    if self.op.os_name:
3792 d0d7d7cf Thomas Thrainer
      self.instance.os = self.op.os_name
3793 22b7f6f8 Thomas Thrainer
3794 22b7f6f8 Thomas Thrainer
    # osparams changes
3795 22b7f6f8 Thomas Thrainer
    if self.op.osparams:
3796 d0d7d7cf Thomas Thrainer
      self.instance.osparams = self.os_inst
3797 22b7f6f8 Thomas Thrainer
      for key, val in self.op.osparams.iteritems():
3798 22b7f6f8 Thomas Thrainer
        result.append(("os/%s" % key, val))
3799 22b7f6f8 Thomas Thrainer
3800 1a182390 Santi Raffa
    if self.op.osparams_private:
3801 1a182390 Santi Raffa
      self.instance.osparams_private = self.os_inst_private
3802 1a182390 Santi Raffa
      for key, val in self.op.osparams_private.iteritems():
3803 1a182390 Santi Raffa
        # Show the Private(...) blurb.
3804 1a182390 Santi Raffa
        result.append(("os_private/%s" % key, repr(val)))
3805 1a182390 Santi Raffa
3806 22b7f6f8 Thomas Thrainer
    if self.op.offline is None:
3807 22b7f6f8 Thomas Thrainer
      # Ignore
3808 22b7f6f8 Thomas Thrainer
      pass
3809 22b7f6f8 Thomas Thrainer
    elif self.op.offline:
3810 22b7f6f8 Thomas Thrainer
      # Mark instance as offline
3811 da4a52a3 Thomas Thrainer
      self.cfg.MarkInstanceOffline(self.instance.uuid)
3812 22b7f6f8 Thomas Thrainer
      result.append(("admin_state", constants.ADMINST_OFFLINE))
3813 22b7f6f8 Thomas Thrainer
    else:
3814 22b7f6f8 Thomas Thrainer
      # Mark instance as online, but stopped
3815 da4a52a3 Thomas Thrainer
      self.cfg.MarkInstanceDown(self.instance.uuid)
3816 22b7f6f8 Thomas Thrainer
      result.append(("admin_state", constants.ADMINST_DOWN))
3817 22b7f6f8 Thomas Thrainer
3818 d0d7d7cf Thomas Thrainer
    self.cfg.Update(self.instance, feedback_fn, self.proc.GetECId())
3819 22b7f6f8 Thomas Thrainer
3820 22b7f6f8 Thomas Thrainer
    assert not (self.owned_locks(locking.LEVEL_NODE_RES) or
3821 22b7f6f8 Thomas Thrainer
                self.owned_locks(locking.LEVEL_NODE)), \
3822 22b7f6f8 Thomas Thrainer
      "All node locks should have been released by now"
3823 22b7f6f8 Thomas Thrainer
3824 22b7f6f8 Thomas Thrainer
    return result
3825 22b7f6f8 Thomas Thrainer
3826 22b7f6f8 Thomas Thrainer
  _DISK_CONVERSIONS = {
3827 22b7f6f8 Thomas Thrainer
    (constants.DT_PLAIN, constants.DT_DRBD8): _ConvertPlainToDrbd,
3828 22b7f6f8 Thomas Thrainer
    (constants.DT_DRBD8, constants.DT_PLAIN): _ConvertDrbdToPlain,
3829 22b7f6f8 Thomas Thrainer
    }
3830 22b7f6f8 Thomas Thrainer
3831 22b7f6f8 Thomas Thrainer
3832 22b7f6f8 Thomas Thrainer
class LUInstanceChangeGroup(LogicalUnit):
3833 22b7f6f8 Thomas Thrainer
  HPATH = "instance-change-group"
3834 22b7f6f8 Thomas Thrainer
  HTYPE = constants.HTYPE_INSTANCE
3835 22b7f6f8 Thomas Thrainer
  REQ_BGL = False
3836 22b7f6f8 Thomas Thrainer
3837 22b7f6f8 Thomas Thrainer
  def ExpandNames(self):
3838 5eacbcae Thomas Thrainer
    self.share_locks = ShareAll()
3839 22b7f6f8 Thomas Thrainer
3840 22b7f6f8 Thomas Thrainer
    self.needed_locks = {
3841 22b7f6f8 Thomas Thrainer
      locking.LEVEL_NODEGROUP: [],
3842 22b7f6f8 Thomas Thrainer
      locking.LEVEL_NODE: [],
3843 22b7f6f8 Thomas Thrainer
      locking.LEVEL_NODE_ALLOC: locking.ALL_SET,
3844 22b7f6f8 Thomas Thrainer
      }
3845 22b7f6f8 Thomas Thrainer
3846 22b7f6f8 Thomas Thrainer
    self._ExpandAndLockInstance()
3847 22b7f6f8 Thomas Thrainer
3848 22b7f6f8 Thomas Thrainer
    if self.op.target_groups:
3849 22b7f6f8 Thomas Thrainer
      self.req_target_uuids = map(self.cfg.LookupNodeGroup,
3850 22b7f6f8 Thomas Thrainer
                                  self.op.target_groups)
3851 22b7f6f8 Thomas Thrainer
    else:
3852 22b7f6f8 Thomas Thrainer
      self.req_target_uuids = None
3853 22b7f6f8 Thomas Thrainer
3854 5eacbcae Thomas Thrainer
    self.op.iallocator = GetDefaultIAllocator(self.cfg, self.op.iallocator)
3855 22b7f6f8 Thomas Thrainer
3856 22b7f6f8 Thomas Thrainer
  def DeclareLocks(self, level):
3857 22b7f6f8 Thomas Thrainer
    if level == locking.LEVEL_NODEGROUP:
3858 22b7f6f8 Thomas Thrainer
      assert not self.needed_locks[locking.LEVEL_NODEGROUP]
3859 22b7f6f8 Thomas Thrainer
3860 22b7f6f8 Thomas Thrainer
      if self.req_target_uuids:
3861 22b7f6f8 Thomas Thrainer
        lock_groups = set(self.req_target_uuids)
3862 22b7f6f8 Thomas Thrainer
3863 22b7f6f8 Thomas Thrainer
        # Lock all groups used by instance optimistically; this requires going
3864 22b7f6f8 Thomas Thrainer
        # via the node before it's locked, requiring verification later on
3865 da4a52a3 Thomas Thrainer
        instance_groups = self.cfg.GetInstanceNodeGroups(self.op.instance_uuid)
3866 22b7f6f8 Thomas Thrainer
        lock_groups.update(instance_groups)
3867 22b7f6f8 Thomas Thrainer
      else:
3868 22b7f6f8 Thomas Thrainer
        # No target groups, need to lock all of them
3869 22b7f6f8 Thomas Thrainer
        lock_groups = locking.ALL_SET
3870 22b7f6f8 Thomas Thrainer
3871 22b7f6f8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODEGROUP] = lock_groups
3872 22b7f6f8 Thomas Thrainer
3873 22b7f6f8 Thomas Thrainer
    elif level == locking.LEVEL_NODE:
3874 22b7f6f8 Thomas Thrainer
      if self.req_target_uuids:
3875 22b7f6f8 Thomas Thrainer
        # Lock all nodes used by instances
3876 22b7f6f8 Thomas Thrainer
        self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
3877 22b7f6f8 Thomas Thrainer
        self._LockInstancesNodes()
3878 22b7f6f8 Thomas Thrainer
3879 22b7f6f8 Thomas Thrainer
        # Lock all nodes in all potential target groups
3880 22b7f6f8 Thomas Thrainer
        lock_groups = (frozenset(self.owned_locks(locking.LEVEL_NODEGROUP)) -
3881 da4a52a3 Thomas Thrainer
                       self.cfg.GetInstanceNodeGroups(self.op.instance_uuid))
3882 1c3231aa Thomas Thrainer
        member_nodes = [node_uuid
3883 22b7f6f8 Thomas Thrainer
                        for group in lock_groups
3884 1c3231aa Thomas Thrainer
                        for node_uuid in self.cfg.GetNodeGroup(group).members]
3885 22b7f6f8 Thomas Thrainer
        self.needed_locks[locking.LEVEL_NODE].extend(member_nodes)
3886 22b7f6f8 Thomas Thrainer
      else:
3887 22b7f6f8 Thomas Thrainer
        # Lock all nodes as all groups are potential targets
3888 22b7f6f8 Thomas Thrainer
        self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
3889 22b7f6f8 Thomas Thrainer
3890 22b7f6f8 Thomas Thrainer
  def CheckPrereq(self):
3891 da4a52a3 Thomas Thrainer
    owned_instance_names = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
3892 22b7f6f8 Thomas Thrainer
    owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
3893 22b7f6f8 Thomas Thrainer
    owned_nodes = frozenset(self.owned_locks(locking.LEVEL_NODE))
3894 22b7f6f8 Thomas Thrainer
3895 22b7f6f8 Thomas Thrainer
    assert (self.req_target_uuids is None or
3896 22b7f6f8 Thomas Thrainer
            owned_groups.issuperset(self.req_target_uuids))
3897 da4a52a3 Thomas Thrainer
    assert owned_instance_names == set([self.op.instance_name])
3898 22b7f6f8 Thomas Thrainer
3899 22b7f6f8 Thomas Thrainer
    # Get instance information
3900 da4a52a3 Thomas Thrainer
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_uuid)
3901 22b7f6f8 Thomas Thrainer
3902 22b7f6f8 Thomas Thrainer
    # Check if node groups for locked instance are still correct
3903 22b7f6f8 Thomas Thrainer
    assert owned_nodes.issuperset(self.instance.all_nodes), \
3904 22b7f6f8 Thomas Thrainer
      ("Instance %s's nodes changed while we kept the lock" %
3905 22b7f6f8 Thomas Thrainer
       self.op.instance_name)
3906 22b7f6f8 Thomas Thrainer
3907 da4a52a3 Thomas Thrainer
    inst_groups = CheckInstanceNodeGroups(self.cfg, self.op.instance_uuid,
3908 5eacbcae Thomas Thrainer
                                          owned_groups)
3909 22b7f6f8 Thomas Thrainer
3910 22b7f6f8 Thomas Thrainer
    if self.req_target_uuids:
3911 22b7f6f8 Thomas Thrainer
      # User requested specific target groups
3912 22b7f6f8 Thomas Thrainer
      self.target_uuids = frozenset(self.req_target_uuids)
3913 22b7f6f8 Thomas Thrainer
    else:
3914 22b7f6f8 Thomas Thrainer
      # All groups except those used by the instance are potential targets
3915 22b7f6f8 Thomas Thrainer
      self.target_uuids = owned_groups - inst_groups
3916 22b7f6f8 Thomas Thrainer
3917 22b7f6f8 Thomas Thrainer
    conflicting_groups = self.target_uuids & inst_groups
3918 22b7f6f8 Thomas Thrainer
    if conflicting_groups:
3919 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Can't use group(s) '%s' as targets, they are"
3920 22b7f6f8 Thomas Thrainer
                                 " used by the instance '%s'" %
3921 22b7f6f8 Thomas Thrainer
                                 (utils.CommaJoin(conflicting_groups),
3922 22b7f6f8 Thomas Thrainer
                                  self.op.instance_name),
3923 22b7f6f8 Thomas Thrainer
                                 errors.ECODE_INVAL)
3924 22b7f6f8 Thomas Thrainer
3925 22b7f6f8 Thomas Thrainer
    if not self.target_uuids:
3926 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("There are no possible target groups",
3927 22b7f6f8 Thomas Thrainer
                                 errors.ECODE_INVAL)
3928 22b7f6f8 Thomas Thrainer
3929 22b7f6f8 Thomas Thrainer
  def BuildHooksEnv(self):
3930 22b7f6f8 Thomas Thrainer
    """Build hooks env.
3931 22b7f6f8 Thomas Thrainer

3932 22b7f6f8 Thomas Thrainer
    """
3933 22b7f6f8 Thomas Thrainer
    assert self.target_uuids
3934 22b7f6f8 Thomas Thrainer
3935 22b7f6f8 Thomas Thrainer
    env = {
3936 22b7f6f8 Thomas Thrainer
      "TARGET_GROUPS": " ".join(self.target_uuids),
3937 22b7f6f8 Thomas Thrainer
      }
3938 22b7f6f8 Thomas Thrainer
3939 5eacbcae Thomas Thrainer
    env.update(BuildInstanceHookEnvByObject(self, self.instance))
3940 22b7f6f8 Thomas Thrainer
3941 22b7f6f8 Thomas Thrainer
    return env
3942 22b7f6f8 Thomas Thrainer
3943 22b7f6f8 Thomas Thrainer
  def BuildHooksNodes(self):
3944 22b7f6f8 Thomas Thrainer
    """Build hooks nodes.
3945 22b7f6f8 Thomas Thrainer

3946 22b7f6f8 Thomas Thrainer
    """
3947 22b7f6f8 Thomas Thrainer
    mn = self.cfg.GetMasterNode()
3948 22b7f6f8 Thomas Thrainer
    return ([mn], [mn])
3949 22b7f6f8 Thomas Thrainer
3950 22b7f6f8 Thomas Thrainer
  def Exec(self, feedback_fn):
3951 22b7f6f8 Thomas Thrainer
    instances = list(self.owned_locks(locking.LEVEL_INSTANCE))
3952 22b7f6f8 Thomas Thrainer
3953 22b7f6f8 Thomas Thrainer
    assert instances == [self.op.instance_name], "Instance not locked"
3954 22b7f6f8 Thomas Thrainer
3955 22b7f6f8 Thomas Thrainer
    req = iallocator.IAReqGroupChange(instances=instances,
3956 22b7f6f8 Thomas Thrainer
                                      target_groups=list(self.target_uuids))
3957 22b7f6f8 Thomas Thrainer
    ial = iallocator.IAllocator(self.cfg, self.rpc, req)
3958 22b7f6f8 Thomas Thrainer
3959 22b7f6f8 Thomas Thrainer
    ial.Run(self.op.iallocator)
3960 22b7f6f8 Thomas Thrainer
3961 22b7f6f8 Thomas Thrainer
    if not ial.success:
3962 22b7f6f8 Thomas Thrainer
      raise errors.OpPrereqError("Can't compute solution for changing group of"
3963 22b7f6f8 Thomas Thrainer
                                 " instance '%s' using iallocator '%s': %s" %
3964 22b7f6f8 Thomas Thrainer
                                 (self.op.instance_name, self.op.iallocator,
3965 22b7f6f8 Thomas Thrainer
                                  ial.info), errors.ECODE_NORES)
3966 22b7f6f8 Thomas Thrainer
3967 5eacbcae Thomas Thrainer
    jobs = LoadNodeEvacResult(self, ial.result, self.op.early_release, False)
3968 22b7f6f8 Thomas Thrainer
3969 22b7f6f8 Thomas Thrainer
    self.LogInfo("Iallocator returned %s job(s) for changing group of"
3970 22b7f6f8 Thomas Thrainer
                 " instance '%s'", len(jobs), self.op.instance_name)
3971 22b7f6f8 Thomas Thrainer
3972 22b7f6f8 Thomas Thrainer
    return ResultWithJobs(jobs)