libvirt: add IP address to libvirt guest metadata
Libvirt XML contains useful configuration information such as instance names, flavors and images as metadata. This change extends this metadata to include the IP addresses of the instances. Example: <metadata> <nova:instance xmlns:nova="http://openstack.org/xmlns/libvirt/nova/1.1"> ... <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:ports> ... </nova:instance> </metadata> Change-Id: I45f1df4935905170957c2ea2496c8a698a7464a2 blueprint: libvirt-driver-ip-metadata Signed-off-by: Nobuhiro MIKI <nmiki@yahoo-corp.jp>
This commit is contained in:
parent
67c76de5f4
commit
838370a490
@ -183,6 +183,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)
|
||||
@ -1380,6 +1385,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):
|
||||
|
@ -3646,9 +3646,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>
|
||||
@ -3666,6 +3687,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):
|
||||
@ -2701,6 +2704,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
|
||||
@ -19036,6 +19077,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,
|
||||
@ -19050,6 +19093,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:
|
||||
@ -23504,6 +23548,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')
|
||||
@ -23511,7 +23586,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="""
|
||||
@ -23551,6 +23627,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)
|
||||
|
||||
@ -23617,11 +23694,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])
|
||||
@ -23641,6 +23719,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])
|
||||
|
||||
@ -23763,7 +23842,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)
|
||||
@ -23775,6 +23855,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):
|
||||
@ -3229,6 +3229,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()
|
||||
@ -3252,6 +3253,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
|
||||
|
||||
@ -3405,3 +3408,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
|
||||
|
@ -2226,6 +2226,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)
|
||||
@ -2319,6 +2325,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):
|
||||
@ -4941,7 +4958,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()
|
||||
@ -4972,6 +4989,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
|
||||
@ -6094,7 +6123,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…
Reference in New Issue
Block a user