Publish image meta from notifications and pollsters (if available)
Currently, Ceilometer is only able to use the image_meta structure from notifications provided by Nova, since the relevant metadata is not written to the guests' libvirt XML files. A new patch is available that adds the same metadata that gets exposed in Nova notifications to libvirt XML metadata, so this change implements reading this metadata and adding it to the Ceilometer samples. Since image_meta is now available from the compute pollsters, meters.yaml has been also updated to also publish image_meta from compute notification meter samples. Processing for generating image_meta was also implemented when using Nova client to discover instances (instance_discovery_method is set to workload_partitioning), using the image metadata already fetched using a Glance API request. This seems to work okay, but has the disadvantages of a) only being available for ephemeral instances (booted from image), and b) possibly being out of date with what the instance is actually running, as the Glance image may have been updated after the instance was launched (the libvirt metadata contains what the instance was *actually* configured with). Signed-off-by: Callum Dickinson <callum.dickinson@catalystcloud.nz> Depends-On: https://review.opendev.org/c/openstack/nova/+/942766 Story: #2011371 Task: #51740 Change-Id: I7d8164f80322a9914b15d9a6991b2bc91b158ff3
This commit is contained in:
@@ -217,12 +217,45 @@ class InstanceDiscovery(plugin_base.DiscoveryBase):
|
||||
if extra_specs is not None:
|
||||
flavor["extra_specs"] = extra_specs
|
||||
|
||||
# The image description is partial, but Gnocchi only care about
|
||||
# the id, so we are fine
|
||||
image_xml = metadata_xml.find("./root[@type='image']")
|
||||
image = ({'id': image_xml.attrib['uuid']}
|
||||
if image_xml is not None else None)
|
||||
|
||||
image_meta_xml = metadata_xml.find("./image")
|
||||
if image_meta_xml is not None:
|
||||
# If the <image> element exists at all, Nova supports
|
||||
# image_meta in libvirt metadata. Add it to the instance
|
||||
# attributes even if all the required values are empty.
|
||||
image_meta = {}
|
||||
base_image_ref = image_meta_xml.attrib.get("uuid")
|
||||
if base_image_ref is not None:
|
||||
image_meta["base_image_ref"] = base_image_ref
|
||||
# The following properties get special treatment
|
||||
# because they are set as such in SM_INHERITABLE_KEYS,
|
||||
# as defined in nova/utils.py.
|
||||
container_format_xml = image_meta_xml.find(
|
||||
"./containerFormat")
|
||||
if container_format_xml is not None:
|
||||
image_meta["container_format"] = (
|
||||
container_format_xml.text)
|
||||
disk_format_xml = image_meta_xml.find("./diskFormat")
|
||||
if disk_format_xml is not None:
|
||||
image_meta["disk_format"] = disk_format_xml.text
|
||||
min_disk_xml = image_meta_xml.find("./minDisk")
|
||||
if min_disk_xml is not None:
|
||||
image_meta["min_disk"] = min_disk_xml.text
|
||||
min_ram_xml = image_meta_xml.find("./minRam")
|
||||
if min_ram_xml is not None:
|
||||
image_meta["min_ram"] = min_ram_xml.text
|
||||
# Get additional properties defined in image_meta.
|
||||
properties_xml = image_meta_xml.find("./properties")
|
||||
if properties_xml is not None:
|
||||
for prop in properties_xml.findall("./property"):
|
||||
image_meta[prop.attrib["name"]] = prop.text
|
||||
else:
|
||||
# None for "no image_meta found".
|
||||
image_meta = None
|
||||
|
||||
# Getting the server metadata requires expensive Nova API
|
||||
# queries, and may potentially contain sensitive user info,
|
||||
# so it is only fetched when configured to do so.
|
||||
@@ -276,6 +309,8 @@ class InstanceDiscovery(plugin_base.DiscoveryBase):
|
||||
# 'ramdisk_id',
|
||||
# some image detail
|
||||
}
|
||||
if image_meta is not None:
|
||||
instance_data["image_meta"] = image_meta
|
||||
|
||||
LOG.debug("instance data: %s", instance_data)
|
||||
instances.append(NovaLikeServer(**instance_data))
|
||||
|
@@ -59,6 +59,8 @@ def _get_metadata_from_object(conf, instance):
|
||||
metadata['image'] = None
|
||||
metadata['image_ref'] = None
|
||||
metadata['image_ref_url'] = None
|
||||
if hasattr(instance, 'image_meta') and instance.image_meta:
|
||||
metadata['image_meta'] = instance.image_meta
|
||||
|
||||
for name in INSTANCE_PROPERTIES:
|
||||
if hasattr(instance, name):
|
||||
|
@@ -201,6 +201,7 @@ metric:
|
||||
flavor_name: $.payload.instance_type
|
||||
display_name: $.payload.display_name
|
||||
image_ref: $.payload.image_meta.base_image_ref
|
||||
image_meta: $.payload.image_meta
|
||||
launched_at: $.payload.launched_at
|
||||
created_at: $.payload.created_at
|
||||
deleted_at: $.payload.deleted_at
|
||||
|
@@ -128,6 +128,17 @@ class Client:
|
||||
ameta = image_metadata.get(attr) if image_metadata else default
|
||||
setattr(instance, attr, ameta)
|
||||
|
||||
if image:
|
||||
image_meta = {"base_image_ref": iid}
|
||||
# Notifications and libvirt XML metadata return all
|
||||
# image_meta values as strings. Do the same here.
|
||||
image_meta.update((k, str(v))
|
||||
for k, v in image.items()
|
||||
if k not in ('id', 'name', 'metadata'))
|
||||
else:
|
||||
image_meta = {}
|
||||
instance.image_meta = image_meta
|
||||
|
||||
@logged
|
||||
def instance_get_all_by_host(self, hostname, since=None):
|
||||
"""Returns list of instances on particular host.
|
||||
|
@@ -49,6 +49,15 @@ class TestPollsterBase(base.BaseTestCase):
|
||||
'fqdn': 'vm_fqdn',
|
||||
'metering.stack': '2cadc4b4-8789-123c-b4eg-edd2f0a9c128',
|
||||
'project_cos': 'dev'}
|
||||
self.instance.image = {'id': '0ff4d118-4947-49e6-963a-7a28e65f3f11'}
|
||||
self.instance.image_meta = {
|
||||
'base_image_ref': self.instance.image['id'],
|
||||
'container_format': 'bare',
|
||||
'disk_format': 'raw',
|
||||
'min_disk': '1',
|
||||
'min_ram': '0',
|
||||
'os_distro': 'ubuntu',
|
||||
'os_type': 'linux'}
|
||||
|
||||
self.useFixture(fixtures.MockPatch(
|
||||
'ceilometer.compute.virt.inspector.get_hypervisor_inspector',
|
||||
|
@@ -67,6 +67,10 @@ class TestCPUPollster(base.TestPollsterBase):
|
||||
self.assertIsNone(samples[0].resource_metadata['task_state'])
|
||||
self.assertEqual(self.instance.flavor,
|
||||
samples[0].resource_metadata['flavor'])
|
||||
self.assertEqual(self.instance.image['id'],
|
||||
samples[0].resource_metadata['image_ref'])
|
||||
self.assertEqual(self.instance.image_meta,
|
||||
samples[0].resource_metadata['image_meta'])
|
||||
|
||||
def test_get_reserved_metadata_with_keys(self):
|
||||
self.CONF.set_override('reserved_metadata_keys', ['fqdn'])
|
||||
|
@@ -66,6 +66,13 @@ class TestLocationMetadata(base.BaseTestCase):
|
||||
'image': {'id': 1,
|
||||
'links': [{"rel": "bookmark",
|
||||
'href': 2}]},
|
||||
'image_meta': {'base_image_ref': 1,
|
||||
'container_format': 'bare',
|
||||
'disk_format': 'raw',
|
||||
'min_disk': '20',
|
||||
'min_ram': '0',
|
||||
'os_distro': 'ubuntu',
|
||||
'os_type': 'linux'},
|
||||
'hostId': '1234-5678',
|
||||
'OS-EXT-SRV-ATTR:host': 'host-test',
|
||||
'flavor': {'name': 'm1.tiny',
|
||||
@@ -105,6 +112,10 @@ class TestLocationMetadata(base.BaseTestCase):
|
||||
'metadata']['metering.autoscale.group'][:256]
|
||||
self.assertEqual(expected, user_metadata['autoscale_group'])
|
||||
self.assertEqual(1, len(user_metadata))
|
||||
self.assertEqual(self.INSTANCE_PROPERTIES['image']['id'],
|
||||
md['image_ref'])
|
||||
self.assertEqual(self.INSTANCE_PROPERTIES['image_meta'],
|
||||
md['image_meta'])
|
||||
|
||||
def test_metadata_empty_image(self):
|
||||
self.INSTANCE_PROPERTIES['image'] = None
|
||||
@@ -121,3 +132,29 @@ class TestLocationMetadata(base.BaseTestCase):
|
||||
md = util._get_metadata_from_object(self.CONF, self.instance)
|
||||
self.assertEqual(1, md['image_ref'])
|
||||
self.assertIsNone(md['image_ref_url'])
|
||||
|
||||
def test_metadata_image_meta_volume_image(self):
|
||||
self.INSTANCE_PROPERTIES['image_meta']['base_image_ref'] = ''
|
||||
self.instance = FauxInstance(**self.INSTANCE_PROPERTIES)
|
||||
md = util._get_metadata_from_object(self.CONF, self.instance)
|
||||
self.assertEqual(self.INSTANCE_PROPERTIES['image_meta'],
|
||||
md['image_meta'])
|
||||
|
||||
def test_metadata_image_meta_volume_no_image(self):
|
||||
self.INSTANCE_PROPERTIES['image_meta'] = {'base_image_ref': ''}
|
||||
self.instance = FauxInstance(**self.INSTANCE_PROPERTIES)
|
||||
md = util._get_metadata_from_object(self.CONF, self.instance)
|
||||
self.assertEqual(self.INSTANCE_PROPERTIES['image_meta'],
|
||||
md['image_meta'])
|
||||
|
||||
def test_metadata_image_meta_none(self):
|
||||
self.INSTANCE_PROPERTIES['image_meta'] = None
|
||||
self.instance = FauxInstance(**self.INSTANCE_PROPERTIES)
|
||||
md = util._get_metadata_from_object(self.CONF, self.instance)
|
||||
self.assertNotIn('image_meta', md)
|
||||
|
||||
def test_metadata_image_meta_noexist(self):
|
||||
del self.INSTANCE_PROPERTIES['image_meta']
|
||||
self.instance = FauxInstance(**self.INSTANCE_PROPERTIES)
|
||||
md = util._get_metadata_from_object(self.CONF, self.instance)
|
||||
self.assertNotIn('image_meta', md)
|
||||
|
@@ -40,6 +40,16 @@ LIBVIRT_METADATA_XML = """
|
||||
<extraSpec name="hw_rng:allowed">true</extraSpec>
|
||||
</extraSpecs>
|
||||
</flavor>
|
||||
<image uuid="bdaf114a-35e9-4163-accd-226d5944bf11">
|
||||
<containerFormat>bare</containerFormat>
|
||||
<diskFormat>raw</diskFormat>
|
||||
<minDisk>1</minDisk>
|
||||
<minRam>0</minRam>
|
||||
<properties>
|
||||
<property name="os_distro">ubuntu</property>
|
||||
<property name="os_type">linux</property>
|
||||
</properties>
|
||||
</image>
|
||||
<owner>
|
||||
<user uuid="a1f4684e58bd4c88aefd2ecb0783b497">admin</user>
|
||||
<project uuid="d99c829753f64057bc0f2030da309943">admin</project>
|
||||
@@ -155,6 +165,63 @@ LIBVIRT_METADATA_XML_NO_FLAVOR_EXTRA_SPECS = """
|
||||
</instance>
|
||||
"""
|
||||
|
||||
LIBVIRT_METADATA_XML_FROM_VOLUME_IMAGE = """
|
||||
<instance>
|
||||
<package version="14.0.0"/>
|
||||
<name>test.dom.com</name>
|
||||
<creationTime>2016-11-16 07:35:06</creationTime>
|
||||
<flavor name="m1.tiny" id="eba4213d-3c6c-4b5f-8158-dd0022d71d62">
|
||||
<memory>512</memory>
|
||||
<disk>1</disk>
|
||||
<swap>0</swap>
|
||||
<ephemeral>0</ephemeral>
|
||||
<vcpus>1</vcpus>
|
||||
<extraSpecs>
|
||||
<extraSpec name="hw_rng:allowed">true</extraSpec>
|
||||
</extraSpecs>
|
||||
</flavor>
|
||||
<image uuid="">
|
||||
<containerFormat>bare</containerFormat>
|
||||
<diskFormat>raw</diskFormat>
|
||||
<minDisk>1</minDisk>
|
||||
<minRam>0</minRam>
|
||||
<properties>
|
||||
<property name="os_distro">ubuntu</property>
|
||||
<property name="os_type">linux</property>
|
||||
</properties>
|
||||
</image>
|
||||
<owner>
|
||||
<user uuid="a1f4684e58bd4c88aefd2ecb0783b497">admin</user>
|
||||
<project uuid="d99c829753f64057bc0f2030da309943">admin</project>
|
||||
</owner>
|
||||
</instance>
|
||||
"""
|
||||
|
||||
LIBVIRT_METADATA_XML_FROM_VOLUME_NO_IMAGE = """
|
||||
<instance>
|
||||
<package version="14.0.0"/>
|
||||
<name>test.dom.com</name>
|
||||
<creationTime>2016-11-16 07:35:06</creationTime>
|
||||
<flavor name="m1.tiny" id="eba4213d-3c6c-4b5f-8158-dd0022d71d62">
|
||||
<memory>512</memory>
|
||||
<disk>1</disk>
|
||||
<swap>0</swap>
|
||||
<ephemeral>0</ephemeral>
|
||||
<vcpus>1</vcpus>
|
||||
<extraSpecs>
|
||||
<extraSpec name="hw_rng:allowed">true</extraSpec>
|
||||
</extraSpecs>
|
||||
</flavor>
|
||||
<image uuid="">
|
||||
<properties></properties>
|
||||
</image>
|
||||
<owner>
|
||||
<user uuid="a1f4684e58bd4c88aefd2ecb0783b497">admin</user>
|
||||
<project uuid="d99c829753f64057bc0f2030da309943">admin</project>
|
||||
</owner>
|
||||
</instance>
|
||||
"""
|
||||
|
||||
LIBVIRT_DESC_XML = """
|
||||
<domain type='kvm' id='1'>
|
||||
<name>instance-00000001</name>
|
||||
@@ -407,6 +474,33 @@ class TestDiscovery(base.BaseTestCase):
|
||||
self.assertEqual("x86_64", metadata["architecture"])
|
||||
self.assertEqual({"server_group": "group1"},
|
||||
metadata["user_metadata"])
|
||||
self.assertEqual({"id"},
|
||||
set(metadata["image"].keys()))
|
||||
self.assertEqual("bdaf114a-35e9-4163-accd-226d5944bf11",
|
||||
metadata["image"]["id"])
|
||||
self.assertIn("image_meta", metadata)
|
||||
self.assertEqual({"base_image_ref",
|
||||
"container_format",
|
||||
"disk_format",
|
||||
"min_disk",
|
||||
"min_ram",
|
||||
"os_distro",
|
||||
"os_type"},
|
||||
set(metadata["image_meta"].keys()))
|
||||
self.assertEqual("bdaf114a-35e9-4163-accd-226d5944bf11",
|
||||
metadata["image_meta"]["base_image_ref"])
|
||||
self.assertEqual("bare",
|
||||
metadata["image_meta"]["container_format"])
|
||||
self.assertEqual("raw",
|
||||
metadata["image_meta"]["disk_format"])
|
||||
self.assertEqual("1",
|
||||
metadata["image_meta"]["min_disk"])
|
||||
self.assertEqual("0",
|
||||
metadata["image_meta"]["min_ram"])
|
||||
self.assertEqual("ubuntu",
|
||||
metadata["image_meta"]["os_distro"])
|
||||
self.assertEqual("linux",
|
||||
metadata["image_meta"]["os_type"])
|
||||
|
||||
@mock.patch.object(discovery.InstanceDiscovery, "get_server")
|
||||
@mock.patch.object(discovery.InstanceDiscovery, "get_flavor_id")
|
||||
@@ -472,6 +566,11 @@ class TestDiscovery(base.BaseTestCase):
|
||||
self.assertEqual("x86_64", metadata["architecture"])
|
||||
self.assertEqual({"server_group": "group1"},
|
||||
metadata["user_metadata"])
|
||||
self.assertEqual({"id"},
|
||||
set(metadata["image"].keys()))
|
||||
self.assertEqual("bdaf114a-35e9-4163-accd-226d5944bf11",
|
||||
metadata["image"]["id"])
|
||||
self.assertNotIn("image_meta", metadata)
|
||||
|
||||
@mock.patch.object(discovery.InstanceDiscovery, "get_server")
|
||||
@mock.patch.object(discovery.InstanceDiscovery, "get_flavor_id")
|
||||
@@ -730,6 +829,85 @@ class TestDiscovery(base.BaseTestCase):
|
||||
"vcpus": 1},
|
||||
metadata["flavor"])
|
||||
|
||||
@mock.patch("ceilometer.compute.virt.libvirt.utils."
|
||||
"refresh_libvirt_connection")
|
||||
def test_discovery_with_libvirt_from_volume_image(
|
||||
self, mock_libvirt_conn):
|
||||
self.CONF.set_override("instance_discovery_method",
|
||||
"libvirt_metadata",
|
||||
group="compute")
|
||||
self.CONF.set_override("fetch_extra_metadata", False, group="compute")
|
||||
mock_libvirt_conn.return_value = FakeConn(
|
||||
domains=[
|
||||
FakeDomain(metadata=LIBVIRT_METADATA_XML_FROM_VOLUME_IMAGE)])
|
||||
dsc = discovery.InstanceDiscovery(self.CONF)
|
||||
resources = dsc.discover(mock.MagicMock())
|
||||
|
||||
self.assertEqual(1, len(resources))
|
||||
r = list(resources)[0]
|
||||
s = util.make_sample_from_instance(self.CONF, r, "metric", "delta",
|
||||
"carrot", 1)
|
||||
self.assertEqual("a75c2fa5-6c03-45a8-bbf7-b993cfcdec27",
|
||||
s.resource_id)
|
||||
self.assertEqual("d99c829753f64057bc0f2030da309943",
|
||||
s.project_id)
|
||||
self.assertEqual("a1f4684e58bd4c88aefd2ecb0783b497",
|
||||
s.user_id)
|
||||
|
||||
metadata = s.resource_metadata
|
||||
self.assertIsNone(metadata["image"])
|
||||
self.assertIn("image_meta", metadata)
|
||||
self.assertEqual({"base_image_ref",
|
||||
"container_format",
|
||||
"disk_format",
|
||||
"min_disk",
|
||||
"min_ram",
|
||||
"os_distro",
|
||||
"os_type"},
|
||||
set(metadata["image_meta"].keys()))
|
||||
self.assertEqual("",
|
||||
metadata["image_meta"]["base_image_ref"])
|
||||
self.assertEqual("bare",
|
||||
metadata["image_meta"]["container_format"])
|
||||
self.assertEqual("raw",
|
||||
metadata["image_meta"]["disk_format"])
|
||||
self.assertEqual("1",
|
||||
metadata["image_meta"]["min_disk"])
|
||||
self.assertEqual("0",
|
||||
metadata["image_meta"]["min_ram"])
|
||||
self.assertEqual("ubuntu",
|
||||
metadata["image_meta"]["os_distro"])
|
||||
self.assertEqual("linux",
|
||||
metadata["image_meta"]["os_type"])
|
||||
|
||||
@mock.patch("ceilometer.compute.virt.libvirt.utils."
|
||||
"refresh_libvirt_connection")
|
||||
def test_discovery_with_libvirt_from_volume_no_image(
|
||||
self, mock_libvirt_conn):
|
||||
self.CONF.set_override("instance_discovery_method",
|
||||
"libvirt_metadata",
|
||||
group="compute")
|
||||
self.CONF.set_override("fetch_extra_metadata", False, group="compute")
|
||||
mock_libvirt_conn.return_value = FakeConn(
|
||||
domains=[
|
||||
FakeDomain(
|
||||
metadata=LIBVIRT_METADATA_XML_FROM_VOLUME_NO_IMAGE)])
|
||||
dsc = discovery.InstanceDiscovery(self.CONF)
|
||||
resources = dsc.discover(mock.MagicMock())
|
||||
|
||||
self.assertEqual(1, len(resources))
|
||||
r = list(resources)[0]
|
||||
s = util.make_sample_from_instance(self.CONF, r, "metric", "delta",
|
||||
"carrot", 1)
|
||||
|
||||
metadata = s.resource_metadata
|
||||
self.assertIsNone(metadata["image"])
|
||||
self.assertIn("image_meta", metadata)
|
||||
self.assertEqual({"base_image_ref"},
|
||||
set(metadata["image_meta"].keys()))
|
||||
self.assertEqual("",
|
||||
metadata["image_meta"]["base_image_ref"])
|
||||
|
||||
def test_discovery_with_legacy_resource_cache_cleanup(self):
|
||||
self.CONF.set_override("instance_discovery_method", "naive",
|
||||
group="compute")
|
||||
|
@@ -22,6 +22,12 @@ from ceilometer import nova_client
|
||||
from ceilometer import service
|
||||
|
||||
|
||||
class FauxImage(dict):
|
||||
|
||||
def __getattr__(self, key):
|
||||
return self[key]
|
||||
|
||||
|
||||
class TestNovaClient(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
@@ -51,25 +57,34 @@ class TestNovaClient(base.BaseTestCase):
|
||||
|
||||
def fake_images_get(self, *args, **kwargs):
|
||||
self._images_count += 1
|
||||
a = mock.MagicMock()
|
||||
a.id = args[0]
|
||||
image_id = args[0]
|
||||
image_details = {
|
||||
1: ('ubuntu-12.04-x86', dict(kernel_id=11, ramdisk_id=21)),
|
||||
2: ('centos-5.4-x64', dict(kernel_id=12, ramdisk_id=22)),
|
||||
3: ('rhel-6-x64', None),
|
||||
4: ('rhel-6-x64', dict()),
|
||||
5: ('rhel-6-x64', dict(kernel_id=11)),
|
||||
6: ('rhel-6-x64', dict(ramdisk_id=21))
|
||||
# NOTE(callumdickinson): Real image IDs are UUIDs, not integers,
|
||||
# so the actual code runs assuming the IDs are strings.
|
||||
1: ('ubuntu-12.04-x86',
|
||||
dict(kernel_id=11, ramdisk_id=21),
|
||||
dict(container_format='bare',
|
||||
disk_format='raw',
|
||||
min_disk=1,
|
||||
min_ram=0,
|
||||
os_distro='ubuntu',
|
||||
os_type='linux')),
|
||||
2: ('centos-5.4-x64', dict(kernel_id=12, ramdisk_id=22), dict()),
|
||||
3: ('rhel-6-x64', None, dict()),
|
||||
4: ('rhel-6-x64', dict(), dict()),
|
||||
5: ('rhel-6-x64', dict(kernel_id=11), dict()),
|
||||
6: ('rhel-6-x64', dict(ramdisk_id=21), dict()),
|
||||
}
|
||||
|
||||
if a.id in image_details:
|
||||
a.name = image_details[a.id][0]
|
||||
a.metadata = image_details[a.id][1]
|
||||
if image_id in image_details:
|
||||
return FauxImage(
|
||||
id=image_id,
|
||||
name=image_details[image_id][0],
|
||||
metadata=image_details[image_id][1],
|
||||
**image_details[image_id][2])
|
||||
else:
|
||||
raise glanceclient.exc.HTTPNotFound('foobar')
|
||||
|
||||
return a
|
||||
|
||||
@staticmethod
|
||||
def fake_servers_list(*args, **kwargs):
|
||||
a = mock.MagicMock()
|
||||
@@ -151,6 +166,14 @@ class TestNovaClient(base.BaseTestCase):
|
||||
self.assertEqual('m1.tiny', instance.flavor['name'])
|
||||
self.assertEqual(11, instance.kernel_id)
|
||||
self.assertEqual(21, instance.ramdisk_id)
|
||||
self.assertEqual({'base_image_ref': 1,
|
||||
'container_format': 'bare',
|
||||
'disk_format': 'raw',
|
||||
'min_disk': '1',
|
||||
'min_ram': '0',
|
||||
'os_distro': 'ubuntu',
|
||||
'os_type': 'linux'},
|
||||
instance.image_meta)
|
||||
|
||||
def test_with_flavor_and_image_unknown_image(self):
|
||||
instances = self.fake_servers_list_unknown_image()
|
||||
@@ -160,6 +183,7 @@ class TestNovaClient(base.BaseTestCase):
|
||||
self.assertNotEqual(instance.flavor['name'], 'unknown-id-666')
|
||||
self.assertIsNone(instance.kernel_id)
|
||||
self.assertIsNone(instance.ramdisk_id)
|
||||
self.assertEqual({}, instance.image_meta)
|
||||
|
||||
def test_with_flavor_and_image_unknown_flavor(self):
|
||||
instances = self.fake_servers_list_unknown_flavor()
|
||||
@@ -172,6 +196,14 @@ class TestNovaClient(base.BaseTestCase):
|
||||
self.assertNotEqual(instance.image['name'], 'unknown-id-666')
|
||||
self.assertEqual(11, instance.kernel_id)
|
||||
self.assertEqual(21, instance.ramdisk_id)
|
||||
self.assertEqual({'base_image_ref': 1,
|
||||
'container_format': 'bare',
|
||||
'disk_format': 'raw',
|
||||
'min_disk': '1',
|
||||
'min_ram': '0',
|
||||
'os_distro': 'ubuntu',
|
||||
'os_type': 'linux'},
|
||||
instance.image_meta)
|
||||
|
||||
def test_with_flavor_and_image_none_metadata(self):
|
||||
instances = self.fake_servers_list_image_missing_metadata(3)
|
||||
|
@@ -0,0 +1,23 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
The ``image_meta`` metadata structure for compute meters was
|
||||
formerly only available via the notification meters. When using
|
||||
Nova 2025.2 Flamingo or later, ``image_meta`` is now also supplied by
|
||||
the compute pollsters. This is now possible due to the addition of
|
||||
the relevant metadata to the libvirt guest XML.
|
||||
- |
|
||||
The built-in ``meters.yaml`` has been updated to publish the
|
||||
``image_meta`` metadata attribute for compute notification meter
|
||||
samples by default.
|
||||
upgrade:
|
||||
- |
|
||||
``meters.yaml`` has been updated to add ``image_meta`` to compute meter
|
||||
samples by default.
|
||||
- |
|
||||
In order for the new image metadata attributes to start being populated
|
||||
from libvirt metadata in pollster samples, Nova must be upgraded to
|
||||
2025.2 Flamingo or later (older versions are still backwards compatible,
|
||||
but the new attributes will not be available via pollster samples).
|
||||
Existing instances will need to be shelved-and-unshelved or cold migrated
|
||||
for the metadata to be populated.
|
Reference in New Issue
Block a user