Merge "Add the disk.ephemeral.size and disk.root.size pollsters"

This commit is contained in:
Zuul 2025-02-26 07:27:21 +00:00 committed by Gerrit Code Review
commit 774137434c
6 changed files with 202 additions and 2 deletions

View File

@ -170,3 +170,44 @@ class GenericComputePollster(plugin_base.PollsterBase):
'Could not get %(name)s events for %(id)s: %(e)s', {
'name': self.sample_name, 'id': instance.id, 'e': err},
exc_info=True)
class InstanceMetadataPollster(plugin_base.PollsterBase):
"""A base class for implementing a pollster using instance metadata.
This metadata is originally supplied by Nova, but if
instance_discovery_method is set to libvirt_metadata,
metadata is fetched from the local libvirt socket,
just like with the standard compute pollsters.
"""
sample_name = None
sample_unit = ''
sample_type = sample.TYPE_GAUGE
@property
def default_discovery(self):
return 'local_instances'
def get_resource_id(self, instance):
return instance.id
def get_volume(self, instance):
raise ceilometer.NotImplementedError
def get_additional_metadata(self, instance):
return {}
def get_samples(self, manager, cache, resources):
for instance in resources:
yield util.make_sample_from_instance(
self.conf,
instance,
name=self.sample_name,
unit=self.sample_unit,
type=self.sample_type,
resource_id=self.get_resource_id(instance),
volume=self.get_volume(instance),
additional_metadata=self.get_additional_metadata(instance),
monotonic_time=now(),
)

View File

@ -91,3 +91,20 @@ class PerDeviceDiskWriteLatencyPollster(PerDeviceDiskPollster):
sample_type = sample.TYPE_CUMULATIVE
sample_unit = 'ns'
sample_stats_key = 'wr_total_times'
class EphemeralSizePollster(pollsters.InstanceMetadataPollster):
sample_name = 'disk.ephemeral.size'
sample_unit = 'GB'
def get_volume(self, instance):
return int(instance.flavor['ephemeral'])
class RootSizePollster(pollsters.InstanceMetadataPollster):
sample_name = 'disk.root.size'
sample_unit = 'GB'
def get_volume(self, instance):
return (int(instance.flavor['disk'])
- int(instance.flavor['ephemeral']))

View File

@ -0,0 +1,130 @@
# Copyright 2025 Catalyst Cloud Limited
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from unittest import mock
from ceilometer.compute.pollsters import disk
from ceilometer.polling import manager
from ceilometer.tests.unit.compute.pollsters import base
class TestDiskPollsterBase(base.TestPollsterBase):
TYPE = 'gauge'
def setUp(self):
super().setUp()
self.instances = self._get_fake_instances()
def _get_fake_instances(self, ephemeral=0):
instances = []
for i in [1, 2]:
instance = mock.MagicMock()
instance.name = f'instance-{i}'
setattr(instance, 'OS-EXT-SRV-ATTR:instance_name',
instance.name)
instance.id = i
instance.flavor = {'name': 'm1.small', 'id': 2, 'vcpus': 1,
'ram': 512, 'disk': 20, 'ephemeral': ephemeral}
instance.status = 'active'
instances.append(instance)
return instances
def _check_get_samples(self,
factory,
name,
instances=None,
expected_count=2):
pollster = factory(self.CONF)
mgr = manager.AgentManager(0, self.CONF)
samples = list(pollster.get_samples(mgr,
{},
instances or self.instances))
self.assertGreater(len(samples), 0)
self.assertEqual({name}, set(s.name for s in samples),
(f"Only samples for meter {name} "
"should be published"))
self.assertEqual(expected_count, len(samples))
return samples
class TestDiskSizePollsters(TestDiskPollsterBase):
TYPE = 'gauge'
def test_ephemeral_disk_zero(self):
samples = {
sample.resource_id: sample
for sample in self._check_get_samples(
disk.EphemeralSizePollster,
'disk.ephemeral.size',
expected_count=len(self.instances))}
for instance in self.instances:
with self.subTest(instance.name):
self.assertIn(instance.id, samples)
sample = samples[instance.id]
self.assertEqual(instance.flavor['ephemeral'],
sample.volume)
self.assertEqual(self.TYPE, sample.type)
def test_ephemeral_disk_nonzero(self):
instances = self._get_fake_instances(ephemeral=10)
samples = {
sample.resource_id: sample
for sample in self._check_get_samples(
disk.EphemeralSizePollster,
'disk.ephemeral.size',
instances=instances,
expected_count=len(instances))}
for instance in instances:
with self.subTest(instance.name):
self.assertIn(instance.id, samples)
sample = samples[instance.id]
self.assertEqual(instance.flavor['ephemeral'],
sample.volume)
self.assertEqual(self.TYPE, sample.type)
def test_root_disk(self):
samples = {
sample.resource_id: sample
for sample in self._check_get_samples(
disk.RootSizePollster,
'disk.root.size',
expected_count=len(self.instances))}
for instance in self.instances:
with self.subTest(instance.name):
self.assertIn(instance.id, samples)
sample = samples[instance.id]
self.assertEqual((instance.flavor['disk']
- instance.flavor['ephemeral']),
sample.volume)
self.assertEqual(self.TYPE, sample.type)
def test_root_disk_ephemeral_nonzero(self):
instances = self._get_fake_instances(ephemeral=10)
samples = {
sample.resource_id: sample
for sample in self._check_get_samples(
disk.RootSizePollster,
'disk.root.size',
instances=instances,
expected_count=len(instances))}
for instance in instances:
with self.subTest(instance.name):
self.assertIn(instance.id, samples)
sample = samples[instance.id]
self.assertEqual((instance.flavor['disk']
- instance.flavor['ephemeral']),
sample.volume)
self.assertEqual(self.TYPE, sample.type)

View File

@ -124,10 +124,12 @@ The following meters are collected for OpenStack Compute.
| .bytes | | | | | | |
+-----------+-------+------+----------+----------+---------+------------------+
| disk.root\| Gauge | GB | instance | Notific\ | Libvirt | Size of root disk|
| .size | | | ID | ation | | |
| .size | | | ID | ation, \ | | |
| | | | | Pollster | | |
+-----------+-------+------+----------+----------+---------+------------------+
| disk.ephe\| Gauge | GB | instance | Notific\ | Libvirt | Size of ephemeral|
| meral.size| | | ID | ation | | disk |
| meral.size| | | ID | ation, \ | | disk |
| | | | | Pollster | | |
+-----------+-------+------+----------+----------+---------+------------------+
| disk.dev\ | Gauge | B | disk ID | Pollster | Libvirt | The amount of d\ |
| ice.capa\ | | | | | | isk per device |

View File

@ -0,0 +1,8 @@
---
features:
- |
The ``disk.ephemeral.size`` meter is now published as a compute pollster,
in addition to the existing notification meter.
- |
The ``disk.root.size`` meter is now published as a compute pollster,
in addition to the existing notification meter.

View File

@ -94,6 +94,8 @@ ceilometer.poll.compute =
disk.device.capacity = ceilometer.compute.pollsters.disk:PerDeviceCapacityPollster
disk.device.allocation = ceilometer.compute.pollsters.disk:PerDeviceAllocationPollster
disk.device.usage = ceilometer.compute.pollsters.disk:PerDevicePhysicalPollster
disk.ephemeral.size = ceilometer.compute.pollsters.disk:EphemeralSizePollster
disk.root.size = ceilometer.compute.pollsters.disk:RootSizePollster
perf.cpu.cycles = ceilometer.compute.pollsters.instance_stats:PerfCPUCyclesPollster
perf.instructions = ceilometer.compute.pollsters.instance_stats:PerfInstructionsPollster
perf.cache.references = ceilometer.compute.pollsters.instance_stats:PerfCacheReferencesPollster