Merge "api: Add response body schemas for server usage audit log APIs"

This commit is contained in:
Zuul
2025-12-15 18:03:27 +00:00
committed by Gerrit Code Review
7 changed files with 107 additions and 38 deletions

View File

@@ -1,25 +1,25 @@
{
"instance_usage_audit_logs": {
"hosts_not_run": [
"samplehost3"
"329fa448-f6bb-4e72-b954-faa66c30d4fa"
],
"log": {
"samplehost0": {
"2c8ef37b-f0cc-4a9e-92a6-32df0095cb12": {
"errors": 1,
"instances": 1,
"message": "Instance usage audit ran for host samplehost0, 1 instances in 0.01 seconds.",
"message": "Instance usage audit ran for host 2c8ef37b-f0cc-4a9e-92a6-32df0095cb12, 1 instances in 0.01 seconds.",
"state": "DONE"
},
"samplehost1": {
"60dbe74d-0cf3-419b-83f5-407e4b78c7b4": {
"errors": 1,
"instances": 2,
"message": "Instance usage audit ran for host samplehost1, 2 instances in 0.01 seconds.",
"message": "Instance usage audit ran for host 60dbe74d-0cf3-419b-83f5-407e4b78c7b4, 2 instances in 0.01 seconds.",
"state": "DONE"
},
"samplehost2": {
"2aa90c00-23eb-4da6-aff9-eda66bb56182": {
"errors": 1,
"instances": 3,
"message": "Instance usage audit ran for host samplehost2, 3 instances in 0.01 seconds.",
"message": "Instance usage audit ran for host 2aa90c00-23eb-4da6-aff9-eda66bb56182, 3 instances in 0.01 seconds.",
"state": "DONE"
}
},

View File

@@ -1,25 +1,25 @@
{
"instance_usage_audit_log": {
"hosts_not_run": [
"samplehost3"
"329fa448-f6bb-4e72-b954-faa66c30d4fa"
],
"log": {
"samplehost0": {
"2c8ef37b-f0cc-4a9e-92a6-32df0095cb12": {
"errors": 1,
"instances": 1,
"message": "Instance usage audit ran for host samplehost0, 1 instances in 0.01 seconds.",
"message": "Instance usage audit ran for host 2c8ef37b-f0cc-4a9e-92a6-32df0095cb12, 1 instances in 0.01 seconds.",
"state": "DONE"
},
"samplehost1": {
"60dbe74d-0cf3-419b-83f5-407e4b78c7b4": {
"errors": 1,
"instances": 2,
"message": "Instance usage audit ran for host samplehost1, 2 instances in 0.01 seconds.",
"message": "Instance usage audit ran for host 60dbe74d-0cf3-419b-83f5-407e4b78c7b4, 2 instances in 0.01 seconds.",
"state": "DONE"
},
"samplehost2": {
"2aa90c00-23eb-4da6-aff9-eda66bb56182": {
"errors": 1,
"instances": 3,
"message": "Instance usage audit ran for host samplehost2, 3 instances in 0.01 seconds.",
"message": "Instance usage audit ran for host 2aa90c00-23eb-4da6-aff9-eda66bb56182, 3 instances in 0.01 seconds.",
"state": "DONE"
}
},

View File

@@ -27,6 +27,7 @@ from nova.policies import instance_usage_audit_log as iual_policies
from nova import utils
@validation.validated
class InstanceUsageAuditLogController(wsgi.Controller):
def __init__(self):
@@ -35,6 +36,7 @@ class InstanceUsageAuditLogController(wsgi.Controller):
@wsgi.expected_errors(())
@validation.query_schema(schema.index_query)
@validation.response_body_schema(schema.index_response)
def index(self, req):
context = req.environ['nova.context']
context.can(iual_policies.BASE_POLICY_NAME % 'list', target={})
@@ -43,16 +45,17 @@ class InstanceUsageAuditLogController(wsgi.Controller):
@wsgi.expected_errors(400)
@validation.query_schema(schema.show_query)
@validation.response_body_schema(schema.show_response)
def show(self, req, id):
context = req.environ['nova.context']
context.can(iual_policies.BASE_POLICY_NAME % 'show', target={})
try:
if '.' in id:
before_date = datetime.datetime.strptime(str(id),
"%Y-%m-%d %H:%M:%S.%f")
before_date = datetime.datetime.strptime(
str(id), "%Y-%m-%d %H:%M:%S.%f")
else:
before_date = datetime.datetime.strptime(str(id),
"%Y-%m-%d %H:%M:%S")
before_date = datetime.datetime.strptime(
str(id), "%Y-%m-%d %H:%M:%S")
except ValueError:
msg = _("Invalid timestamp for date %s") % id
raise webob.exc.HTTPBadRequest(explanation=msg)

View File

@@ -21,3 +21,66 @@ show_query = {
'properties': {},
'additionalProperties': True,
}
_instance_usage_audit_log_response = {
'type': 'object',
'properties': {
'hosts_not_run': {
'type': 'array',
'items': {'type': 'string', 'format': 'uuid'},
},
'log': {
'type': 'object',
'additionalProperties': {
'instances': {'type': 'integer', 'minimum': 0},
'errors': {'type': 'integer', 'minimum': 0},
'message': {'type': 'string'},
'state': {'type': 'string', 'enum': ['RUNNING', 'DONE']},
},
},
'num_hosts': {'type': 'integer', 'minimum': 0},
'num_hosts_done': {'type': 'integer', 'minimum': 0},
'num_hosts_not_run': {'type': 'integer', 'minimum': 0},
'num_hosts_running': {'type': 'integer', 'minimum': 0},
'overall_status': {'type': 'string'},
'period_beginning': {'type': 'string', 'format': 'date-time'},
'period_ending': {'type': 'string', 'format': 'date-time'},
'total_errors': {'type': 'integer', 'minimum': 0},
'total_instances': {'type': 'integer', 'minimum': 0},
},
'required': [
'hosts_not_run',
'log',
'num_hosts',
'num_hosts_done',
'num_hosts_not_run',
'num_hosts_running',
'overall_status',
'period_beginning',
'period_ending',
'total_errors',
'total_instances',
],
'additionalProperties': False,
}
index_response = {
'type': 'object',
'properties': {
# NOTE(stephenfin): Yes, this is correct: the index response is
# identical to the show response. In fact, the show response is really
# the index response with a 'before' filter and a singular key
'instance_usage_audit_logs': _instance_usage_audit_log_response,
},
'required': ['instance_usage_audit_logs'],
'additionalProperties': False,
}
show_response = {
'type': 'object',
'properties': {
'instance_usage_audit_log': _instance_usage_audit_log_response,
},
'required': ['instance_usage_audit_log'],
'additionalProperties': False,
}

View File

@@ -1,25 +1,25 @@
{
"instance_usage_audit_logs": {
"hosts_not_run": [
"samplehost3"
"329fa448-f6bb-4e72-b954-faa66c30d4fa"
],
"log": {
"samplehost0": {
"2c8ef37b-f0cc-4a9e-92a6-32df0095cb12": {
"errors": 1,
"instances": 1,
"message": "Instance usage audit ran for host samplehost0, 1 instances in 0.01 seconds.",
"message": "Instance usage audit ran for host 2c8ef37b-f0cc-4a9e-92a6-32df0095cb12, 1 instances in 0.01 seconds.",
"state": "DONE"
},
"samplehost1": {
"60dbe74d-0cf3-419b-83f5-407e4b78c7b4": {
"errors": 1,
"instances": 2,
"message": "Instance usage audit ran for host samplehost1, 2 instances in 0.01 seconds.",
"message": "Instance usage audit ran for host 60dbe74d-0cf3-419b-83f5-407e4b78c7b4, 2 instances in 0.01 seconds.",
"state": "DONE"
},
"samplehost2": {
"2aa90c00-23eb-4da6-aff9-eda66bb56182": {
"errors": 1,
"instances": 3,
"message": "Instance usage audit ran for host samplehost2, 3 instances in 0.01 seconds.",
"message": "Instance usage audit ran for host 2aa90c00-23eb-4da6-aff9-eda66bb56182, 3 instances in 0.01 seconds.",
"state": "DONE"
}
},

View File

@@ -1,25 +1,25 @@
{
"instance_usage_audit_log": {
"hosts_not_run": [
"samplehost3"
"329fa448-f6bb-4e72-b954-faa66c30d4fa"
],
"log": {
"samplehost0": {
"2c8ef37b-f0cc-4a9e-92a6-32df0095cb12": {
"errors": 1,
"instances": 1,
"message": "Instance usage audit ran for host samplehost0, 1 instances in 0.01 seconds.",
"message": "Instance usage audit ran for host 2c8ef37b-f0cc-4a9e-92a6-32df0095cb12, 1 instances in 0.01 seconds.",
"state": "DONE"
},
"samplehost1": {
"60dbe74d-0cf3-419b-83f5-407e4b78c7b4": {
"errors": 1,
"instances": 2,
"message": "Instance usage audit ran for host samplehost1, 2 instances in 0.01 seconds.",
"message": "Instance usage audit ran for host 60dbe74d-0cf3-419b-83f5-407e4b78c7b4, 2 instances in 0.01 seconds.",
"state": "DONE"
},
"samplehost2": {
"2aa90c00-23eb-4da6-aff9-eda66bb56182": {
"errors": 1,
"instances": 3,
"message": "Instance usage audit ran for host samplehost2, 3 instances in 0.01 seconds.",
"message": "Instance usage audit ran for host 2aa90c00-23eb-4da6-aff9-eda66bb56182, 3 instances in 0.01 seconds.",
"state": "DONE"
}
},

View File

@@ -28,13 +28,16 @@ class InstanceUsageAuditLogJsonTest(api_sample_base.ApiSampleTestBaseV21):
def setUp(self):
super(InstanceUsageAuditLogJsonTest, self).setUp()
hosts = (
'2c8ef37b-f0cc-4a9e-92a6-32df0095cb12',
'60dbe74d-0cf3-419b-83f5-407e4b78c7b4',
'2aa90c00-23eb-4da6-aff9-eda66bb56182',
'329fa448-f6bb-4e72-b954-faa66c30d4fa',
)
def fake_service_get_all(self, context,
filters=None, set_zones=False):
services = [objects.Service(host='samplehost0'),
objects.Service(host='samplehost1'),
objects.Service(host='samplehost2'),
objects.Service(host='samplehost3')]
return services
return [objects.Service(host=host) for host in hosts]
def fake_utcnow(with_timezone=False):
# It is not UTC time, but no effect for testing
@@ -46,7 +49,7 @@ class InstanceUsageAuditLogJsonTest(api_sample_base.ApiSampleTestBaseV21):
fake_service_get_all)
for i in range(0, 3):
self._create_task_log('samplehost%d' % i, i + 1)
self._create_task_log(hosts[i], i + 1)
def _create_task_log(self, host, num_instances):
task_log = objects.TaskLog(context.get_admin_context())