Add possibility to get metrics for all projects

This is to enable ceilometer to get all the metrics from all projects
the functionality is by default guarded by policy, which allows
only admins to access. This policy is simlar for example to
nova's policy for listing all servers.

Change-Id: I5894328c816b5803a69e9786d33b81566612df40
This commit is contained in:
Jaromir Wysoglad 2025-01-21 09:01:17 -05:00
parent c373d73290
commit e5c561a4c4
3 changed files with 83 additions and 8 deletions

View File

@ -80,8 +80,8 @@ class MetricsController(rest.RestController):
result[c.project_id][c.alarm_id][c.state] = c.value
return result
@wsme_pecan.wsexpose(MetricsOutput)
def get_all(self):
@wsme_pecan.wsexpose(MetricsOutput, bool)
def get_all(self, all_projects=False):
"""Return all metrics"""
if not pecan.request.cfg.enable_evaluation_results_metrics:
raise base.ClientSideError(_(
@ -91,16 +91,23 @@ class MetricsController(rest.RestController):
project_id = pecan.request.headers.get('X-Project-Id')
target = {"project_id": project_id}
rbac.enforce('get_metrics', pecan.request.headers,
pecan.request.enforcer, target)
counters = []
LOG.debug('Getting evaluation result counters from database')
if all_projects is True:
rbac.enforce('get_metrics:all_projects', pecan.request.headers,
pecan.request.enforcer, target)
counters = pecan.request.storage.get_alarm_counters()
else:
rbac.enforce('get_metrics', pecan.request.headers,
pecan.request.enforcer, target)
counters = pecan.request.storage.get_alarm_counters(
project_id=project_id
)
content = MetricsOutput()
alarm_states = [evaluator.UNKNOWN, evaluator.OK, evaluator.ALARM]
LOG.debug('Getting evaluation result counters from database')
grouped_counters = self.group_counters(
pecan.request.storage.get_alarm_counters(project_id=project_id)
)
grouped_counters = self.group_counters(counters)
evaluation_results = []
for project, alarms in grouped_counters.items():
for alarm, states in alarms.items():

View File

@ -342,6 +342,18 @@ rules = [
}
]
),
policy.DocumentedRuleDefault(
name="telemetry:get_metrics:all_projects",
check_str=PROJECT_ADMIN,
scope_types=['project'],
description='Get all metrics from all projects.',
operations=[
{
'path': '/v2/metrics',
'method': 'GET'
}
]
),
]

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import os
import webtest
@ -58,7 +59,9 @@ class TestMetrics(v2.FunctionalTest):
def setUp(self):
super(TestMetrics, self).setUp()
self.project_id = "some_project_id"
self.project_id2 = "some_project_id2"
self.alarm_id = "some_alarm_id"
self.alarm_id2 = "some_alarm_id2"
self.user_id = "some_user_id"
self.role = "reader"
self.auth_headers = {'X-User-Id': self.user_id,
@ -69,6 +72,11 @@ class TestMetrics(v2.FunctionalTest):
self.project_id,
self.user_id)
)
self.alarm_conn.create_alarm(getTestAlarm(
self.alarm_id2,
self.project_id2,
self.user_id)
)
self.alarm_conn.increment_alarm_counter(
self.alarm_id,
self.project_id,
@ -84,6 +92,11 @@ class TestMetrics(v2.FunctionalTest):
self.project_id,
"insufficient_data"
)
self.alarm_conn.increment_alarm_counter(
self.alarm_id2,
self.project_id2,
"alarm"
)
def test_get_all_metrics_inside_project(self):
expected = {
@ -118,3 +131,46 @@ class TestMetrics(v2.FunctionalTest):
self.assertEqual(403, response.status_code)
self.assertEqual(faultstring,
response.json['error_message']['faultstring'])
def test_get_all_metrics_all_projects(self):
auth_headers = copy.copy(self.auth_headers)
auth_headers['X-Roles'] = 'admin'
expected = {
"evaluation_results": [{
"alarm_id": self.alarm_id,
"project_id": self.project_id,
"state_counters": {
"ok": 1,
"insufficient data": 2,
"alarm": 0
}
}, {
"alarm_id": self.alarm_id2,
"project_id": self.project_id2,
"state_counters": {
"ok": 0,
"insufficient data": 0,
"alarm": 1
}
}]
}
metrics = self.get_json(
'/metrics?all_projects=true',
headers=auth_headers,
)
self.assertEqual(expected, metrics)
def test_get_all_metrics_all_projects_forbidden(self):
pf = os.path.abspath('aodh/tests/functional/api/v2/policy.yaml-test')
self.CONF.set_override('policy_file', pf, group='oslo_policy')
self.CONF.set_override('auth_mode', None, group='api')
self.app = webtest.TestApp(app.load_app(self.CONF))
response = self.get_json('/metrics?all_projects=true',
expect_errors=True,
status=403,
headers=self.auth_headers)
faultstring = 'RBAC Authorization Failed'
self.assertEqual(403, response.status_code)
self.assertEqual(faultstring,
response.json['error_message']['faultstring'])