Poll for evaluation metrics from aodh

Change-Id: I584c3859d8c214100c7077dc6fec665a0e93b898
This commit is contained in:
Jaromir Wysoglad
2025-01-21 15:12:04 -05:00
parent 732143a904
commit cd0db8b766
11 changed files with 191 additions and 1 deletions

View File

57
ceilometer/alarm/aodh.py Normal file
View File

@@ -0,0 +1,57 @@
#
# Copyright 2025 Red Hat, Inc
#
# 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.
"""Common code for working with alarm metrics
"""
from ceilometer.polling import plugin_base
from ceilometer import sample
DEFAULT_GROUP = "service_credentials"
class _Base(plugin_base.PollsterBase):
@property
def default_discovery(self):
return 'alarm'
class EvaluationResultPollster(_Base):
@staticmethod
def get_evaluation_results_metrics(metrics):
evaluation_metrics = []
if "evaluation_results" in metrics:
for metric in metrics["evaluation_results"]:
for state, count in metric["state_counters"].items():
evaluation_metrics.append({
"name": "evaluation_result",
"state": state,
"count": count,
"project_id": metric['project_id'],
"alarm_id": metric['alarm_id']
})
return evaluation_metrics
def get_samples(self, manager, cache, resources):
metrics = self.get_evaluation_results_metrics(resources[0])
for metric in metrics:
yield sample.Sample(
name='alarm.' + metric['name'],
type=sample.TYPE_GAUGE,
volume=int(metric['count']),
unit='evaluation_result_count',
user_id=None,
project_id=metric['project_id'],
resource_id=metric['alarm_id'],
resource_metadata={"alarm_state": metric['state']},
)

View File

@@ -0,0 +1,40 @@
#
# 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 aodhclient import client as aodh_client
from oslo_config import cfg
from ceilometer import keystone_client
from ceilometer.polling import plugin_base
SERVICE_OPTS = [
cfg.StrOpt('aodh',
default='alarming',
help='Aodh service type.'),
]
class AlarmDiscovery(plugin_base.DiscoveryBase):
def __init__(self, conf):
super().__init__(conf)
creds = conf.service_credentials
self.aodh_client = aodh_client.Client(
version='2',
session=keystone_client.get_session(conf),
region_name=creds.region_name,
interface=creds.interface,
service_type=conf.service_types.aodh)
def discover(self, manager, param=None):
"""Discover resources to monitor."""
return [self.aodh_client.metrics.get(all_projects=True)]

View File

@@ -17,6 +17,7 @@ import socket
from keystoneauth1 import loading
from oslo_config import cfg
import ceilometer.alarm.discovery
import ceilometer.cmd.polling
import ceilometer.compute.discovery
import ceilometer.compute.virt.inspector
@@ -100,7 +101,8 @@ def list_opts():
('rgw_admin_credentials', ceilometer.objectstore.rgw.CREDENTIAL_OPTS),
('rgw_client', ceilometer.objectstore.rgw.CLIENT_OPTS),
('service_types',
itertools.chain(ceilometer.image.discovery.SERVICE_OPTS,
itertools.chain(ceilometer.alarm.discovery.SERVICE_OPTS,
ceilometer.image.discovery.SERVICE_OPTS,
ceilometer.neutron_client.SERVICE_OPTS,
ceilometer.nova_client.SERVICE_OPTS,
ceilometer.objectstore.rgw.SERVICE_OPTS,

View File

@@ -136,5 +136,8 @@ def _gen_labels(sample):
else:
labels['keys'].append('server_group')
labels['values'].append('none')
if resource_metadata.get('alarm_state', '') != '':
labels['keys'].append('state')
labels['values'].append(resource_metadata['alarm_state'])
return labels

View File

View File

@@ -0,0 +1,64 @@
#
# Copyright 2012 New Dream Network, LLC (DreamHost)
#
# 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 ceilometer.alarm import aodh
from ceilometer.polling import manager
from ceilometer import service
import ceilometer.tests.base as base
ALARM_METRIC_LIST = [
{
'evaluation_results': [{
'alarm_id': 'b8e17f58-089a-43fc-a96b-e9bcac4d4b53',
'project_id': '2dd8edd6c8c24f49bf04670534f6b357',
'state_counters': {
'ok': 2,
'alarm': 5,
'insufficient data': 0,
}
}, {
'alarm_id': 'fa386719-67e3-42ff-aec8-17e547dac77a',
'project_id': 'd45b070bcce04ca99546128a40854e7c',
'state_counters': {
'ok': 50,
'alarm': 3,
'insufficient data': 10,
}
}],
},
]
class TestAlarmEvaluationResultPollster(base.BaseTestCase):
def setUp(self):
super().setUp()
conf = service.prepare_service([], [])
self.manager = manager.AgentManager(0, conf)
self.pollster = aodh.EvaluationResultPollster(conf)
def test_alarm_pollster(self):
alarm_samples = list(
self.pollster.get_samples(self.manager,
{},
resources=ALARM_METRIC_LIST))
self.assertEqual(6, len(alarm_samples))
self.assertEqual('alarm.evaluation_result', alarm_samples[0].name)
self.assertEqual(2, alarm_samples[0].volume)
self.assertEqual('2dd8edd6c8c24f49bf04670534f6b357',
alarm_samples[0].project_id)
self.assertEqual('b8e17f58-089a-43fc-a96b-e9bcac4d4b53',
alarm_samples[0].resource_id)
self.assertEqual('ok',
alarm_samples[0].resource_metadata['alarm_state'])

View File

@@ -634,3 +634,19 @@ The following meters are collected for FWaaS:
| ices.firewal\ | | ll_pol\ | | | firewall policy |
| l.policy | | icy | | | |
+---------------+-------+---------+------------+-----------+------------------+
Openstack alarming
~~~~~~~~~~~~~~~~~~
The following meters are collected for Aodh:
+---------------+-------+---------+------------+-----------+------------------+
| Name | Type | Unit | Resource | Origin | Note |
+===============+=======+=========+============+===========+==================+
| **Meters added in the Flamingo release** |
+---------------+-------+---------+------------+-----------+------------------+
| alarm.evalua\ | Gauge | evalua\ | alarm ID | Pollster | Total count of |
| tion_result | | tion_r\ | | | evaluation |
| | | esult\_\| | | results for each |
| | | count | | | alarm |
+---------------+-------+---------+------------+-----------+------------------+

View File

@@ -0,0 +1,5 @@
---
features:
- |
Ceilometer is now able to poll the /metrics endpoint in Aodh to get
evaluation results metrics.

View File

@@ -37,3 +37,4 @@ gnocchiclient>=7.0.0 # Apache-2.0
python-zaqarclient>=1.3.0 # Apache-2.0
prometheus_client>=0.20.0 # Apache-2.0
requests-aws>=0.1.4 # BSD License (3 clause)
aodhclient>=3.8.0 # Apache-2.0

View File

@@ -63,6 +63,7 @@ ceilometer.discover.central =
volume_pools = ceilometer.volume.discovery:VolumePoolsDiscovery
volume_snapshots = ceilometer.volume.discovery:VolumeSnapshotsDiscovery
volume_backups = ceilometer.volume.discovery:VolumeBackupsDiscovery
alarm = ceilometer.alarm.discovery:AlarmDiscovery
ceilometer.discover.ipmi =
local_node = ceilometer.polling.discovery.localnode:LocalNodeDiscovery
@@ -118,6 +119,7 @@ ceilometer.poll.ipmi =
hardware.ipmi.power = ceilometer.ipmi.pollsters.sensor:PowerSensorPollster
ceilometer.poll.central =
alarm.evaluation_result = ceilometer.alarm.aodh:EvaluationResultPollster
ip.floating = ceilometer.network.floatingip:FloatingIPPollster
image.size = ceilometer.image.glance:ImageSizePollster
radosgw.containers.objects = ceilometer.objectstore.rgw:ContainersObjectsPollster