Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / instance_utils.py @ 8701dfb0

History | View | Annotate | Download (15.8 kB)

1 22b7f6f8 Thomas Thrainer
#
2 22b7f6f8 Thomas Thrainer
#
3 22b7f6f8 Thomas Thrainer
4 22b7f6f8 Thomas Thrainer
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 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
"""Utility function mainly, but not only used by instance LU's."""
23 22b7f6f8 Thomas Thrainer
24 22b7f6f8 Thomas Thrainer
import logging
25 22b7f6f8 Thomas Thrainer
import os
26 22b7f6f8 Thomas Thrainer
27 22b7f6f8 Thomas Thrainer
from ganeti import constants
28 22b7f6f8 Thomas Thrainer
from ganeti import errors
29 22b7f6f8 Thomas Thrainer
from ganeti import locking
30 22b7f6f8 Thomas Thrainer
from ganeti import network
31 22b7f6f8 Thomas Thrainer
from ganeti import objects
32 22b7f6f8 Thomas Thrainer
from ganeti import pathutils
33 22b7f6f8 Thomas Thrainer
from ganeti import utils
34 22b7f6f8 Thomas Thrainer
35 22b7f6f8 Thomas Thrainer
from ganeti.cmdlib.common import _AnnotateDiskParams
36 22b7f6f8 Thomas Thrainer
37 22b7f6f8 Thomas Thrainer
38 22b7f6f8 Thomas Thrainer
def _BuildInstanceHookEnv(name, primary_node, secondary_nodes, os_type, status,
39 22b7f6f8 Thomas Thrainer
                          minmem, maxmem, vcpus, nics, disk_template, disks,
40 22b7f6f8 Thomas Thrainer
                          bep, hvp, hypervisor_name, tags):
41 22b7f6f8 Thomas Thrainer
  """Builds instance related env variables for hooks
42 22b7f6f8 Thomas Thrainer

43 22b7f6f8 Thomas Thrainer
  This builds the hook environment from individual variables.
44 22b7f6f8 Thomas Thrainer

45 22b7f6f8 Thomas Thrainer
  @type name: string
46 22b7f6f8 Thomas Thrainer
  @param name: the name of the instance
47 22b7f6f8 Thomas Thrainer
  @type primary_node: string
48 22b7f6f8 Thomas Thrainer
  @param primary_node: the name of the instance's primary node
49 22b7f6f8 Thomas Thrainer
  @type secondary_nodes: list
50 22b7f6f8 Thomas Thrainer
  @param secondary_nodes: list of secondary nodes as strings
51 22b7f6f8 Thomas Thrainer
  @type os_type: string
52 22b7f6f8 Thomas Thrainer
  @param os_type: the name of the instance's OS
53 22b7f6f8 Thomas Thrainer
  @type status: string
54 22b7f6f8 Thomas Thrainer
  @param status: the desired status of the instance
55 22b7f6f8 Thomas Thrainer
  @type minmem: string
56 22b7f6f8 Thomas Thrainer
  @param minmem: the minimum memory size of the instance
57 22b7f6f8 Thomas Thrainer
  @type maxmem: string
58 22b7f6f8 Thomas Thrainer
  @param maxmem: the maximum memory size of the instance
59 22b7f6f8 Thomas Thrainer
  @type vcpus: string
60 22b7f6f8 Thomas Thrainer
  @param vcpus: the count of VCPUs the instance has
61 22b7f6f8 Thomas Thrainer
  @type nics: list
62 22b7f6f8 Thomas Thrainer
  @param nics: list of tuples (name, uuid, ip, mac, mode, link, net, netinfo)
63 22b7f6f8 Thomas Thrainer
      representing the NICs the instance has
64 22b7f6f8 Thomas Thrainer
  @type disk_template: string
65 22b7f6f8 Thomas Thrainer
  @param disk_template: the disk template of the instance
66 22b7f6f8 Thomas Thrainer
  @type disks: list
67 22b7f6f8 Thomas Thrainer
  @param disks: list of tuples (name, uuid, size, mode)
68 22b7f6f8 Thomas Thrainer
  @type bep: dict
69 22b7f6f8 Thomas Thrainer
  @param bep: the backend parameters for the instance
70 22b7f6f8 Thomas Thrainer
  @type hvp: dict
71 22b7f6f8 Thomas Thrainer
  @param hvp: the hypervisor parameters for the instance
72 22b7f6f8 Thomas Thrainer
  @type hypervisor_name: string
73 22b7f6f8 Thomas Thrainer
  @param hypervisor_name: the hypervisor for the instance
74 22b7f6f8 Thomas Thrainer
  @type tags: list
75 22b7f6f8 Thomas Thrainer
  @param tags: list of instance tags as strings
76 22b7f6f8 Thomas Thrainer
  @rtype: dict
77 22b7f6f8 Thomas Thrainer
  @return: the hook environment for this instance
78 22b7f6f8 Thomas Thrainer

79 22b7f6f8 Thomas Thrainer
  """
80 22b7f6f8 Thomas Thrainer
  env = {
81 22b7f6f8 Thomas Thrainer
    "OP_TARGET": name,
82 22b7f6f8 Thomas Thrainer
    "INSTANCE_NAME": name,
83 22b7f6f8 Thomas Thrainer
    "INSTANCE_PRIMARY": primary_node,
84 22b7f6f8 Thomas Thrainer
    "INSTANCE_SECONDARIES": " ".join(secondary_nodes),
85 22b7f6f8 Thomas Thrainer
    "INSTANCE_OS_TYPE": os_type,
86 22b7f6f8 Thomas Thrainer
    "INSTANCE_STATUS": status,
87 22b7f6f8 Thomas Thrainer
    "INSTANCE_MINMEM": minmem,
88 22b7f6f8 Thomas Thrainer
    "INSTANCE_MAXMEM": maxmem,
89 22b7f6f8 Thomas Thrainer
    # TODO(2.9) remove deprecated "memory" value
90 22b7f6f8 Thomas Thrainer
    "INSTANCE_MEMORY": maxmem,
91 22b7f6f8 Thomas Thrainer
    "INSTANCE_VCPUS": vcpus,
92 22b7f6f8 Thomas Thrainer
    "INSTANCE_DISK_TEMPLATE": disk_template,
93 22b7f6f8 Thomas Thrainer
    "INSTANCE_HYPERVISOR": hypervisor_name,
94 22b7f6f8 Thomas Thrainer
    }
95 22b7f6f8 Thomas Thrainer
  if nics:
96 22b7f6f8 Thomas Thrainer
    nic_count = len(nics)
97 22b7f6f8 Thomas Thrainer
    for idx, (name, _, ip, mac, mode, link, net, netinfo) in enumerate(nics):
98 22b7f6f8 Thomas Thrainer
      if ip is None:
99 22b7f6f8 Thomas Thrainer
        ip = ""
100 22b7f6f8 Thomas Thrainer
      env["INSTANCE_NIC%d_NAME" % idx] = name
101 22b7f6f8 Thomas Thrainer
      env["INSTANCE_NIC%d_IP" % idx] = ip
102 22b7f6f8 Thomas Thrainer
      env["INSTANCE_NIC%d_MAC" % idx] = mac
103 22b7f6f8 Thomas Thrainer
      env["INSTANCE_NIC%d_MODE" % idx] = mode
104 22b7f6f8 Thomas Thrainer
      env["INSTANCE_NIC%d_LINK" % idx] = link
105 22b7f6f8 Thomas Thrainer
      if netinfo:
106 22b7f6f8 Thomas Thrainer
        nobj = objects.Network.FromDict(netinfo)
107 22b7f6f8 Thomas Thrainer
        env.update(nobj.HooksDict("INSTANCE_NIC%d_" % idx))
108 22b7f6f8 Thomas Thrainer
      elif network:
109 22b7f6f8 Thomas Thrainer
        # FIXME: broken network reference: the instance NIC specifies a
110 22b7f6f8 Thomas Thrainer
        # network, but the relevant network entry was not in the config. This
111 22b7f6f8 Thomas Thrainer
        # should be made impossible.
112 22b7f6f8 Thomas Thrainer
        env["INSTANCE_NIC%d_NETWORK_NAME" % idx] = net
113 22b7f6f8 Thomas Thrainer
      if mode == constants.NIC_MODE_BRIDGED:
114 22b7f6f8 Thomas Thrainer
        env["INSTANCE_NIC%d_BRIDGE" % idx] = link
115 22b7f6f8 Thomas Thrainer
  else:
116 22b7f6f8 Thomas Thrainer
    nic_count = 0
117 22b7f6f8 Thomas Thrainer
118 22b7f6f8 Thomas Thrainer
  env["INSTANCE_NIC_COUNT"] = nic_count
119 22b7f6f8 Thomas Thrainer
120 22b7f6f8 Thomas Thrainer
  if disks:
121 22b7f6f8 Thomas Thrainer
    disk_count = len(disks)
122 22b7f6f8 Thomas Thrainer
    for idx, (name, size, mode) in enumerate(disks):
123 22b7f6f8 Thomas Thrainer
      env["INSTANCE_DISK%d_NAME" % idx] = name
124 22b7f6f8 Thomas Thrainer
      env["INSTANCE_DISK%d_SIZE" % idx] = size
125 22b7f6f8 Thomas Thrainer
      env["INSTANCE_DISK%d_MODE" % idx] = mode
126 22b7f6f8 Thomas Thrainer
  else:
127 22b7f6f8 Thomas Thrainer
    disk_count = 0
128 22b7f6f8 Thomas Thrainer
129 22b7f6f8 Thomas Thrainer
  env["INSTANCE_DISK_COUNT"] = disk_count
130 22b7f6f8 Thomas Thrainer
131 22b7f6f8 Thomas Thrainer
  if not tags:
132 22b7f6f8 Thomas Thrainer
    tags = []
133 22b7f6f8 Thomas Thrainer
134 22b7f6f8 Thomas Thrainer
  env["INSTANCE_TAGS"] = " ".join(tags)
135 22b7f6f8 Thomas Thrainer
136 22b7f6f8 Thomas Thrainer
  for source, kind in [(bep, "BE"), (hvp, "HV")]:
137 22b7f6f8 Thomas Thrainer
    for key, value in source.items():
138 22b7f6f8 Thomas Thrainer
      env["INSTANCE_%s_%s" % (kind, key)] = value
139 22b7f6f8 Thomas Thrainer
140 22b7f6f8 Thomas Thrainer
  return env
141 22b7f6f8 Thomas Thrainer
142 22b7f6f8 Thomas Thrainer
143 22b7f6f8 Thomas Thrainer
def _BuildInstanceHookEnvByObject(lu, instance, override=None):
144 22b7f6f8 Thomas Thrainer
  """Builds instance related env variables for hooks from an object.
145 22b7f6f8 Thomas Thrainer

146 22b7f6f8 Thomas Thrainer
  @type lu: L{LogicalUnit}
147 22b7f6f8 Thomas Thrainer
  @param lu: the logical unit on whose behalf we execute
148 22b7f6f8 Thomas Thrainer
  @type instance: L{objects.Instance}
149 22b7f6f8 Thomas Thrainer
  @param instance: the instance for which we should build the
150 22b7f6f8 Thomas Thrainer
      environment
151 22b7f6f8 Thomas Thrainer
  @type override: dict
152 22b7f6f8 Thomas Thrainer
  @param override: dictionary with key/values that will override
153 22b7f6f8 Thomas Thrainer
      our values
154 22b7f6f8 Thomas Thrainer
  @rtype: dict
155 22b7f6f8 Thomas Thrainer
  @return: the hook environment dictionary
156 22b7f6f8 Thomas Thrainer

157 22b7f6f8 Thomas Thrainer
  """
158 22b7f6f8 Thomas Thrainer
  cluster = lu.cfg.GetClusterInfo()
159 22b7f6f8 Thomas Thrainer
  bep = cluster.FillBE(instance)
160 22b7f6f8 Thomas Thrainer
  hvp = cluster.FillHV(instance)
161 22b7f6f8 Thomas Thrainer
  args = {
162 22b7f6f8 Thomas Thrainer
    "name": instance.name,
163 22b7f6f8 Thomas Thrainer
    "primary_node": instance.primary_node,
164 22b7f6f8 Thomas Thrainer
    "secondary_nodes": instance.secondary_nodes,
165 22b7f6f8 Thomas Thrainer
    "os_type": instance.os,
166 22b7f6f8 Thomas Thrainer
    "status": instance.admin_state,
167 22b7f6f8 Thomas Thrainer
    "maxmem": bep[constants.BE_MAXMEM],
168 22b7f6f8 Thomas Thrainer
    "minmem": bep[constants.BE_MINMEM],
169 22b7f6f8 Thomas Thrainer
    "vcpus": bep[constants.BE_VCPUS],
170 22b7f6f8 Thomas Thrainer
    "nics": _NICListToTuple(lu, instance.nics),
171 22b7f6f8 Thomas Thrainer
    "disk_template": instance.disk_template,
172 22b7f6f8 Thomas Thrainer
    "disks": [(disk.name, disk.size, disk.mode)
173 22b7f6f8 Thomas Thrainer
              for disk in instance.disks],
174 22b7f6f8 Thomas Thrainer
    "bep": bep,
175 22b7f6f8 Thomas Thrainer
    "hvp": hvp,
176 22b7f6f8 Thomas Thrainer
    "hypervisor_name": instance.hypervisor,
177 22b7f6f8 Thomas Thrainer
    "tags": instance.tags,
178 22b7f6f8 Thomas Thrainer
  }
179 22b7f6f8 Thomas Thrainer
  if override:
180 22b7f6f8 Thomas Thrainer
    args.update(override)
181 22b7f6f8 Thomas Thrainer
  return _BuildInstanceHookEnv(**args) # pylint: disable=W0142
182 22b7f6f8 Thomas Thrainer
183 22b7f6f8 Thomas Thrainer
184 22b7f6f8 Thomas Thrainer
def _GetClusterDomainSecret():
185 22b7f6f8 Thomas Thrainer
  """Reads the cluster domain secret.
186 22b7f6f8 Thomas Thrainer

187 22b7f6f8 Thomas Thrainer
  """
188 22b7f6f8 Thomas Thrainer
  return utils.ReadOneLineFile(pathutils.CLUSTER_DOMAIN_SECRET_FILE,
189 22b7f6f8 Thomas Thrainer
                               strict=True)
190 22b7f6f8 Thomas Thrainer
191 22b7f6f8 Thomas Thrainer
192 22b7f6f8 Thomas Thrainer
def _CheckNodeNotDrained(lu, node):
193 22b7f6f8 Thomas Thrainer
  """Ensure that a given node is not drained.
194 22b7f6f8 Thomas Thrainer

195 22b7f6f8 Thomas Thrainer
  @param lu: the LU on behalf of which we make the check
196 22b7f6f8 Thomas Thrainer
  @param node: the node to check
197 22b7f6f8 Thomas Thrainer
  @raise errors.OpPrereqError: if the node is drained
198 22b7f6f8 Thomas Thrainer

199 22b7f6f8 Thomas Thrainer
  """
200 22b7f6f8 Thomas Thrainer
  if lu.cfg.GetNodeInfo(node).drained:
201 22b7f6f8 Thomas Thrainer
    raise errors.OpPrereqError("Can't use drained node %s" % node,
202 22b7f6f8 Thomas Thrainer
                               errors.ECODE_STATE)
203 22b7f6f8 Thomas Thrainer
204 22b7f6f8 Thomas Thrainer
205 22b7f6f8 Thomas Thrainer
def _StartInstanceDisks(lu, instance, force):
206 22b7f6f8 Thomas Thrainer
  """Start the disks of an instance.
207 22b7f6f8 Thomas Thrainer

208 22b7f6f8 Thomas Thrainer
  """
209 22b7f6f8 Thomas Thrainer
  disks_ok, _ = _AssembleInstanceDisks(lu, instance,
210 22b7f6f8 Thomas Thrainer
                                           ignore_secondaries=force)
211 22b7f6f8 Thomas Thrainer
  if not disks_ok:
212 22b7f6f8 Thomas Thrainer
    _ShutdownInstanceDisks(lu, instance)
213 22b7f6f8 Thomas Thrainer
    if force is not None and not force:
214 22b7f6f8 Thomas Thrainer
      lu.LogWarning("",
215 22b7f6f8 Thomas Thrainer
                    hint=("If the message above refers to a secondary node,"
216 22b7f6f8 Thomas Thrainer
                          " you can retry the operation using '--force'"))
217 22b7f6f8 Thomas Thrainer
    raise errors.OpExecError("Disk consistency error")
218 22b7f6f8 Thomas Thrainer
219 22b7f6f8 Thomas Thrainer
220 22b7f6f8 Thomas Thrainer
def _ShutdownInstanceDisks(lu, instance, disks=None, ignore_primary=False):
221 22b7f6f8 Thomas Thrainer
  """Shutdown block devices of an instance.
222 22b7f6f8 Thomas Thrainer

223 22b7f6f8 Thomas Thrainer
  This does the shutdown on all nodes of the instance.
224 22b7f6f8 Thomas Thrainer

225 22b7f6f8 Thomas Thrainer
  If the ignore_primary is false, errors on the primary node are
226 22b7f6f8 Thomas Thrainer
  ignored.
227 22b7f6f8 Thomas Thrainer

228 22b7f6f8 Thomas Thrainer
  """
229 22b7f6f8 Thomas Thrainer
  all_result = True
230 22b7f6f8 Thomas Thrainer
  disks = _ExpandCheckDisks(instance, disks)
231 22b7f6f8 Thomas Thrainer
232 22b7f6f8 Thomas Thrainer
  for disk in disks:
233 22b7f6f8 Thomas Thrainer
    for node, top_disk in disk.ComputeNodeTree(instance.primary_node):
234 22b7f6f8 Thomas Thrainer
      lu.cfg.SetDiskID(top_disk, node)
235 22b7f6f8 Thomas Thrainer
      result = lu.rpc.call_blockdev_shutdown(node, (top_disk, instance))
236 22b7f6f8 Thomas Thrainer
      msg = result.fail_msg
237 22b7f6f8 Thomas Thrainer
      if msg:
238 22b7f6f8 Thomas Thrainer
        lu.LogWarning("Could not shutdown block device %s on node %s: %s",
239 22b7f6f8 Thomas Thrainer
                      disk.iv_name, node, msg)
240 22b7f6f8 Thomas Thrainer
        if ((node == instance.primary_node and not ignore_primary) or
241 22b7f6f8 Thomas Thrainer
            (node != instance.primary_node and not result.offline)):
242 22b7f6f8 Thomas Thrainer
          all_result = False
243 22b7f6f8 Thomas Thrainer
  return all_result
244 22b7f6f8 Thomas Thrainer
245 22b7f6f8 Thomas Thrainer
246 22b7f6f8 Thomas Thrainer
def _RemoveInstance(lu, feedback_fn, instance, ignore_failures):
247 22b7f6f8 Thomas Thrainer
  """Utility function to remove an instance.
248 22b7f6f8 Thomas Thrainer

249 22b7f6f8 Thomas Thrainer
  """
250 22b7f6f8 Thomas Thrainer
  logging.info("Removing block devices for instance %s", instance.name)
251 22b7f6f8 Thomas Thrainer
252 22b7f6f8 Thomas Thrainer
  if not _RemoveDisks(lu, instance, ignore_failures=ignore_failures):
253 22b7f6f8 Thomas Thrainer
    if not ignore_failures:
254 22b7f6f8 Thomas Thrainer
      raise errors.OpExecError("Can't remove instance's disks")
255 22b7f6f8 Thomas Thrainer
    feedback_fn("Warning: can't remove instance's disks")
256 22b7f6f8 Thomas Thrainer
257 22b7f6f8 Thomas Thrainer
  logging.info("Removing instance %s out of cluster config", instance.name)
258 22b7f6f8 Thomas Thrainer
259 22b7f6f8 Thomas Thrainer
  lu.cfg.RemoveInstance(instance.name)
260 22b7f6f8 Thomas Thrainer
261 22b7f6f8 Thomas Thrainer
  assert not lu.remove_locks.get(locking.LEVEL_INSTANCE), \
262 22b7f6f8 Thomas Thrainer
    "Instance lock removal conflict"
263 22b7f6f8 Thomas Thrainer
264 22b7f6f8 Thomas Thrainer
  # Remove lock for the instance
265 22b7f6f8 Thomas Thrainer
  lu.remove_locks[locking.LEVEL_INSTANCE] = instance.name
266 22b7f6f8 Thomas Thrainer
267 22b7f6f8 Thomas Thrainer
268 22b7f6f8 Thomas Thrainer
def _AssembleInstanceDisks(lu, instance, disks=None, ignore_secondaries=False,
269 22b7f6f8 Thomas Thrainer
                           ignore_size=False):
270 22b7f6f8 Thomas Thrainer
  """Prepare the block devices for an instance.
271 22b7f6f8 Thomas Thrainer

272 22b7f6f8 Thomas Thrainer
  This sets up the block devices on all nodes.
273 22b7f6f8 Thomas Thrainer

274 22b7f6f8 Thomas Thrainer
  @type lu: L{LogicalUnit}
275 22b7f6f8 Thomas Thrainer
  @param lu: the logical unit on whose behalf we execute
276 22b7f6f8 Thomas Thrainer
  @type instance: L{objects.Instance}
277 22b7f6f8 Thomas Thrainer
  @param instance: the instance for whose disks we assemble
278 22b7f6f8 Thomas Thrainer
  @type disks: list of L{objects.Disk} or None
279 22b7f6f8 Thomas Thrainer
  @param disks: which disks to assemble (or all, if None)
280 22b7f6f8 Thomas Thrainer
  @type ignore_secondaries: boolean
281 22b7f6f8 Thomas Thrainer
  @param ignore_secondaries: if true, errors on secondary nodes
282 22b7f6f8 Thomas Thrainer
      won't result in an error return from the function
283 22b7f6f8 Thomas Thrainer
  @type ignore_size: boolean
284 22b7f6f8 Thomas Thrainer
  @param ignore_size: if true, the current known size of the disk
285 22b7f6f8 Thomas Thrainer
      will not be used during the disk activation, useful for cases
286 22b7f6f8 Thomas Thrainer
      when the size is wrong
287 22b7f6f8 Thomas Thrainer
  @return: False if the operation failed, otherwise a list of
288 22b7f6f8 Thomas Thrainer
      (host, instance_visible_name, node_visible_name)
289 22b7f6f8 Thomas Thrainer
      with the mapping from node devices to instance devices
290 22b7f6f8 Thomas Thrainer

291 22b7f6f8 Thomas Thrainer
  """
292 22b7f6f8 Thomas Thrainer
  device_info = []
293 22b7f6f8 Thomas Thrainer
  disks_ok = True
294 22b7f6f8 Thomas Thrainer
  iname = instance.name
295 22b7f6f8 Thomas Thrainer
  disks = _ExpandCheckDisks(instance, disks)
296 22b7f6f8 Thomas Thrainer
297 22b7f6f8 Thomas Thrainer
  # With the two passes mechanism we try to reduce the window of
298 22b7f6f8 Thomas Thrainer
  # opportunity for the race condition of switching DRBD to primary
299 22b7f6f8 Thomas Thrainer
  # before handshaking occured, but we do not eliminate it
300 22b7f6f8 Thomas Thrainer
301 22b7f6f8 Thomas Thrainer
  # The proper fix would be to wait (with some limits) until the
302 22b7f6f8 Thomas Thrainer
  # connection has been made and drbd transitions from WFConnection
303 22b7f6f8 Thomas Thrainer
  # into any other network-connected state (Connected, SyncTarget,
304 22b7f6f8 Thomas Thrainer
  # SyncSource, etc.)
305 22b7f6f8 Thomas Thrainer
306 22b7f6f8 Thomas Thrainer
  # 1st pass, assemble on all nodes in secondary mode
307 22b7f6f8 Thomas Thrainer
  for idx, inst_disk in enumerate(disks):
308 22b7f6f8 Thomas Thrainer
    for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
309 22b7f6f8 Thomas Thrainer
      if ignore_size:
310 22b7f6f8 Thomas Thrainer
        node_disk = node_disk.Copy()
311 22b7f6f8 Thomas Thrainer
        node_disk.UnsetSize()
312 22b7f6f8 Thomas Thrainer
      lu.cfg.SetDiskID(node_disk, node)
313 22b7f6f8 Thomas Thrainer
      result = lu.rpc.call_blockdev_assemble(node, (node_disk, instance), iname,
314 22b7f6f8 Thomas Thrainer
                                             False, idx)
315 22b7f6f8 Thomas Thrainer
      msg = result.fail_msg
316 22b7f6f8 Thomas Thrainer
      if msg:
317 22b7f6f8 Thomas Thrainer
        is_offline_secondary = (node in instance.secondary_nodes and
318 22b7f6f8 Thomas Thrainer
                                result.offline)
319 22b7f6f8 Thomas Thrainer
        lu.LogWarning("Could not prepare block device %s on node %s"
320 22b7f6f8 Thomas Thrainer
                      " (is_primary=False, pass=1): %s",
321 22b7f6f8 Thomas Thrainer
                      inst_disk.iv_name, node, msg)
322 22b7f6f8 Thomas Thrainer
        if not (ignore_secondaries or is_offline_secondary):
323 22b7f6f8 Thomas Thrainer
          disks_ok = False
324 22b7f6f8 Thomas Thrainer
325 22b7f6f8 Thomas Thrainer
  # FIXME: race condition on drbd migration to primary
326 22b7f6f8 Thomas Thrainer
327 22b7f6f8 Thomas Thrainer
  # 2nd pass, do only the primary node
328 22b7f6f8 Thomas Thrainer
  for idx, inst_disk in enumerate(disks):
329 22b7f6f8 Thomas Thrainer
    dev_path = None
330 22b7f6f8 Thomas Thrainer
331 22b7f6f8 Thomas Thrainer
    for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
332 22b7f6f8 Thomas Thrainer
      if node != instance.primary_node:
333 22b7f6f8 Thomas Thrainer
        continue
334 22b7f6f8 Thomas Thrainer
      if ignore_size:
335 22b7f6f8 Thomas Thrainer
        node_disk = node_disk.Copy()
336 22b7f6f8 Thomas Thrainer
        node_disk.UnsetSize()
337 22b7f6f8 Thomas Thrainer
      lu.cfg.SetDiskID(node_disk, node)
338 22b7f6f8 Thomas Thrainer
      result = lu.rpc.call_blockdev_assemble(node, (node_disk, instance), iname,
339 22b7f6f8 Thomas Thrainer
                                             True, idx)
340 22b7f6f8 Thomas Thrainer
      msg = result.fail_msg
341 22b7f6f8 Thomas Thrainer
      if msg:
342 22b7f6f8 Thomas Thrainer
        lu.LogWarning("Could not prepare block device %s on node %s"
343 22b7f6f8 Thomas Thrainer
                      " (is_primary=True, pass=2): %s",
344 22b7f6f8 Thomas Thrainer
                      inst_disk.iv_name, node, msg)
345 22b7f6f8 Thomas Thrainer
        disks_ok = False
346 22b7f6f8 Thomas Thrainer
      else:
347 22b7f6f8 Thomas Thrainer
        dev_path = result.payload
348 22b7f6f8 Thomas Thrainer
349 22b7f6f8 Thomas Thrainer
    device_info.append((instance.primary_node, inst_disk.iv_name, dev_path))
350 22b7f6f8 Thomas Thrainer
351 22b7f6f8 Thomas Thrainer
  # leave the disks configured for the primary node
352 22b7f6f8 Thomas Thrainer
  # this is a workaround that would be fixed better by
353 22b7f6f8 Thomas Thrainer
  # improving the logical/physical id handling
354 22b7f6f8 Thomas Thrainer
  for disk in disks:
355 22b7f6f8 Thomas Thrainer
    lu.cfg.SetDiskID(disk, instance.primary_node)
356 22b7f6f8 Thomas Thrainer
357 22b7f6f8 Thomas Thrainer
  return disks_ok, device_info
358 22b7f6f8 Thomas Thrainer
359 22b7f6f8 Thomas Thrainer
360 22b7f6f8 Thomas Thrainer
def _RemoveDisks(lu, instance, target_node=None, ignore_failures=False):
361 22b7f6f8 Thomas Thrainer
  """Remove all disks for an instance.
362 22b7f6f8 Thomas Thrainer

363 22b7f6f8 Thomas Thrainer
  This abstracts away some work from `AddInstance()` and
364 22b7f6f8 Thomas Thrainer
  `RemoveInstance()`. Note that in case some of the devices couldn't
365 22b7f6f8 Thomas Thrainer
  be removed, the removal will continue with the other ones.
366 22b7f6f8 Thomas Thrainer

367 22b7f6f8 Thomas Thrainer
  @type lu: L{LogicalUnit}
368 22b7f6f8 Thomas Thrainer
  @param lu: the logical unit on whose behalf we execute
369 22b7f6f8 Thomas Thrainer
  @type instance: L{objects.Instance}
370 22b7f6f8 Thomas Thrainer
  @param instance: the instance whose disks we should remove
371 22b7f6f8 Thomas Thrainer
  @type target_node: string
372 22b7f6f8 Thomas Thrainer
  @param target_node: used to override the node on which to remove the disks
373 22b7f6f8 Thomas Thrainer
  @rtype: boolean
374 22b7f6f8 Thomas Thrainer
  @return: the success of the removal
375 22b7f6f8 Thomas Thrainer

376 22b7f6f8 Thomas Thrainer
  """
377 22b7f6f8 Thomas Thrainer
  logging.info("Removing block devices for instance %s", instance.name)
378 22b7f6f8 Thomas Thrainer
379 22b7f6f8 Thomas Thrainer
  all_result = True
380 22b7f6f8 Thomas Thrainer
  ports_to_release = set()
381 22b7f6f8 Thomas Thrainer
  anno_disks = _AnnotateDiskParams(instance, instance.disks, lu.cfg)
382 22b7f6f8 Thomas Thrainer
  for (idx, device) in enumerate(anno_disks):
383 22b7f6f8 Thomas Thrainer
    if target_node:
384 22b7f6f8 Thomas Thrainer
      edata = [(target_node, device)]
385 22b7f6f8 Thomas Thrainer
    else:
386 22b7f6f8 Thomas Thrainer
      edata = device.ComputeNodeTree(instance.primary_node)
387 22b7f6f8 Thomas Thrainer
    for node, disk in edata:
388 22b7f6f8 Thomas Thrainer
      lu.cfg.SetDiskID(disk, node)
389 22b7f6f8 Thomas Thrainer
      result = lu.rpc.call_blockdev_remove(node, disk)
390 22b7f6f8 Thomas Thrainer
      if result.fail_msg:
391 22b7f6f8 Thomas Thrainer
        lu.LogWarning("Could not remove disk %s on node %s,"
392 22b7f6f8 Thomas Thrainer
                      " continuing anyway: %s", idx, node, result.fail_msg)
393 22b7f6f8 Thomas Thrainer
        if not (result.offline and node != instance.primary_node):
394 22b7f6f8 Thomas Thrainer
          all_result = False
395 22b7f6f8 Thomas Thrainer
396 22b7f6f8 Thomas Thrainer
    # if this is a DRBD disk, return its port to the pool
397 22b7f6f8 Thomas Thrainer
    if device.dev_type in constants.LDS_DRBD:
398 22b7f6f8 Thomas Thrainer
      ports_to_release.add(device.logical_id[2])
399 22b7f6f8 Thomas Thrainer
400 22b7f6f8 Thomas Thrainer
  if all_result or ignore_failures:
401 22b7f6f8 Thomas Thrainer
    for port in ports_to_release:
402 22b7f6f8 Thomas Thrainer
      lu.cfg.AddTcpUdpPort(port)
403 22b7f6f8 Thomas Thrainer
404 22b7f6f8 Thomas Thrainer
  if instance.disk_template in constants.DTS_FILEBASED:
405 22b7f6f8 Thomas Thrainer
    file_storage_dir = os.path.dirname(instance.disks[0].logical_id[1])
406 22b7f6f8 Thomas Thrainer
    if target_node:
407 22b7f6f8 Thomas Thrainer
      tgt = target_node
408 22b7f6f8 Thomas Thrainer
    else:
409 22b7f6f8 Thomas Thrainer
      tgt = instance.primary_node
410 22b7f6f8 Thomas Thrainer
    result = lu.rpc.call_file_storage_dir_remove(tgt, file_storage_dir)
411 22b7f6f8 Thomas Thrainer
    if result.fail_msg:
412 22b7f6f8 Thomas Thrainer
      lu.LogWarning("Could not remove directory '%s' on node %s: %s",
413 22b7f6f8 Thomas Thrainer
                    file_storage_dir, instance.primary_node, result.fail_msg)
414 22b7f6f8 Thomas Thrainer
      all_result = False
415 22b7f6f8 Thomas Thrainer
416 22b7f6f8 Thomas Thrainer
  return all_result
417 22b7f6f8 Thomas Thrainer
418 22b7f6f8 Thomas Thrainer
419 22b7f6f8 Thomas Thrainer
def _ExpandCheckDisks(instance, disks):
420 22b7f6f8 Thomas Thrainer
  """Return the instance disks selected by the disks list
421 22b7f6f8 Thomas Thrainer

422 22b7f6f8 Thomas Thrainer
  @type disks: list of L{objects.Disk} or None
423 22b7f6f8 Thomas Thrainer
  @param disks: selected disks
424 22b7f6f8 Thomas Thrainer
  @rtype: list of L{objects.Disk}
425 22b7f6f8 Thomas Thrainer
  @return: selected instance disks to act on
426 22b7f6f8 Thomas Thrainer

427 22b7f6f8 Thomas Thrainer
  """
428 22b7f6f8 Thomas Thrainer
  if disks is None:
429 22b7f6f8 Thomas Thrainer
    return instance.disks
430 22b7f6f8 Thomas Thrainer
  else:
431 22b7f6f8 Thomas Thrainer
    if not set(disks).issubset(instance.disks):
432 22b7f6f8 Thomas Thrainer
      raise errors.ProgrammerError("Can only act on disks belonging to the"
433 22b7f6f8 Thomas Thrainer
                                   " target instance")
434 22b7f6f8 Thomas Thrainer
    return disks
435 22b7f6f8 Thomas Thrainer
436 22b7f6f8 Thomas Thrainer
437 22b7f6f8 Thomas Thrainer
def _NICToTuple(lu, nic):
438 22b7f6f8 Thomas Thrainer
  """Build a tupple of nic information.
439 22b7f6f8 Thomas Thrainer

440 22b7f6f8 Thomas Thrainer
  @type lu:  L{LogicalUnit}
441 22b7f6f8 Thomas Thrainer
  @param lu: the logical unit on whose behalf we execute
442 22b7f6f8 Thomas Thrainer
  @type nic: L{objects.NIC}
443 22b7f6f8 Thomas Thrainer
  @param nic: nic to convert to hooks tuple
444 22b7f6f8 Thomas Thrainer

445 22b7f6f8 Thomas Thrainer
  """
446 22b7f6f8 Thomas Thrainer
  cluster = lu.cfg.GetClusterInfo()
447 22b7f6f8 Thomas Thrainer
  filled_params = cluster.SimpleFillNIC(nic.nicparams)
448 22b7f6f8 Thomas Thrainer
  mode = filled_params[constants.NIC_MODE]
449 22b7f6f8 Thomas Thrainer
  link = filled_params[constants.NIC_LINK]
450 22b7f6f8 Thomas Thrainer
  netinfo = None
451 22b7f6f8 Thomas Thrainer
  if nic.network:
452 22b7f6f8 Thomas Thrainer
    nobj = lu.cfg.GetNetwork(nic.network)
453 22b7f6f8 Thomas Thrainer
    netinfo = objects.Network.ToDict(nobj)
454 22b7f6f8 Thomas Thrainer
  return (nic.name, nic.uuid, nic.ip, nic.mac, mode, link, nic.network, netinfo)
455 22b7f6f8 Thomas Thrainer
456 22b7f6f8 Thomas Thrainer
457 22b7f6f8 Thomas Thrainer
def _NICListToTuple(lu, nics):
458 22b7f6f8 Thomas Thrainer
  """Build a list of nic information tuples.
459 22b7f6f8 Thomas Thrainer

460 22b7f6f8 Thomas Thrainer
  This list is suitable to be passed to _BuildInstanceHookEnv or as a return
461 22b7f6f8 Thomas Thrainer
  value in LUInstanceQueryData.
462 22b7f6f8 Thomas Thrainer

463 22b7f6f8 Thomas Thrainer
  @type lu:  L{LogicalUnit}
464 22b7f6f8 Thomas Thrainer
  @param lu: the logical unit on whose behalf we execute
465 22b7f6f8 Thomas Thrainer
  @type nics: list of L{objects.NIC}
466 22b7f6f8 Thomas Thrainer
  @param nics: list of nics to convert to hooks tuples
467 22b7f6f8 Thomas Thrainer

468 22b7f6f8 Thomas Thrainer
  """
469 22b7f6f8 Thomas Thrainer
  hooks_nics = []
470 22b7f6f8 Thomas Thrainer
  for nic in nics:
471 22b7f6f8 Thomas Thrainer
    hooks_nics.append(_NICToTuple(lu, nic))
472 22b7f6f8 Thomas Thrainer
  return hooks_nics