Skip to content

Instantly share code, notes, and snippets.

@yosshy
Last active August 29, 2015 14:04
Show Gist options
  • Save yosshy/5b6bd323bb631316ef3e to your computer and use it in GitHub Desktop.
Save yosshy/5b6bd323bb631316ef3e to your computer and use it in GitHub Desktop.
Libvirt/QEMU iSCSI pass-through patch for Nova Juno
<domain type='qemu' id='9'>
<name>instance-00000005</name>
<uuid>528dc044-4ea2-4cb7-9ebe-f1a03875490c</uuid>
<memory unit='KiB'>2097152</memory>
<currentMemory unit='KiB'>2097152</currentMemory>
<vcpu placement='static'>1</vcpu>
<resource>
<partition>/machine</partition>
</resource>
<sysinfo type='smbios'>
<system>
<entry name='manufacturer'>OpenStack Foundation</entry>
<entry name='product'>OpenStack Nova</entry>
<entry name='version'>2014.2</entry>
<entry name='serial'>ba8d6b41-89e8-4f4a-b887-cee4070e8d9f</entry>
<entry name='uuid'>528dc044-4ea2-4cb7-9ebe-f1a03875490c</entry>
</system>
</sysinfo>
<os>
<type arch='x86_64' machine='pc-i440fx-trusty'>hvm</type>
<boot dev='hd'/>
<smbios mode='sysinfo'/>
</os>
<features>
<acpi/>
<apic/>
</features>
<cpu>
<topology sockets='1' cores='1' threads='1'/>
</cpu>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='none'/>
<source file='/opt/stack/data/nova/instances/528dc044-4ea2-4cb7-9ebe-f1a03875490c/disk'/>
<target dev='vda' bus='virtio'/>
<alias name='virtio-disk0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</disk>
<disk type='network' device='disk'>
<driver name='qemu' type='raw' cache='none'/>
<auth username='XfeKqEHYULdN6NSbCiXH'>
<secret type='iscsi' uuid='dc3d9e94-f7f1-401a-88c2-477107bbb8af'/>
</auth>
<source protocol='iscsi' name='iqn.2010-10.org.openstack:volume-d09da9fc-4d71-4b11-b74a-7561c5dfd224/1'>
<host name='10.0.2.15' port='3260'/>
</source>
<target dev='vdb' bus='virtio'/>
<serial>d09da9fc-4d71-4b11-b74a-7561c5dfd224</serial>
<alias name='virtio-disk1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</disk>
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw' cache='none'/>
<source file='/opt/stack/data/nova/instances/528dc044-4ea2-4cb7-9ebe-f1a03875490c/disk.config'/>
<target dev='hdd' bus='ide'/>
<readonly/>
<alias name='ide0-1-1'/>
<address type='drive' controller='0' bus='1' target='0' unit='1'/>
</disk>
<controller type='usb' index='0'>
<alias name='usb0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
</controller>
<controller type='pci' index='0' model='pci-root'>
<alias name='pci.0'/>
</controller>
<controller type='ide' index='0'>
<alias name='ide0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<interface type='bridge'>
<mac address='fa:16:3e:1f:7b:f9'/>
<source bridge='br100'/>
<target dev='vnet0'/>
<model type='virtio'/>
<driver name='qemu'/>
<filterref filter='nova-instance-instance-00000005-fa163e1f7bf9'/>
<alias name='net0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<serial type='file'>
<source path='/opt/stack/data/nova/instances/528dc044-4ea2-4cb7-9ebe-f1a03875490c/console.log'/>
<target port='0'/>
<alias name='serial0'/>
</serial>
<serial type='pty'>
<source path='/dev/pts/25'/>
<target port='1'/>
<alias name='serial1'/>
</serial>
<console type='file'>
<source path='/opt/stack/data/nova/instances/528dc044-4ea2-4cb7-9ebe-f1a03875490c/console.log'/>
<target type='serial' port='0'/>
<alias name='serial0'/>
</console>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='vnc' port='5900' autoport='yes' listen='127.0.0.1' keymap='ja'>
<listen type='address' address='127.0.0.1'/>
</graphics>
<video>
<model type='cirrus' vram='9216' heads='1'/>
<alias name='video0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
<memballoon model='virtio'>
<alias name='balloon0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</memballoon>
</devices>
<seclabel type='dynamic' model='apparmor' relabel='yes'>
<label>libvirt-528dc044-4ea2-4cb7-9ebe-f1a03875490c</label>
<imagelabel>libvirt-528dc044-4ea2-4cb7-9ebe-f1a03875490c</imagelabel>
</seclabel>
</domain>
commit a65bb5b87f2f662e6dd3ec9a04d3d3fd1f4f29ab
Author: Akira Yoshiyama <[email protected]>
Date: Tue Jul 29 14:58:30 2014 +0000
Add KVM/QEMU iSCSI pass-through capability.
This patch allows nova-compute to use KVM/QEMU iSCSI pass-through
capability for Cinder iSCSI volume drivers. It doesn't provide
iSCSI multipath capability, but host OS doesn't have to handle
iSCSI connection for volume because KVM/QEMU does it directly
with libiscsi.
To use this, you have to write a parameter at nova.conf:
volume_drivers = iscsi=nova.virt.libvirt.volume.LibvirtNetVolumeDriver,iser=nova.virt.libvirt.volume.LibvirtISERVolumeDriver,...
or just
volume_drivers = iscsi=nova.virt.libvirt.volume.LibvirtNetVolumeDriver
Note that qemu-system-x86 in Ubuntu has no iSCSI pass-through
support because libiscsi isn't in main repository but universe.
I've tested qemu-system-x86 built with libiscsi2 package of
Debian on Ubuntu 14.04.
diff --git a/nova/virt/libvirt/config.py b/nova/virt/libvirt/config.py
index 0255ac1..b0844ac 100644
--- a/nova/virt/libvirt/config.py
+++ b/nova/virt/libvirt/config.py
@@ -1717,3 +1717,38 @@ class LibvirtConfigGuestMetaNovaOwner(LibvirtConfigObject):
project.set("uuid", self.projectid)
meta.append(project)
return meta
+
+
+class LibvirtConfigSecret(LibvirtConfigObject):
+
+ def __init__(self):
+ super(LibvirtConfigSecret,
+ self).__init__(root_name="secret")
+ self.ephemeral = False
+ self.private = False
+ self.description = None
+ self.usage_type = None
+ self.usage_name = None
+ self.usage_target = None
+
+ def get_bool_str(self, value):
+ if value:
+ return 'yes'
+ return 'no'
+
+ def format_dom(self):
+ root = super(LibvirtConfigSecret, self).format_dom()
+ root.set("ephemeral", self.get_bool_str(self.ephemeral))
+ root.set("private", self.get_bool_str(self.private))
+ if self.description is not None:
+ root.append(self._text_node("description", str(self.description)))
+ if self.usage_target is not None and self.usage_type is not None:
+ usage = self._new_node("usage")
+ if self.usage_type is not None:
+ usage.set("type", self.usage_type)
+ if self.usage_name is not None:
+ usage.append(self._text_node('name', str(self.usage_name)))
+ if self.usage_target is not None:
+ usage.append(self._text_node('target', str(self.usage_target)))
+ root.append(usage)
+ return root
diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py
index 16c4e69..31c49a1 100644
--- a/nova/virt/libvirt/driver.py
+++ b/nova/virt/libvirt/driver.py
@@ -5515,6 +5515,50 @@ class LibvirtDriver(driver.ComputeDriver):
return fs_type in [disk.FS_FORMAT_EXT2, disk.FS_FORMAT_EXT3,
disk.FS_FORMAT_EXT4, disk.FS_FORMAT_XFS]
+ def _find_secret(self, usage_type_str, usage_name):
+ if usage_type_str == 'iscsi':
+ usage_type = libvirt.VIR_SECRET_USAGE_TYPE_ISCSI
+ elif usage_type_str == 'ceph':
+ usage_type = libvirt.VIR_SECRET_USAGE_TYPE_CEPH
+ elif usage_type_str == 'volume':
+ usage_type = libvirt.VIR_SECRET_USAGE_TYPE_VOLUME
+
+ return self._conn.secretLookupByUsage(usage_type, usage_name)
+
+ def get_secret(self, secret_conf, password=None):
+ """Create a secret.
+
+ secret_conf must be passed in.
+ """
+ try:
+ usage_name = secret_conf.usage_name or secret_conf.usage_target
+ usage_type = secret_conf.usage_type
+ return self._find_secret(usage_type, usage_name)
+ except Exception:
+ pass
+
+ xml = secret_conf.to_xml()
+ try:
+ LOG.debug(_LE('Secret XML: %s') % xml)
+ secret = self._conn.secretDefineXML(xml)
+ if password is not None:
+ secret.setValue(password)
+ return secret
+ except Exception:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error defining a secret with XML: %s') % xml)
+
+ def delete_secret(self, usage_type, usage_name):
+ """Delete a secret.
+
+ secret_conf must be passed in.
+ """
+ try:
+ secret = self._find_secret(usage_type, usage_name)
+ secret.undefine()
+ except Exception:
+ pass
+
class HostState(object):
"""Manages information about the compute node through libvirt."""
diff --git a/nova/virt/libvirt/volume.py b/nova/virt/libvirt/volume.py
index 261216b..ff94af5 100644
--- a/nova/virt/libvirt/volume.py
+++ b/nova/virt/libvirt/volume.py
@@ -190,6 +190,31 @@ class LibvirtNetVolumeDriver(LibvirtBaseVolumeDriver):
super(LibvirtNetVolumeDriver,
self).__init__(connection, is_block_dev=False)
+ def _get_secret_uuid(self, conf, password=None):
+ secret_conf = vconfig.LibvirtConfigSecret()
+ secret_conf.ephemeral = False
+ secret_conf.private = False
+ secret_conf.usage_type = conf.source_protocol
+ if conf.source_protocol == 'rbd':
+ secret_conf.usage_type = 'ceph'
+ secret_conf.usage_name = conf.source_name
+ elif conf.source_protocol == 'iscsi':
+ secret_conf.usage_type = 'iscsi'
+ secret_conf.usage_target = conf.source_name
+ secret = self.connection.get_secret(secret_conf, password)
+ return secret.UUIDString()
+
+ def _delete_secret_by_name(self, connection_info):
+ source_protocol = connection_info['driver_volume_type']
+ netdisk_properties = connection_info['data']
+ if source_protocol == 'rbd':
+ return
+ elif source_protocol == 'iscsi':
+ usage_type = 'iscsi'
+ usage_name = ("%(target_iqn)s/%(target_lun)s" %
+ netdisk_properties)
+ self.connection.delete_secret(usage_type, usage_name)
+
def connect_volume(self, connection_info, disk_info):
conf = super(LibvirtNetVolumeDriver,
self).connect_volume(connection_info,
@@ -207,14 +232,32 @@ class LibvirtNetVolumeDriver(LibvirtBaseVolumeDriver):
auth_enabled = True # Force authentication locally
if CONF.libvirt.rbd_user:
conf.auth_username = CONF.libvirt.rbd_user
+ if conf.source_protocol == 'iscsi':
+ conf.source_name = ("%(target_iqn)s/%(target_lun)s" %
+ netdisk_properties)
+ ip, port = netdisk_properties.get('target_portal', "").split(':')
+ conf.source_hosts = [ip]
+ conf.source_ports = [port]
+ if netdisk_properties.get('auth_method') == 'CHAP':
+ auth_enabled = True
+ conf.auth_secret_type = 'iscsi'
+ password = netdisk_properties.get('auth_password')
+ conf.auth_secret_uuid = self._get_secret_uuid(conf, password)
if auth_enabled:
conf.auth_username = (conf.auth_username or
netdisk_properties['auth_username'])
- conf.auth_secret_type = netdisk_properties['secret_type']
+ conf.auth_secret_type = (conf.auth_secret_type or
+ netdisk_properties['secret_type'])
conf.auth_secret_uuid = (conf.auth_secret_uuid or
netdisk_properties['secret_uuid'])
return conf
+ def disconnect_volume(self, connection_info, disk_dev):
+ """Detach the volume from instance_name."""
+ super(LibvirtNetVolumeDriver,
+ self).disconnect_volume(connection_info, disk_dev)
+ self._delete_secret_by_name(connection_info)
+
class LibvirtISCSIVolumeDriver(LibvirtBaseVolumeDriver):
"""Driver to attach Network volumes to libvirt."""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment