summaryrefslogtreecommitdiffstats
path: root/nova/virt
diff options
context:
space:
mode:
authorVishvananda Ishaya <vishvananda@gmail.com>2011-09-23 09:22:32 -0700
committerVishvananda Ishaya <vishvananda@gmail.com>2011-10-11 14:25:04 -0700
commiteb03d47fecd3bfc24243da29ee01679b334a08fe (patch)
tree23243973d2656fecadab6811e0dca6ceb246a7ae /nova/virt
parente164f3f703026db30937dbbddc63818cef8bd939 (diff)
Remove AoE, Clean up volume code
* Removes Ata Over Ethernet * Adds drivers to libvirt for volumes * Adds initialize_connection and terminate_connection to volume api * Passes connection info back through volume api Change-Id: I1b1626f40bebe8466ab410fb174683293c7c474f
Diffstat (limited to 'nova/virt')
-rw-r--r--nova/virt/driver.py16
-rw-r--r--nova/virt/fake.py23
-rw-r--r--nova/virt/hyperv.py7
-rw-r--r--nova/virt/libvirt.xml.template22
-rw-r--r--nova/virt/libvirt/connection.py138
-rw-r--r--nova/virt/libvirt/volume.py149
-rw-r--r--nova/virt/vmwareapi_conn.py7
-rw-r--r--nova/virt/xenapi/volume_utils.py15
-rw-r--r--nova/virt/xenapi/volumeops.py11
-rw-r--r--nova/virt/xenapi_conn.py17
10 files changed, 307 insertions, 98 deletions
diff --git a/nova/virt/driver.py b/nova/virt/driver.py
index 362d5de57..f0051aa4a 100644
--- a/nova/virt/driver.py
+++ b/nova/virt/driver.py
@@ -145,11 +145,13 @@ class ComputeDriver(object):
the creation of the new instance.
:param network_info:
:py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
- :param block_device_info:
+ :param block_device_info: Information about block devices to be
+ attached to the instance.
"""
raise NotImplementedError()
- def destroy(self, instance, network_info, cleanup=True):
+ def destroy(self, instance, network_info, block_device_info=None,
+ cleanup=True):
"""Destroy (shutdown and delete) the specified instance.
If the instance is not found (for example if networking failed), this
@@ -159,6 +161,8 @@ class ComputeDriver(object):
:param instance: Instance object as returned by DB layer.
:param network_info:
:py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
+ :param block_device_info: Information about block devices that should
+ be detached from the instance.
:param cleanup:
"""
@@ -203,12 +207,12 @@ class ComputeDriver(object):
# TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
- def attach_volume(self, context, instance_id, volume_id, mountpoint):
- """Attach the disk at device_path to the instance at mountpoint"""
+ def attach_volume(self, connection_info, instance_name, mountpoint):
+ """Attach the disk to the instance at mountpoint using info"""
raise NotImplementedError()
- def detach_volume(self, context, instance_id, volume_id):
- """Detach the disk attached to the instance at mountpoint"""
+ def detach_volume(self, connection_info, instance_name, mountpoint):
+ """Detach the disk attached to the instance"""
raise NotImplementedError()
def compare_cpu(self, cpu_info):
diff --git a/nova/virt/fake.py b/nova/virt/fake.py
index 60cc43b01..2ed6834ea 100644
--- a/nova/virt/fake.py
+++ b/nova/virt/fake.py
@@ -92,6 +92,10 @@ class FakeConnection(driver.ComputeDriver):
info_list.append(self._map_to_instance_info(instance))
return info_list
+ def plug_vifs(self, instance, network_info):
+ """Plugin VIFs into networks."""
+ pass
+
def spawn(self, context, instance,
network_info=None, block_device_info=None):
name = instance.name
@@ -148,7 +152,8 @@ class FakeConnection(driver.ComputeDriver):
def resume(self, instance, callback):
pass
- def destroy(self, instance, network_info, cleanup=True):
+ def destroy(self, instance, network_info, block_device_info=None,
+ cleanup=True):
key = instance['name']
if key in self.instances:
del self.instances[key]
@@ -156,13 +161,15 @@ class FakeConnection(driver.ComputeDriver):
LOG.warning("Key '%s' not in instances '%s'" %
(key, self.instances))
- def attach_volume(self, instance_name, device_path, mountpoint):
+ def attach_volume(self, connection_info, instance_name, mountpoint):
+ """Attach the disk to the instance at mountpoint using info"""
if not instance_name in self._mounts:
self._mounts[instance_name] = {}
- self._mounts[instance_name][mountpoint] = device_path
+ self._mounts[instance_name][mountpoint] = connection_info
return True
- def detach_volume(self, instance_name, mountpoint):
+ def detach_volume(self, connection_info, instance_name, mountpoint):
+ """Detach the disk attached to the instance"""
try:
del self._mounts[instance_name][mountpoint]
except KeyError:
@@ -233,11 +240,19 @@ class FakeConnection(driver.ComputeDriver):
"""This method is supported only by libvirt."""
raise NotImplementedError('This method is supported only by libvirt.')
+ def get_instance_disk_info(self, ctxt, instance_ref):
+ """This method is supported only by libvirt."""
+ return
+
def live_migration(self, context, instance_ref, dest,
post_method, recover_method, block_migration=False):
"""This method is supported only by libvirt."""
return
+ def pre_live_migration(self, block_device_info):
+ """This method is supported only by libvirt."""
+ return
+
def unfilter_instance(self, instance_ref, network_info):
"""This method is supported only by libvirt."""
raise NotImplementedError('This method is supported only by libvirt.')
diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py
index fbf898317..0d48c3792 100644
--- a/nova/virt/hyperv.py
+++ b/nova/virt/hyperv.py
@@ -374,7 +374,8 @@ class HyperVConnection(driver.ComputeDriver):
raise exception.InstanceNotFound(instance_id=instance.id)
self._set_vm_state(instance.name, 'Reboot')
- def destroy(self, instance, network_info, cleanup=True):
+ def destroy(self, instance, network_info, block_device_info=None,
+ cleanup=True):
"""Destroy the VM. Also destroy the associated VHD disk files"""
LOG.debug(_("Got request to destroy vm %s"), instance.name)
vm = self._lookup(instance.name)
@@ -474,12 +475,12 @@ class HyperVConnection(driver.ComputeDriver):
LOG.error(msg)
raise Exception(msg)
- def attach_volume(self, instance_name, device_path, mountpoint):
+ def attach_volume(self, connection_info, instance_name, mountpoint):
vm = self._lookup(instance_name)
if vm is None:
raise exception.InstanceNotFound(instance_id=instance_name)
- def detach_volume(self, instance_name, mountpoint):
+ def detach_volume(self, connection_info, instance_name, mountpoint):
vm = self._lookup(instance_name)
if vm is None:
raise exception.InstanceNotFound(instance_id=instance_name)
diff --git a/nova/virt/libvirt.xml.template b/nova/virt/libvirt.xml.template
index d3aeadda4..2a01f32b7 100644
--- a/nova/virt/libvirt.xml.template
+++ b/nova/virt/libvirt.xml.template
@@ -80,30 +80,22 @@
<target dev='${local_device}' bus='${disk_bus}'/>
</disk>
#end if
- #for $eph in $ephemerals
- <disk type='block'>
+ #for $eph in $ephemerals
+ <disk type='block'>
<driver type='${driver_type}'/>
<source dev='${basepath}/${eph.device_path}'/>
<target dev='${eph.device}' bus='${disk_bus}'/>
- </disk>
- #end for
- #if $getVar('swap_device', False)
+ </disk>
+ #end for
+ #if $getVar('swap_device', False)
<disk type='file'>
<driver type='${driver_type}'/>
<source file='${basepath}/disk.swap'/>
<target dev='${swap_device}' bus='${disk_bus}'/>
</disk>
- #end if
+ #end if
#for $vol in $volumes
- <disk type='${vol.type}'>
- <driver type='raw'/>
- #if $vol.type == 'network'
- <source protocol='${vol.protocol}' name='${vol.name}'/>
- #else
- <source dev='${vol.device_path}'/>
- #end if
- <target dev='${vol.mount_device}' bus='${disk_bus}'/>
- </disk>
+ ${vol}
#end for
#end if
#if $getVar('config_drive', False)
diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py
index 03b1a4ba4..97f90312b 100644
--- a/nova/virt/libvirt/connection.py
+++ b/nova/virt/libvirt/connection.py
@@ -134,6 +134,12 @@ flags.DEFINE_string('libvirt_vif_type', 'bridge',
flags.DEFINE_string('libvirt_vif_driver',
'nova.virt.libvirt.vif.LibvirtBridgeDriver',
'The libvirt VIF driver to configure the VIFs.')
+flags.DEFINE_list('libvirt_volume_drivers',
+ ['iscsi=nova.virt.libvirt.volume.LibvirtISCSIVolumeDriver',
+ 'local=nova.virt.libvirt.volume.LibvirtVolumeDriver',
+ 'rdb=nova.virt.libvirt.volume.LibvirtNetVolumeDriver',
+ 'sheepdog=nova.virt.libvirt.volume.LibvirtNetVolumeDriver'],
+ 'Libvirt handlers for remote volumes.')
flags.DEFINE_string('default_local_format',
None,
'The default format a local_volume will be formatted with '
@@ -184,6 +190,11 @@ class LibvirtConnection(driver.ComputeDriver):
fw_class = utils.import_class(FLAGS.firewall_driver)
self.firewall_driver = fw_class(get_connection=self._get_connection)
self.vif_driver = utils.import_object(FLAGS.libvirt_vif_driver)
+ self.volume_drivers = {}
+ for driver_str in FLAGS.libvirt_volume_drivers:
+ driver_type, _sep, driver = driver_str.partition('=')
+ driver_class = utils.import_class(driver)
+ self.volume_drivers[driver_type] = driver_class(self)
def init_host(self, host):
# NOTE(nsokolov): moved instance restarting to ComputeManager
@@ -261,7 +272,8 @@ class LibvirtConnection(driver.ComputeDriver):
for (network, mapping) in network_info:
self.vif_driver.plug(instance, network, mapping)
- def destroy(self, instance, network_info, cleanup=True):
+ def destroy(self, instance, network_info, block_device_info=None,
+ cleanup=True):
instance_name = instance['name']
try:
@@ -292,21 +304,21 @@ class LibvirtConnection(driver.ComputeDriver):
locals())
raise
- try:
- # NOTE(justinsb): We remove the domain definition. We probably
- # would do better to keep it if cleanup=False (e.g. volumes?)
- # (e.g. #2 - not losing machines on failure)
- virt_dom.undefine()
- except libvirt.libvirtError as e:
- errcode = e.get_error_code()
- LOG.warning(_("Error from libvirt during undefine of "
- "%(instance_name)s. Code=%(errcode)s "
- "Error=%(e)s") %
- locals())
- raise
+ try:
+ # NOTE(justinsb): We remove the domain definition. We probably
+ # would do better to keep it if cleanup=False (e.g. volumes?)
+ # (e.g. #2 - not losing machines on failure)
+ virt_dom.undefine()
+ except libvirt.libvirtError as e:
+ errcode = e.get_error_code()
+ LOG.warning(_("Error from libvirt during undefine of "
+ "%(instance_name)s. Code=%(errcode)s "
+ "Error=%(e)s") %
+ locals())
+ raise
- for (network, mapping) in network_info:
- self.vif_driver.unplug(instance, network, mapping)
+ for (network, mapping) in network_info:
+ self.vif_driver.unplug(instance, network, mapping)
def _wait_for_destroy():
"""Called at an interval until the VM is gone."""
@@ -325,6 +337,15 @@ class LibvirtConnection(driver.ComputeDriver):
self.firewall_driver.unfilter_instance(instance,
network_info=network_info)
+ # NOTE(vish): we disconnect from volumes regardless
+ block_device_mapping = driver.block_device_info_get_mapping(
+ block_device_info)
+ for vol in block_device_mapping:
+ connection_info = vol['connection_info']
+ mountpoint = vol['mount_device']
+ xml = self.volume_driver_method('disconnect_volume',
+ connection_info,
+ mountpoint)
if cleanup:
self._cleanup(instance)
@@ -340,24 +361,22 @@ class LibvirtConnection(driver.ComputeDriver):
if os.path.exists(target):
shutil.rmtree(target)
+ def volume_driver_method(self, method_name, connection_info,
+ *args, **kwargs):
+ driver_type = connection_info.get('driver_volume_type')
+ if not driver_type in self.volume_drivers:
+ raise exception.VolumeDriverNotFound(driver_type=driver_type)
+ driver = self.volume_drivers[driver_type]
+ method = getattr(driver, method_name)
+ return method(connection_info, *args, **kwargs)
+
@exception.wrap_exception()
- def attach_volume(self, instance_name, device_path, mountpoint):
+ def attach_volume(self, connection_info, instance_name, mountpoint):
virt_dom = self._lookup_by_name(instance_name)
mount_device = mountpoint.rpartition("/")[2]
- (type, protocol, name) = \
- self._get_volume_device_info(device_path)
- if type == 'block':
- xml = """<disk type='block'>
- <driver name='qemu' type='raw'/>
- <source dev='%s'/>
- <target dev='%s' bus='virtio'/>
- </disk>""" % (device_path, mount_device)
- elif type == 'network':
- xml = """<disk type='network'>
- <driver name='qemu' type='raw'/>
- <source protocol='%s' name='%s'/>
- <target dev='%s' bus='virtio'/>
- </disk>""" % (protocol, name, mount_device)
+ xml = self.volume_driver_method('connect_volume',
+ connection_info,
+ mount_device)
virt_dom.attachDevice(xml)
def _get_disk_xml(self, xml, device):
@@ -381,13 +400,21 @@ class LibvirtConnection(driver.ComputeDriver):
doc.freeDoc()
@exception.wrap_exception()
- def detach_volume(self, instance_name, mountpoint):
- virt_dom = self._lookup_by_name(instance_name)
+ def detach_volume(self, connection_info, instance_name, mountpoint):
mount_device = mountpoint.rpartition("/")[2]
- xml = self._get_disk_xml(virt_dom.XMLDesc(0), mount_device)
- if not xml:
- raise exception.DiskNotFound(location=mount_device)
- virt_dom.detachDevice(xml)
+ try:
+ # NOTE(vish): This is called to cleanup volumes after live
+ # migration, so we should still logout even if
+ # the instance doesn't exist here anymore.
+ virt_dom = self._lookup_by_name(instance_name)
+ xml = self._get_disk_xml(virt_dom.XMLDesc(0), mount_device)
+ if not xml:
+ raise exception.DiskNotFound(location=mount_device)
+ virt_dom.detachDevice(xml)
+ finally:
+ self.volume_driver_method('disconnect_volume',
+ connection_info,
+ mount_device)
@exception.wrap_exception()
def snapshot(self, context, instance, image_href):
@@ -1049,15 +1076,6 @@ class LibvirtConnection(driver.ComputeDriver):
LOG.debug(_("block_device_list %s"), block_device_list)
return block_device.strip_dev(mount_device) in block_device_list
- def _get_volume_device_info(self, device_path):
- if device_path.startswith('/dev/'):
- return ('block', None, None)
- elif ':' in device_path:
- (protocol, name) = device_path.split(':')
- return ('network', protocol, name)
- else:
- raise exception.InvalidDevicePath(path=device_path)
-
def _prepare_xml_info(self, instance, network_info, rescue,
block_device_info=None):
block_device_mapping = driver.block_device_info_get_mapping(
@@ -1075,10 +1093,14 @@ class LibvirtConnection(driver.ComputeDriver):
else:
driver_type = 'raw'
+ volumes = []
for vol in block_device_mapping:
- vol['mount_device'] = block_device.strip_dev(vol['mount_device'])
- (vol['type'], vol['protocol'], vol['name']) = \
- self._get_volume_device_info(vol['device_path'])
+ connection_info = vol['connection_info']
+ mountpoint = vol['mount_device']
+ xml = self.volume_driver_method('connect_volume',
+ connection_info,
+ mountpoint)
+ volumes.append(xml)
ebs_root = self._volume_in_mapping(self.default_root_device,
block_device_info)
@@ -1111,7 +1133,7 @@ class LibvirtConnection(driver.ComputeDriver):
'nics': nics,
'ebs_root': ebs_root,
'local_device': local_device,
- 'volumes': block_device_mapping,
+ 'volumes': volumes,
'use_virtio_for_bridges':
FLAGS.libvirt_use_virtio_for_bridges,
'ephemerals': ephemerals}
@@ -1707,6 +1729,24 @@ class LibvirtConnection(driver.ComputeDriver):
timer.f = wait_for_live_migration
timer.start(interval=0.5, now=True)
+ def pre_live_migration(self, block_device_info):
+ """Preparation live migration.
+
+ :params block_device_info:
+ It must be the result of _get_instance_volume_bdms()
+ at compute manager.
+ """
+
+ # Establishing connection to volume server.
+ block_device_mapping = driver.block_device_info_get_mapping(
+ block_device_info)
+ for vol in block_device_mapping:
+ connection_info = vol['connection_info']
+ mountpoint = vol['mount_device']
+ xml = self.volume_driver_method('connect_volume',
+ connection_info,
+ mountpoint)
+
def pre_block_migration(self, ctxt, instance_ref, disk_info_json):
"""Preparation block migration.
diff --git a/nova/virt/libvirt/volume.py b/nova/virt/libvirt/volume.py
new file mode 100644
index 000000000..caa1ec48a
--- /dev/null
+++ b/nova/virt/libvirt/volume.py
@@ -0,0 +1,149 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 OpenStack LLC.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""Volume drivers for libvirt."""
+
+import os
+import time
+
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import utils
+
+LOG = logging.getLogger('nova.virt.libvirt.volume')
+FLAGS = flags.FLAGS
+flags.DECLARE('num_iscsi_scan_tries', 'nova.volume.driver')
+
+
+class LibvirtVolumeDriver(object):
+ """Base class for volume drivers."""
+ def __init__(self, connection):
+ self.connection = connection
+
+ def connect_volume(self, connection_info, mount_device):
+ """Connect the volume. Returns xml for libvirt."""
+ device_path = connection_info['data']['device_path']
+ xml = """<disk type='block'>
+ <driver name='qemu' type='raw'/>
+ <source dev='%s'/>
+ <target dev='%s' bus='virtio'/>
+ </disk>""" % (device_path, mount_device)
+ return xml
+
+ def disconnect_volume(self, connection_info, mount_device):
+ """Disconnect the volume"""
+ pass
+
+
+class LibvirtNetVolumeDriver(LibvirtVolumeDriver):
+ """Driver to attach Network volumes to libvirt."""
+
+ def connect_volume(self, connection_info, mount_device):
+ protocol = connection_info['driver_volume_type']
+ name = connection_info['data']['name']
+ xml = """<disk type='network'>
+ <driver name='qemu' type='raw'/>
+ <source protocol='%s' name='%s'/>
+ <target dev='%s' bus='virtio'/>
+ </disk>""" % (protocol, name, mount_device)
+ return xml
+
+
+class LibvirtISCSIVolumeDriver(LibvirtVolumeDriver):
+ """Driver to attach Network volumes to libvirt."""
+
+ def _run_iscsiadm(self, iscsi_properties, iscsi_command):
+ (out, err) = utils.execute('iscsiadm', '-m', 'node', '-T',
+ iscsi_properties['target_iqn'],
+ '-p', iscsi_properties['target_portal'],
+ *iscsi_command, run_as_root=True)
+ LOG.debug("iscsiadm %s: stdout=%s stderr=%s" %
+ (iscsi_command, out, err))
+ return (out, err)
+
+ def _iscsiadm_update(self, iscsi_properties, property_key, property_value):
+ iscsi_command = ('--op', 'update', '-n', property_key,
+ '-v', property_value)
+ return self._run_iscsiadm(iscsi_properties, iscsi_command)
+
+ def connect_volume(self, connection_info, mount_device):
+ """Attach the volume to instance_name"""
+ iscsi_properties = connection_info['data']
+ try:
+ # NOTE(vish): if we are on the same host as nova volume, the
+ # discovery makes the target so we don't need to
+ # run --op new
+ self._run_iscsiadm(iscsi_properties, ())
+ except exception.ProcessExecutionError:
+ self._run_iscsiadm(iscsi_properties, ('--op', 'new'))
+
+ if iscsi_properties.get('auth_method'):
+ self._iscsiadm_update(iscsi_properties,
+ "node.session.auth.authmethod",
+ iscsi_properties['auth_method'])
+ self._iscsiadm_update(iscsi_properties,
+ "node.session.auth.username",
+ iscsi_properties['auth_username'])
+ self._iscsiadm_update(iscsi_properties,
+ "node.session.auth.password",
+ iscsi_properties['auth_password'])
+
+ self._run_iscsiadm(iscsi_properties, ("--login",))
+
+ self._iscsiadm_update(iscsi_properties, "node.startup", "automatic")
+
+ host_device = ("/dev/disk/by-path/ip-%s-iscsi-%s-lun-0" %
+ (iscsi_properties['target_portal'],
+ iscsi_properties['target_iqn']))
+
+ # The /dev/disk/by-path/... node is not always present immediately
+ # TODO(justinsb): This retry-with-delay is a pattern, move to utils?
+ tries = 0
+ while not os.path.exists(host_device):
+ if tries >= FLAGS.num_iscsi_scan_tries:
+ raise exception.Error(_("iSCSI device not found at %s") %
+ (host_device))
+
+ LOG.warn(_("ISCSI volume not yet found at: %(mount_device)s. "
+ "Will rescan & retry. Try number: %(tries)s") %
+ locals())
+
+ # The rescan isn't documented as being necessary(?), but it helps
+ self._run_iscsiadm(iscsi_properties, ("--rescan",))
+
+ tries = tries + 1
+ if not os.path.exists(host_device):
+ time.sleep(tries ** 2)
+
+ if tries != 0:
+ LOG.debug(_("Found iSCSI node %(mount_device)s "
+ "(after %(tries)s rescans)") %
+ locals())
+
+ connection_info['data']['device_path'] = host_device
+ sup = super(LibvirtISCSIVolumeDriver, self)
+ return sup.connect_volume(connection_info, mount_device)
+
+ def disconnect_volume(self, connection_info, mount_device):
+ """Detach the volume from instance_name"""
+ sup = super(LibvirtISCSIVolumeDriver, self)
+ sup.disconnect_volume(connection_info, mount_device)
+ iscsi_properties = connection_info['data']
+ self._iscsiadm_update(iscsi_properties, "node.startup", "manual")
+ self._run_iscsiadm(iscsi_properties, ("--logout",))
+ self._run_iscsiadm(iscsi_properties, ('--op', 'delete'))
diff --git a/nova/virt/vmwareapi_conn.py b/nova/virt/vmwareapi_conn.py
index fa89a8f45..12e542390 100644
--- a/nova/virt/vmwareapi_conn.py
+++ b/nova/virt/vmwareapi_conn.py
@@ -137,7 +137,8 @@ class VMWareESXConnection(driver.ComputeDriver):
"""Reboot VM instance."""
self._vmops.reboot(instance, network_info)
- def destroy(self, instance, network_info, cleanup=True):
+ def destroy(self, instance, network_info, block_device_info=None,
+ cleanup=True):
"""Destroy VM instance."""
self._vmops.destroy(instance, network_info)
@@ -173,11 +174,11 @@ class VMWareESXConnection(driver.ComputeDriver):
"""Return link to instance's ajax console."""
return self._vmops.get_ajax_console(instance)
- def attach_volume(self, instance_name, device_path, mountpoint):
+ def attach_volume(self, connection_info, instance_name, mountpoint):
"""Attach volume storage to VM instance."""
pass
- def detach_volume(self, instance_name, mountpoint):
+ def detach_volume(self, connection_info, instance_name, mountpoint):
"""Detach volume storage to VM instance."""
pass
diff --git a/nova/virt/xenapi/volume_utils.py b/nova/virt/xenapi/volume_utils.py
index 5d5eb824f..ccb4e085d 100644
--- a/nova/virt/xenapi/volume_utils.py
+++ b/nova/virt/xenapi/volume_utils.py
@@ -147,7 +147,7 @@ class VolumeHelper(HelperBase):
% sr_ref)
@classmethod
- def parse_volume_info(cls, device_path, mountpoint):
+ def parse_volume_info(cls, connection_info, mountpoint):
"""
Parse device_path and mountpoint as they can be used by XenAPI.
In particular, the mountpoint (e.g. /dev/sdc) must be translated
@@ -161,11 +161,12 @@ class VolumeHelper(HelperBase):
the iscsi driver to set them.
"""
device_number = VolumeHelper.mountpoint_to_number(mountpoint)
- volume_id = _get_volume_id(device_path)
- (iscsi_name, iscsi_portal) = _get_target(volume_id)
- target_host = _get_target_host(iscsi_portal)
- target_port = _get_target_port(iscsi_portal)
- target_iqn = _get_iqn(iscsi_name, volume_id)
+ data = connection_info['data']
+ volume_id = data['volume_id']
+ target_portal = data['target_portal']
+ target_host = _get_target_host(target_portal)
+ target_port = _get_target_port(target_portal)
+ target_iqn = data['target_iqn']
LOG.debug('(vol_id,number,host,port,iqn): (%s,%s,%s,%s)',
volume_id, target_host, target_port, target_iqn)
if (device_number < 0) or \
@@ -173,7 +174,7 @@ class VolumeHelper(HelperBase):
(target_host is None) or \
(target_iqn is None):
raise StorageError(_('Unable to obtain target information'
- ' %(device_path)s, %(mountpoint)s') % locals())
+ ' %(data)s, %(mountpoint)s') % locals())
volume_info = {}
volume_info['deviceNumber'] = device_number
volume_info['volumeId'] = volume_id
diff --git a/nova/virt/xenapi/volumeops.py b/nova/virt/xenapi/volumeops.py
index afcb8cf47..661373c4a 100644
--- a/nova/virt/xenapi/volumeops.py
+++ b/nova/virt/xenapi/volumeops.py
@@ -40,18 +40,21 @@ class VolumeOps(object):
VolumeHelper.XenAPI = self.XenAPI
VMHelper.XenAPI = self.XenAPI
- def attach_volume(self, instance_name, device_path, mountpoint):
+ def attach_volume(self, connection_info, instance_name, mountpoint):
"""Attach volume storage to VM instance"""
# Before we start, check that the VM exists
vm_ref = VMHelper.lookup(self._session, instance_name)
if vm_ref is None:
raise exception.InstanceNotFound(instance_id=instance_name)
# NOTE: No Resource Pool concept so far
- LOG.debug(_("Attach_volume: %(instance_name)s, %(device_path)s,"
+ LOG.debug(_("Attach_volume: %(connection_info)s, %(instance_name)s,"
" %(mountpoint)s") % locals())
+ driver_type = connection_info['driver_volume_type']
+ if driver_type != 'iscsi':
+ raise exception.VolumeDriverNotFound(driver_type=driver_type)
# Create the iSCSI SR, and the PDB through which hosts access SRs.
# But first, retrieve target info, like Host, IQN, LUN and SCSIID
- vol_rec = VolumeHelper.parse_volume_info(device_path, mountpoint)
+ vol_rec = VolumeHelper.parse_volume_info(connection_info, mountpoint)
label = 'SR-%s' % vol_rec['volumeId']
description = 'Disk-for:%s' % instance_name
# Create SR
@@ -92,7 +95,7 @@ class VolumeOps(object):
LOG.info(_('Mountpoint %(mountpoint)s attached to'
' instance %(instance_name)s') % locals())
- def detach_volume(self, instance_name, mountpoint):
+ def detach_volume(self, connection_info, instance_name, mountpoint):
"""Detach volume storage to VM instance"""
# Before we start, check that the VM exists
vm_ref = VMHelper.lookup(self._session, instance_name)
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index e63a06ad2..f2c41613c 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -222,7 +222,8 @@ class XenAPIConnection(driver.ComputeDriver):
"""
self._vmops.inject_file(instance, b64_path, b64_contents)
- def destroy(self, instance, network_info, cleanup=True):
+ def destroy(self, instance, network_info, block_device_info=None,
+ cleanup=True):
"""Destroy VM instance"""
self._vmops.destroy(instance, network_info)
@@ -302,15 +303,17 @@ class XenAPIConnection(driver.ComputeDriver):
xs_url = urlparse.urlparse(FLAGS.xenapi_connection_url)
return xs_url.netloc
- def attach_volume(self, instance_name, device_path, mountpoint):
+ def attach_volume(self, connection_info, instance_name, mountpoint):
"""Attach volume storage to VM instance"""
- return self._volumeops.attach_volume(instance_name,
- device_path,
- mountpoint)
+ return self._volumeops.attach_volume(connection_info,
+ instance_name,
+ mountpoint)
- def detach_volume(self, instance_name, mountpoint):
+ def detach_volume(self, connection_info, instance_name, mountpoint):
"""Detach volume storage to VM instance"""
- return self._volumeops.detach_volume(instance_name, mountpoint)
+ return self._volumeops.detach_volume(connection_info,
+ instance_name,
+ mountpoint)
def get_console_pool_info(self, console_type):
xs_url = urlparse.urlparse(FLAGS.xenapi_connection_url)