diff options
| author | Vishvananda Ishaya <vishvananda@gmail.com> | 2011-09-23 09:22:32 -0700 |
|---|---|---|
| committer | Vishvananda Ishaya <vishvananda@gmail.com> | 2011-10-11 14:25:04 -0700 |
| commit | eb03d47fecd3bfc24243da29ee01679b334a08fe (patch) | |
| tree | 23243973d2656fecadab6811e0dca6ceb246a7ae /nova/virt | |
| parent | e164f3f703026db30937dbbddc63818cef8bd939 (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.py | 16 | ||||
| -rw-r--r-- | nova/virt/fake.py | 23 | ||||
| -rw-r--r-- | nova/virt/hyperv.py | 7 | ||||
| -rw-r--r-- | nova/virt/libvirt.xml.template | 22 | ||||
| -rw-r--r-- | nova/virt/libvirt/connection.py | 138 | ||||
| -rw-r--r-- | nova/virt/libvirt/volume.py | 149 | ||||
| -rw-r--r-- | nova/virt/vmwareapi_conn.py | 7 | ||||
| -rw-r--r-- | nova/virt/xenapi/volume_utils.py | 15 | ||||
| -rw-r--r-- | nova/virt/xenapi/volumeops.py | 11 | ||||
| -rw-r--r-- | nova/virt/xenapi_conn.py | 17 |
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) |
