From 551a7a459c6503158cb4512fec8b2dc9c0641abe Mon Sep 17 00:00:00 2001 From: Sergii Golovatiuk Date: Tue, 7 Aug 2018 19:49:37 +0300 Subject: [PATCH] libvirt: Always escape IPv6 addresses when used in migration URI If IPv6 is passed to URI it should be wrapped within square brackets. This patch detects IPv6 to form migration URI properly. Domain name, IPv4 or already bracketed IPv6 address will pass as is Extend tests to include collapsed IPv6 addresses and IPv6 addresses with port Change-Id: I1201db996ea6ceaebd49479b298d74585a78b006 Closes-Bug: #1786058 (cherry picked from commit 8b019d6f1e7893a7e308bd79c879e94d3400e007) (cherry picked from commit 7ee5499e5507c45249945fa5baf7665bc2f1cc02) --- nova/tests/unit/virt/libvirt/test_driver.py | 73 +++++++++++++++---- nova/virt/libvirt/driver.py | 5 ++ ..._ipv6_live_migration-bbcde8f3b7d17921.yaml | 4 + 3 files changed, 67 insertions(+), 15 deletions(-) create mode 100644 releasenotes/notes/libvirt_fix_ipv6_live_migration-bbcde8f3b7d17921.yaml diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 907a83c87b9e..8533591e0403 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -9269,6 +9269,10 @@ class LibvirtConnTestCase(test.NoDBTestCase, etree.tostring(config, encoding='unicode')) def test_live_migration_uri(self): + addresses = ('127.0.0.1', '127.0.0.1:4444', '[::1]:4444', + '[0:0:0:0:0:0:0:1]:4444', u'127.0.0.1', u'destination', + ) + hypervisor_uri_map = ( ('xen', 'xenmigr://%s/system'), ('kvm', 'qemu+tcp://%s/system'), @@ -9277,17 +9281,42 @@ class LibvirtConnTestCase(test.NoDBTestCase, # anything else will return None ('lxc', None), ) - dest = 'destination' - for hyperv, uri in hypervisor_uri_map: - self.flags(virt_type=hyperv, group='libvirt') - drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) - if uri is not None: - uri = uri % dest - self.assertEqual(uri, drvr._live_migration_uri(dest)) - else: - self.assertRaises(exception.LiveMigrationURINotAvailable, - drvr._live_migration_uri, - dest) + + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) + for dest in addresses: + for hyperv, uri in hypervisor_uri_map: + self.flags(virt_type=hyperv, group='libvirt') + if uri is not None: + uri = uri % dest + self.assertEqual(uri, drvr._live_migration_uri(dest)) + else: + self.assertRaises(exception.LiveMigrationURINotAvailable, + drvr._live_migration_uri, + dest) + + def test_live_migration_uri_ipv6(self): + addresses = ('::1', '0:0:0:0:0:0:0:1', u'::1') + + hypervisor_uri_map = ( + ('xen', 'xenmigr://[%s]/system'), + ('kvm', 'qemu+tcp://[%s]/system'), + ('qemu', 'qemu+tcp://[%s]/system'), + ('parallels', 'parallels+tcp://[%s]/system'), + # anything else will return None + ('lxc', None), + ) + + for dest in addresses: + for hyperv, uri in hypervisor_uri_map: + self.flags(virt_type=hyperv, group='libvirt') + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) + if uri is not None: + uri = uri % dest + self.assertEqual(uri, drvr._live_migration_uri(dest)) + else: + self.assertRaises(exception.LiveMigrationURINotAvailable, + drvr._live_migration_uri, + dest) def test_live_migration_uri_forced(self): dest = 'destination' @@ -9343,12 +9372,26 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.flags(virt_type='kvm', group='libvirt') drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) - addresses = ('127.0.0.1', '127.0.0.1:4444', - '0:0:0:0:0:0:0:1', '[0:0:0:0:0:0:0:1]:4444', - u'127.0.0.1', u'destination') + addresses = ('127.0.0.1', '127.0.0.1:4444', '[::1]:4444', + '[0:0:0:0:0:0:0:1]:4444', u'127.0.0.1', u'destination', + ) + for dest in addresses: + uri = 'tcp://%s' result = drvr._migrate_uri(dest) - self.assertEqual('tcp://%s' % dest, result) + self.assertEqual(uri % dest, result) + self.assertIsInstance(result, str) + + def test_migrate_uri_forced_live_migration_inboud_addr_ipv6(self): + self.flags(virt_type='kvm', group='libvirt') + + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) + addresses = ('::1', '0:0:0:0:0:0:0:1', u'::1') + + for dest in addresses: + uri = 'tcp://[%s]' + result = drvr._migrate_uri(dest) + self.assertEqual(uri % dest, result) self.assertIsInstance(result, str) def test_update_volume_xml_no_serial(self): diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index c8ac4e23ecca..a01de9fda168 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -59,6 +59,7 @@ from oslo_utils import encodeutils from oslo_utils import excutils from oslo_utils import fileutils from oslo_utils import importutils +from oslo_utils import netutils as oslo_netutils from oslo_utils import strutils from oslo_utils import timeutils from oslo_utils import units @@ -741,6 +742,8 @@ class LibvirtDriver(driver.ComputeDriver): 'xen': 'xenmigr://%s/system', 'parallels': 'parallels+tcp://%s/system', } + dest = oslo_netutils.escape_ipv6(dest) + virt_type = CONF.libvirt.virt_type # TODO(pkoniszewski): Remove fetching live_migration_uri in Pike uri = CONF.libvirt.live_migration_uri @@ -760,6 +763,8 @@ class LibvirtDriver(driver.ComputeDriver): @staticmethod def _migrate_uri(dest): uri = None + dest = oslo_netutils.escape_ipv6(dest) + # Only QEMU live migrations supports migrate-uri parameter virt_type = CONF.libvirt.virt_type if virt_type in ('qemu', 'kvm'): diff --git a/releasenotes/notes/libvirt_fix_ipv6_live_migration-bbcde8f3b7d17921.yaml b/releasenotes/notes/libvirt_fix_ipv6_live_migration-bbcde8f3b7d17921.yaml new file mode 100644 index 000000000000..7171f73a5588 --- /dev/null +++ b/releasenotes/notes/libvirt_fix_ipv6_live_migration-bbcde8f3b7d17921.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - A change has been introduced in the libvirt driver to correctly handle + IPv6 addresses for live migration.