Merge "libvirt: add IP address to libvirt guest metadata"
This commit is contained in:
commit
44611935b8
@ -187,6 +187,11 @@ VIR_SECRET_USAGE_TYPE_VOLUME = 1
|
||||
VIR_SECRET_USAGE_TYPE_CEPH = 2
|
||||
VIR_SECRET_USAGE_TYPE_ISCSI = 3
|
||||
|
||||
# metadata types
|
||||
VIR_DOMAIN_METADATA_DESCRIPTION = 0
|
||||
VIR_DOMAIN_METADATA_TITLE = 1
|
||||
VIR_DOMAIN_METADATA_ELEMENT = 2
|
||||
|
||||
# Libvirt version to match MIN_LIBVIRT_VERSION in driver.py
|
||||
FAKE_LIBVIRT_VERSION = versionutils.convert_version_to_int(
|
||||
libvirt_driver.MIN_LIBVIRT_VERSION)
|
||||
@ -1390,6 +1395,9 @@ class Domain(object):
|
||||
def fsThaw(self):
|
||||
pass
|
||||
|
||||
def setMetadata(self, metadata_type, metadata, key, uri, flags=0):
|
||||
pass
|
||||
|
||||
|
||||
class DomainSnapshot(object):
|
||||
def __init__(self, name, domain):
|
||||
|
@ -3510,9 +3510,30 @@ class LibvirtConfigGuestMetadataNovaTest(LibvirtConfigBaseTest):
|
||||
|
||||
meta.flavor = flavor
|
||||
|
||||
meta.ports = config.LibvirtConfigGuestMetaNovaPorts(
|
||||
ports=[
|
||||
config.LibvirtConfigGuestMetaNovaPort(
|
||||
'567a4527-b0e4-4d0a-bcc2-71fda37897f7',
|
||||
ips=[
|
||||
config.LibvirtConfigGuestMetaNovaIp(
|
||||
'fixed', '192.168.1.1', '4'),
|
||||
config.LibvirtConfigGuestMetaNovaIp(
|
||||
'fixed', 'fe80::f95c:b030:7094', '6'),
|
||||
config.LibvirtConfigGuestMetaNovaIp(
|
||||
'floating', '11.22.33.44', '4')]),
|
||||
config.LibvirtConfigGuestMetaNovaPort(
|
||||
'a3ca97e2-0cf9-4159-9bfc-afd55bc13ead',
|
||||
ips=[
|
||||
config.LibvirtConfigGuestMetaNovaIp(
|
||||
'fixed', '10.0.0.1', '4'),
|
||||
config.LibvirtConfigGuestMetaNovaIp(
|
||||
'fixed', 'fdf8:f53b:82e4::52', '6'),
|
||||
config.LibvirtConfigGuestMetaNovaIp(
|
||||
'floating', '1.2.3.4', '4')])])
|
||||
|
||||
xml = meta.to_xml()
|
||||
self.assertXmlEqual(xml, """
|
||||
<nova:instance xmlns:nova='http://openstack.org/xmlns/libvirt/nova/1.0'>
|
||||
<nova:instance xmlns:nova='http://openstack.org/xmlns/libvirt/nova/1.1'>
|
||||
<nova:package version="2014.2.3"/>
|
||||
<nova:name>moonbuggy</nova:name>
|
||||
<nova:creationTime>2009-02-13 23:31:30</nova:creationTime>
|
||||
@ -3530,6 +3551,18 @@ class LibvirtConfigGuestMetadataNovaTest(LibvirtConfigBaseTest):
|
||||
uuid="f241e906-010e-4917-ae81-53f4fb8aa021">moonshot</nova:project>
|
||||
</nova:owner>
|
||||
<nova:root type="image" uuid="fe55c69a-8b2e-4bbc-811a-9ad2023a0426"/>
|
||||
<nova:ports>
|
||||
<nova:port uuid="567a4527-b0e4-4d0a-bcc2-71fda37897f7">
|
||||
<nova:ip type="fixed" address="192.168.1.1" ipVersion="4"/>
|
||||
<nova:ip type="fixed" address="fe80::f95c:b030:7094" ipVersion="6"/>
|
||||
<nova:ip type="floating" address="11.22.33.44" ipVersion="4"/>
|
||||
</nova:port>
|
||||
<nova:port uuid="a3ca97e2-0cf9-4159-9bfc-afd55bc13ead">
|
||||
<nova:ip type="fixed" address="10.0.0.1" ipVersion="4"/>
|
||||
<nova:ip type="fixed" address="fdf8:f53b:82e4::52" ipVersion="6"/>
|
||||
<nova:ip type="floating" address="1.2.3.4" ipVersion="4"/>
|
||||
</nova:port>
|
||||
</nova:ports>
|
||||
</nova:instance>
|
||||
""")
|
||||
|
||||
|
@ -784,6 +784,9 @@ class FakeVirtDomain(object):
|
||||
def undefine(self):
|
||||
return True
|
||||
|
||||
def setMetadata(self, metadata_type, metadata, key, uri, flags=0):
|
||||
pass
|
||||
|
||||
|
||||
class CacheConcurrencyTestCase(test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
@ -2687,6 +2690,44 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
||||
# our stub method is called which asserts the password is scrubbed
|
||||
self.assertTrue(debug_mock.called)
|
||||
|
||||
def test_get_guest_config_meta_with_no_port(self):
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
meta = drvr._get_guest_config_meta(
|
||||
objects.Instance(**self.test_instance),
|
||||
_fake_network_info(self, num_networks=0))
|
||||
|
||||
self.assertEqual(len(meta.ports.ports), 0)
|
||||
|
||||
def test_get_guest_config_meta_with_multiple_ports(self):
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
meta = drvr._get_guest_config_meta(
|
||||
objects.Instance(**self.test_instance),
|
||||
_fake_network_info(self, num_networks=2))
|
||||
|
||||
self.assertEqual(len(meta.ports.ports), 2)
|
||||
|
||||
# first port
|
||||
self.assertEqual(meta.ports.ports[0].uuid, getattr(uuids, 'vif1'))
|
||||
self.assertEqual(len(meta.ports.ports[0].ips), 2)
|
||||
self.assertEqual(meta.ports.ports[0].ips[0].address, '192.168.1.100')
|
||||
self.assertEqual(meta.ports.ports[0].ips[0].ip_type, 'fixed')
|
||||
self.assertEqual(meta.ports.ports[0].ips[0].ip_version, 4)
|
||||
self.assertEqual(meta.ports.ports[0].ips[1].address,
|
||||
'2001:db8:0:1:dcad:beff:feef:1')
|
||||
self.assertEqual(meta.ports.ports[0].ips[1].ip_type, 'fixed')
|
||||
self.assertEqual(meta.ports.ports[0].ips[1].ip_version, 6)
|
||||
|
||||
# second port
|
||||
self.assertEqual(meta.ports.ports[1].uuid, getattr(uuids, 'vif2'))
|
||||
self.assertEqual(len(meta.ports.ports[0].ips), 2)
|
||||
self.assertEqual(meta.ports.ports[1].ips[0].address, '192.168.2.100')
|
||||
self.assertEqual(meta.ports.ports[1].ips[0].ip_type, 'fixed')
|
||||
self.assertEqual(meta.ports.ports[1].ips[0].ip_version, 4)
|
||||
self.assertEqual(meta.ports.ports[1].ips[1].address,
|
||||
'2001:db8:0:2:dcad:beff:feef:1')
|
||||
self.assertEqual(meta.ports.ports[1].ips[1].ip_type, 'fixed')
|
||||
self.assertEqual(meta.ports.ports[1].ips[1].ip_version, 6)
|
||||
|
||||
@mock.patch.object(time, "time")
|
||||
def test_get_guest_config(self, time_mock):
|
||||
time_mock.return_value = 1234567.89
|
||||
@ -18778,6 +18819,8 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
||||
mock_build.return_value = objects.InstanceDeviceMetadata()
|
||||
mock_save = self.useFixture(fixtures.MockPatchObject(
|
||||
objects.Instance, 'save')).mock
|
||||
mock_get_network_info = self.useFixture(fixtures.MockPatchObject(
|
||||
objects.Instance, 'get_network_info')).mock
|
||||
|
||||
expected = drvr.vif_driver.get_config(instance, network_info[0],
|
||||
fake_image_meta,
|
||||
@ -18792,6 +18835,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
||||
network_info[0])
|
||||
mock_build.assert_called_once_with(self.context, instance)
|
||||
mock_save.assert_called_once_with()
|
||||
mock_get_network_info.assert_called_once_with()
|
||||
elif method_name == "detach_interface":
|
||||
drvr.detach_interface(self.context, instance, network_info[0])
|
||||
else:
|
||||
@ -23053,6 +23097,37 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
||||
mock_detach_interface.assert_called_with(self.context, instance,
|
||||
network_info[0])
|
||||
|
||||
def test_attach_interface_guest_set_metadata(self):
|
||||
guest = mock.Mock(spec=libvirt_guest.Guest)
|
||||
instance = self._create_instance()
|
||||
network_info = _fake_network_info(self)[0]
|
||||
domain = FakeVirtDomain(fake_xml='</xml>')
|
||||
image_meta = objects.ImageMeta.from_dict({})
|
||||
config_meta = vconfig.LibvirtConfigGuestMetaNovaInstance()
|
||||
|
||||
with test.nested(
|
||||
mock.patch.object(host.Host, '_get_domain', return_value=domain),
|
||||
mock.patch.object(self.drvr, '_build_device_metadata',
|
||||
return_value=objects.InstanceDeviceMetadata()),
|
||||
mock.patch.object(instance, 'save'),
|
||||
mock.patch.object(instance, 'get_network_info'),
|
||||
mock.patch.object(
|
||||
self.drvr, '_get_guest_config_meta', return_value=config_meta),
|
||||
mock.patch.object(guest, 'set_metadata'),
|
||||
mock.patch.object(self.drvr._host, 'get_guest', return_value=guest)
|
||||
) as (
|
||||
mock_get_domain, mock_build_device_metadata, mock_save,
|
||||
mock_get_network_info, mock_get_guest_config_meta,
|
||||
mock_set_metadata, mock_get_guest
|
||||
):
|
||||
self.drvr.attach_interface(
|
||||
self.context, instance, image_meta, network_info)
|
||||
mock_build_device_metadata.assert_called_once_with(
|
||||
self.context, instance)
|
||||
mock_save.assert_called_once_with()
|
||||
mock_set_metadata.assert_called_once_with(config_meta)
|
||||
|
||||
@mock.patch.object(objects.Instance, 'get_network_info')
|
||||
@mock.patch.object(objects.Instance, 'save')
|
||||
@mock.patch.object(libvirt_driver.LibvirtDriver, '_build_device_metadata')
|
||||
@mock.patch.object(FakeVirtDomain, 'info')
|
||||
@ -23060,7 +23135,8 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
||||
@mock.patch.object(host.Host, '_get_domain')
|
||||
def _test_attach_interface(self, power_state, expected_flags,
|
||||
mock_get_domain, mock_attach,
|
||||
mock_info, mock_build, mock_save):
|
||||
mock_info, mock_build, mock_save,
|
||||
mock_get_network_info):
|
||||
instance = self._create_instance()
|
||||
network_info = _fake_network_info(self)
|
||||
domain = FakeVirtDomain(fake_xml="""
|
||||
@ -23100,6 +23176,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
||||
mock_info.assert_called_once_with()
|
||||
mock_build.assert_called_once_with(self.context, instance)
|
||||
mock_save.assert_called_once_with()
|
||||
mock_get_network_info.assert_called_once_with()
|
||||
mock_attach.assert_called_once_with(expected.to_xml(),
|
||||
flags=expected_flags)
|
||||
|
||||
@ -23166,11 +23243,12 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
||||
side_effect=get_interface_calls),
|
||||
mock.patch.object(domain, 'detachDeviceFlags'),
|
||||
mock.patch('nova.virt.libvirt.driver.LOG.warning'),
|
||||
mock.patch.object(self.drvr.vif_driver, 'unplug')
|
||||
mock.patch.object(self.drvr.vif_driver, 'unplug'),
|
||||
mock.patch.object(instance, 'get_network_info')
|
||||
) as (
|
||||
mock_get_guest, mock_get_config,
|
||||
mock_get_interface, mock_detach_device_flags,
|
||||
mock_warning, mock_unplug
|
||||
mock_warning, mock_unplug, mock_get_network_info
|
||||
):
|
||||
# run the detach method
|
||||
self.drvr.detach_interface(self.context, instance, network_info[0])
|
||||
@ -23190,6 +23268,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
||||
mock_detach_device_flags.assert_called_once_with(
|
||||
expected_cfg.to_xml(), flags=expected_flags)
|
||||
mock_warning.assert_not_called()
|
||||
mock_get_network_info.assert_called_once_with()
|
||||
|
||||
mock_unplug.assert_called_once_with(instance, network_info[0])
|
||||
|
||||
@ -23312,7 +23391,8 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
||||
side_effect=[expected, expected, None, None]),
|
||||
mock.patch.object(self.drvr.vif_driver, 'get_config',
|
||||
return_value=expected),
|
||||
) as (mock_get_interface, mock_get_config):
|
||||
mock.patch.object(instance, 'get_network_info')
|
||||
) as (mock_get_interface, mock_get_config, mock_get_network_info):
|
||||
self.drvr.detach_interface(self.context, instance, network_info[0])
|
||||
|
||||
mock_get_interface.assert_has_calls([mock.call(expected)] * 3)
|
||||
@ -23324,6 +23404,58 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
||||
mock_info.assert_called_once_with()
|
||||
mock_detach.assert_called_once_with(expected.to_xml(),
|
||||
flags=expected_flags)
|
||||
mock_get_network_info.assert_called_once_with()
|
||||
|
||||
def test_detach_interface_guest_set_metadata(self):
|
||||
guest = mock.Mock(spec=libvirt_guest.Guest)
|
||||
instance = self._create_instance()
|
||||
network_info = _fake_network_info(self, num_networks=3)
|
||||
vif = network_info[0]
|
||||
interface = vconfig.LibvirtConfigGuestInterface()
|
||||
image_meta = objects.ImageMeta.from_dict({})
|
||||
disk_info = blockinfo.get_disk_info(
|
||||
CONF.libvirt.virt_type, instance, image_meta)
|
||||
cfg = self.drvr._get_guest_config(
|
||||
instance, network_info, image_meta, disk_info)
|
||||
mock_wait_for_detach = mock.Mock()
|
||||
config_meta = vconfig.LibvirtConfigGuestMetaNovaInstance()
|
||||
|
||||
with test.nested(
|
||||
mock.patch.object(
|
||||
self.drvr._host, 'get_guest', return_value=guest),
|
||||
mock.patch.object(
|
||||
self.drvr.vif_driver, 'get_config', return_value=cfg),
|
||||
mock.patch.object(
|
||||
guest, 'get_interface_by_cfg', return_value=interface),
|
||||
mock.patch.object(guest, 'get_power_state'),
|
||||
mock.patch.object(
|
||||
instance, 'get_network_info', return_value=network_info),
|
||||
mock.patch.object(guest,
|
||||
'detach_device_with_retry', return_value=mock_wait_for_detach),
|
||||
mock.patch.object(
|
||||
self.drvr, '_get_guest_config_meta', return_value=config_meta),
|
||||
mock.patch.object(guest, 'set_metadata')
|
||||
) as (
|
||||
mock_get_guest, mock_get_config, mock_get_interface_by_cfg,
|
||||
mock_get_power_state, mock_get_network_info,
|
||||
mock_detach_device_with_retry, mock_get_guest_config_meta,
|
||||
mock_set_metadata
|
||||
):
|
||||
self.drvr.detach_interface(self.context, instance, vif)
|
||||
mock_get_guest.assert_called_once_with(instance)
|
||||
mock_get_config.assert_called_once_with(
|
||||
instance, vif, test.MatchType(objects.ImageMeta),
|
||||
test.MatchType(objects.Flavor), CONF.libvirt.virt_type)
|
||||
mock_get_interface_by_cfg.assert_called_once_with(cfg)
|
||||
mock_get_power_state.assert_called_once_with(self.drvr._host)
|
||||
mock_detach_device_with_retry.assert_called_once_with(
|
||||
guest.get_interface_by_cfg, cfg, live=False,
|
||||
alternative_device_name=None)
|
||||
mock_wait_for_detach.assert_called_once_with()
|
||||
mock_get_network_info.assert_called_once_with()
|
||||
mock_get_guest_config_meta.assert_called_once_with(
|
||||
instance, network_info[1:])
|
||||
mock_set_metadata.assert_called_once_with(config_meta)
|
||||
|
||||
@mock.patch('nova.objects.block_device.BlockDeviceMapping.save',
|
||||
new=mock.Mock())
|
||||
|
@ -713,6 +713,39 @@ class GuestTestCase(test.NoDBTestCase):
|
||||
self.guest.migrate_configure_max_downtime(1000)
|
||||
self.domain.migrateSetMaxDowntime.assert_called_once_with(1000)
|
||||
|
||||
def test_set_metadata(self):
|
||||
meta = mock.Mock(spec=vconfig.LibvirtConfigGuestMetaNovaInstance)
|
||||
meta.to_xml.return_value = "</xml>"
|
||||
self.guest.set_metadata(meta)
|
||||
self.domain.setMetadata.assert_called_once_with(
|
||||
fakelibvirt.VIR_DOMAIN_METADATA_ELEMENT, "</xml>", "instance",
|
||||
vconfig.NOVA_NS, flags=0)
|
||||
|
||||
def test_set_metadata_persistent(self):
|
||||
meta = mock.Mock(spec=vconfig.LibvirtConfigGuestMetaNovaInstance)
|
||||
meta.to_xml.return_value = "</xml>"
|
||||
self.guest.set_metadata(meta, persistent=True)
|
||||
self.domain.setMetadata.assert_called_once_with(
|
||||
fakelibvirt.VIR_DOMAIN_METADATA_ELEMENT, "</xml>", "instance",
|
||||
vconfig.NOVA_NS, flags=fakelibvirt.VIR_DOMAIN_AFFECT_CONFIG)
|
||||
|
||||
def test_set_metadata_device_live(self):
|
||||
meta = mock.Mock(spec=vconfig.LibvirtConfigGuestMetaNovaInstance)
|
||||
meta.to_xml.return_value = "</xml>"
|
||||
self.guest.set_metadata(meta, live=True)
|
||||
self.domain.setMetadata.assert_called_once_with(
|
||||
fakelibvirt.VIR_DOMAIN_METADATA_ELEMENT, "</xml>", "instance",
|
||||
vconfig.NOVA_NS, flags=fakelibvirt.VIR_DOMAIN_AFFECT_LIVE)
|
||||
|
||||
def test_set_metadata_persistent_live(self):
|
||||
meta = mock.Mock(spec=vconfig.LibvirtConfigGuestMetaNovaInstance)
|
||||
meta.to_xml.return_value = "</xml>"
|
||||
self.guest.set_metadata(meta, persistent=True, live=True)
|
||||
self.domain.setMetadata.assert_called_once_with(
|
||||
fakelibvirt.VIR_DOMAIN_METADATA_ELEMENT, "</xml>", "instance",
|
||||
vconfig.NOVA_NS, flags=fakelibvirt.VIR_DOMAIN_AFFECT_LIVE |
|
||||
fakelibvirt.VIR_DOMAIN_AFFECT_CONFIG)
|
||||
|
||||
|
||||
class GuestBlockTestCase(test.NoDBTestCase):
|
||||
|
||||
|
@ -37,7 +37,7 @@ from nova.virt import hardware
|
||||
|
||||
|
||||
# Namespace to use for Nova specific metadata items in XML
|
||||
NOVA_NS = "http://openstack.org/xmlns/libvirt/nova/1.0"
|
||||
NOVA_NS = "http://openstack.org/xmlns/libvirt/nova/1.1"
|
||||
|
||||
|
||||
class LibvirtConfigObject(object):
|
||||
@ -3221,6 +3221,7 @@ class LibvirtConfigGuestMetaNovaInstance(LibvirtConfigObject):
|
||||
self.owner = None
|
||||
self.roottype = None
|
||||
self.rootid = None
|
||||
self.ports = None
|
||||
|
||||
def format_dom(self):
|
||||
meta = super(LibvirtConfigGuestMetaNovaInstance, self).format_dom()
|
||||
@ -3244,6 +3245,8 @@ class LibvirtConfigGuestMetaNovaInstance(LibvirtConfigObject):
|
||||
root.set("type", self.roottype)
|
||||
root.set("uuid", str(self.rootid))
|
||||
meta.append(root)
|
||||
if self.ports is not None:
|
||||
meta.append(self.ports.format_dom())
|
||||
|
||||
return meta
|
||||
|
||||
@ -3397,3 +3400,53 @@ class LibvirtConfigGuestVPMEM(LibvirtConfigGuestDevice):
|
||||
for sub in list(c):
|
||||
if sub.tag == "size":
|
||||
self.target_size = sub.text
|
||||
|
||||
|
||||
class LibvirtConfigGuestMetaNovaPorts(LibvirtConfigObject):
|
||||
|
||||
def __init__(self, ports=None):
|
||||
super(LibvirtConfigGuestMetaNovaPorts, self).__init__(
|
||||
root_name="ports", ns_prefix="nova", ns_uri=NOVA_NS)
|
||||
|
||||
self.ports = ports
|
||||
|
||||
def format_dom(self):
|
||||
meta = self._new_node("ports")
|
||||
for port in self.ports or []:
|
||||
meta.append(port.format_dom())
|
||||
return meta
|
||||
|
||||
|
||||
class LibvirtConfigGuestMetaNovaPort(LibvirtConfigObject):
|
||||
|
||||
def __init__(self, uuid, ips=None):
|
||||
super(LibvirtConfigGuestMetaNovaPort, self).__init__(
|
||||
root_name="port", ns_prefix="nova", ns_uri=NOVA_NS)
|
||||
|
||||
self.uuid = uuid
|
||||
self.ips = ips
|
||||
|
||||
def format_dom(self):
|
||||
meta = self._new_node("port")
|
||||
meta.set("uuid", str(self.uuid))
|
||||
for ip in self.ips or []:
|
||||
meta.append(ip.format_dom())
|
||||
return meta
|
||||
|
||||
|
||||
class LibvirtConfigGuestMetaNovaIp(LibvirtConfigObject):
|
||||
|
||||
def __init__(self, ip_type, address, ip_version):
|
||||
super(LibvirtConfigGuestMetaNovaIp, self).__init__(
|
||||
root_name="ip", ns_prefix="nova", ns_uri=NOVA_NS)
|
||||
|
||||
self.ip_type = ip_type
|
||||
self.address = address
|
||||
self.ip_version = ip_version
|
||||
|
||||
def format_dom(self):
|
||||
meta = self._new_node("ip")
|
||||
meta.set("type", str(self.ip_type))
|
||||
meta.set("address", str(self.address))
|
||||
meta.set("ipVersion", str(self.ip_version))
|
||||
return meta
|
||||
|
@ -2203,6 +2203,12 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
self.detach_interface(context, instance, vif)
|
||||
raise exception.InterfaceAttachFailed(
|
||||
instance_uuid=instance.uuid)
|
||||
try:
|
||||
guest.set_metadata(
|
||||
self._get_guest_config_meta(
|
||||
instance, instance.get_network_info()))
|
||||
except libvirt.libvirtError:
|
||||
LOG.warning('updating libvirt metadata failed.', instance=instance)
|
||||
|
||||
def detach_interface(self, context, instance, vif):
|
||||
guest = self._host.get_guest(instance)
|
||||
@ -2296,6 +2302,17 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
# are failed to detach due to race conditions the unplug is
|
||||
# necessary for the same reason
|
||||
self.vif_driver.unplug(instance, vif)
|
||||
try:
|
||||
# NOTE(nmiki): In order for the interface to be removed from
|
||||
# network_info, the nova-compute process need to wait for
|
||||
# processing on the neutron side.
|
||||
# Here, I simply exclude the target VIF from metadata.
|
||||
network_info = list(filter(lambda info: info['id'] != vif['id'],
|
||||
instance.get_network_info()))
|
||||
guest.set_metadata(
|
||||
self._get_guest_config_meta(instance, network_info))
|
||||
except libvirt.libvirtError:
|
||||
LOG.warning('updating libvirt metadata failed.', instance=instance)
|
||||
|
||||
def _create_snapshot_metadata(self, image_meta, instance,
|
||||
img_fmt, snp_name):
|
||||
@ -4908,7 +4925,7 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
|
||||
return dev
|
||||
|
||||
def _get_guest_config_meta(self, instance):
|
||||
def _get_guest_config_meta(self, instance, network_info):
|
||||
"""Get metadata config for guest."""
|
||||
|
||||
meta = vconfig.LibvirtConfigGuestMetaNovaInstance()
|
||||
@ -4939,6 +4956,18 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
|
||||
meta.flavor = fmeta
|
||||
|
||||
ports = []
|
||||
for vif in network_info:
|
||||
ips = []
|
||||
for subnet in vif.get('network', {}).get('subnets', []):
|
||||
for ip in subnet.get('ips', []):
|
||||
ips.append(vconfig.LibvirtConfigGuestMetaNovaIp(
|
||||
ip.get('type'), ip.get('address'), ip.get('version')))
|
||||
ports.append(vconfig.LibvirtConfigGuestMetaNovaPort(
|
||||
vif.get('id'), ips=ips))
|
||||
|
||||
meta.ports = vconfig.LibvirtConfigGuestMetaNovaPorts(ports)
|
||||
|
||||
return meta
|
||||
|
||||
@staticmethod
|
||||
@ -6063,7 +6092,8 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
guest_numa_config.numatune,
|
||||
flavor, image_meta)
|
||||
|
||||
guest.metadata.append(self._get_guest_config_meta(instance))
|
||||
guest.metadata.append(self._get_guest_config_meta(
|
||||
instance, network_info))
|
||||
guest.idmaps = self._get_guest_idmaps()
|
||||
|
||||
for event in self._supported_perf_events:
|
||||
|
@ -303,6 +303,28 @@ class Guest(object):
|
||||
LOG.debug("attach device xml: %s", device_xml)
|
||||
self._domain.attachDeviceFlags(device_xml, flags=flags)
|
||||
|
||||
def set_metadata(self, metadata, persistent=False, live=False):
|
||||
"""Set metadata to the guest.
|
||||
|
||||
Please note that this function completely replaces the existing
|
||||
metadata. The scope of the replacement is limited to the Nova-specific
|
||||
XML Namespace.
|
||||
|
||||
:param metadata: A LibvirtConfigGuestMetaNovaInstance
|
||||
:param persistent: A bool to indicate whether the change is
|
||||
persistent or not
|
||||
:param live: A bool to indicate whether it affect the guest
|
||||
in running state
|
||||
"""
|
||||
flags = persistent and libvirt.VIR_DOMAIN_AFFECT_CONFIG or 0
|
||||
flags |= live and libvirt.VIR_DOMAIN_AFFECT_LIVE or 0
|
||||
|
||||
metadata_xml = metadata.to_xml()
|
||||
LOG.debug("set metadata xml: %s", metadata_xml)
|
||||
self._domain.setMetadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT,
|
||||
metadata_xml, "instance",
|
||||
vconfig.NOVA_NS, flags=flags)
|
||||
|
||||
def get_config(self):
|
||||
"""Returns the config instance for a guest
|
||||
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Added IP addresses to the metadata in libvirt XML. If an instance has more
|
||||
than one IP address, enumerate those IP addresses. The port attach or
|
||||
detach is performed dynamically after the creation of the instance. Every
|
||||
time there is a change, it is reflected in the contents of the XML.
|
Loading…
x
Reference in New Issue
Block a user