Port instance_actions API to v3 Part 2
This patch contains the changes required to adapt the agent extension and the corresponding unittest to the v3 framework Partially implements: bp v3-api-extension-versioning Change-Id: Ibf0784a455942185799d40395fab5e8eb112e2d8
This commit is contained in:
parent
33fbb9cb68
commit
9b7d33f227
@ -97,7 +97,9 @@
|
|||||||
"compute_extension:v3:os-image-metadata": "",
|
"compute_extension:v3:os-image-metadata": "",
|
||||||
"compute_extension:v3:os-images": "",
|
"compute_extension:v3:os-images": "",
|
||||||
"compute_extension:instance_actions": "",
|
"compute_extension:instance_actions": "",
|
||||||
|
"compute_extension:v3:os-instance-actions": "",
|
||||||
"compute_extension:instance_actions:events": "rule:admin_api",
|
"compute_extension:instance_actions:events": "rule:admin_api",
|
||||||
|
"compute_extension:v3:os-instance-actions:events": "rule:admin_api",
|
||||||
"compute_extension:instance_usage_audit_log": "rule:admin_api",
|
"compute_extension:instance_usage_audit_log": "rule:admin_api",
|
||||||
"compute_extension:v3:os-instance-usage-audit-log": "rule:admin_api",
|
"compute_extension:v3:os-instance-usage-audit-log": "rule:admin_api",
|
||||||
"compute_extension:v3:ips:discoverable": "",
|
"compute_extension:v3:ips:discoverable": "",
|
||||||
|
@ -21,10 +21,11 @@ from nova.api.openstack import xmlutil
|
|||||||
from nova import compute
|
from nova import compute
|
||||||
from nova import exception
|
from nova import exception
|
||||||
|
|
||||||
|
ALIAS = "os-instance-actions"
|
||||||
authorize_actions = extensions.extension_authorizer('compute',
|
authorize_actions = extensions.extension_authorizer('compute',
|
||||||
'instance_actions')
|
'v3:' + ALIAS)
|
||||||
authorize_events = extensions.soft_extension_authorizer('compute',
|
authorize_events = extensions.soft_extension_authorizer('compute',
|
||||||
'instance_actions:events')
|
'v3:' + ALIAS + ':events')
|
||||||
|
|
||||||
ACTION_KEYS = ['action', 'instance_uuid', 'request_id', 'user_id',
|
ACTION_KEYS = ['action', 'instance_uuid', 'request_id', 'user_id',
|
||||||
'project_id', 'start_time', 'message']
|
'project_id', 'start_time', 'message']
|
||||||
@ -47,17 +48,17 @@ def make_action(elem):
|
|||||||
|
|
||||||
class InstanceActionsTemplate(xmlutil.TemplateBuilder):
|
class InstanceActionsTemplate(xmlutil.TemplateBuilder):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
root = xmlutil.TemplateElement('instanceActions')
|
root = xmlutil.TemplateElement('instance_actions')
|
||||||
elem = xmlutil.SubTemplateElement(root, 'instanceAction',
|
elem = xmlutil.SubTemplateElement(root, 'instance_action',
|
||||||
selector='instanceActions')
|
selector='instance_actions')
|
||||||
make_actions(elem)
|
make_actions(elem)
|
||||||
return xmlutil.MasterTemplate(root, 1)
|
return xmlutil.MasterTemplate(root, 1)
|
||||||
|
|
||||||
|
|
||||||
class InstanceActionTemplate(xmlutil.TemplateBuilder):
|
class InstanceActionTemplate(xmlutil.TemplateBuilder):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
root = xmlutil.TemplateElement('instanceAction',
|
root = xmlutil.TemplateElement('instance_action',
|
||||||
selector='instanceAction')
|
selector='instance_action')
|
||||||
make_action(root)
|
make_action(root)
|
||||||
return xmlutil.MasterTemplate(root, 1)
|
return xmlutil.MasterTemplate(root, 1)
|
||||||
|
|
||||||
@ -92,18 +93,22 @@ class InstanceActionsController(wsgi.Controller):
|
|||||||
authorize_actions(context, target=instance)
|
authorize_actions(context, target=instance)
|
||||||
actions_raw = self.action_api.actions_get(context, instance)
|
actions_raw = self.action_api.actions_get(context, instance)
|
||||||
actions = [self._format_action(action) for action in actions_raw]
|
actions = [self._format_action(action) for action in actions_raw]
|
||||||
return {'instanceActions': actions}
|
return {'instance_actions': actions}
|
||||||
|
|
||||||
@wsgi.serializers(xml=InstanceActionTemplate)
|
@wsgi.serializers(xml=InstanceActionTemplate)
|
||||||
def show(self, req, server_id, id):
|
def show(self, req, server_id, id):
|
||||||
"""Return data about the given instance action."""
|
"""Return data about the given instance action."""
|
||||||
context = req.environ['nova.context']
|
context = req.environ['nova.context']
|
||||||
|
try:
|
||||||
instance = self.compute_api.get(context, server_id)
|
instance = self.compute_api.get(context, server_id)
|
||||||
|
except exception.InstanceNotFound as err:
|
||||||
|
raise exc.HTTPNotFound(explanation=err.format_message())
|
||||||
authorize_actions(context, target=instance)
|
authorize_actions(context, target=instance)
|
||||||
action = self.action_api.action_get_by_request_id(context, instance,
|
action = self.action_api.action_get_by_request_id(context, instance,
|
||||||
id)
|
id)
|
||||||
if action is None:
|
if action is None:
|
||||||
raise exc.HTTPNotFound()
|
msg = _("Action %s not found") % id
|
||||||
|
raise exc.HTTPNotFound(msg)
|
||||||
|
|
||||||
action_id = action['id']
|
action_id = action['id']
|
||||||
action = self._format_action(action)
|
action = self._format_action(action)
|
||||||
@ -111,17 +116,17 @@ class InstanceActionsController(wsgi.Controller):
|
|||||||
events_raw = self.action_api.action_events_get(context, instance,
|
events_raw = self.action_api.action_events_get(context, instance,
|
||||||
action_id)
|
action_id)
|
||||||
action['events'] = [self._format_event(evt) for evt in events_raw]
|
action['events'] = [self._format_event(evt) for evt in events_raw]
|
||||||
return {'instanceAction': action}
|
return {'instance_action': action}
|
||||||
|
|
||||||
|
|
||||||
class Instance_actions(extensions.ExtensionDescriptor):
|
class InstanceActions(extensions.V3APIExtensionBase):
|
||||||
"""View a log of actions and events taken on an instance."""
|
"""View a log of actions and events taken on an instance."""
|
||||||
|
|
||||||
name = "InstanceActions"
|
name = "InstanceActions"
|
||||||
alias = "os-instance-actions"
|
alias = ALIAS
|
||||||
namespace = ("http://docs.openstack.org/compute/ext/"
|
namespace = ("http://docs.openstack.org/compute/ext/"
|
||||||
"instance-actions/api/v1.1")
|
"instance-actions/api/v3")
|
||||||
updated = "2013-02-08T00:00:00+00:00"
|
version = 1
|
||||||
|
|
||||||
def get_resources(self):
|
def get_resources(self):
|
||||||
ext = extensions.ResourceExtension('os-instance-actions',
|
ext = extensions.ResourceExtension('os-instance-actions',
|
||||||
@ -130,3 +135,9 @@ class Instance_actions(extensions.ExtensionDescriptor):
|
|||||||
member_name='server',
|
member_name='server',
|
||||||
collection_name='servers'))
|
collection_name='servers'))
|
||||||
return [ext]
|
return [ext]
|
||||||
|
|
||||||
|
def get_controller_extensions(self):
|
||||||
|
"""It's an abstract function V3APIExtensionBase and the extension
|
||||||
|
will not be loaded without it.
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
@ -19,7 +19,7 @@ import uuid
|
|||||||
from lxml import etree
|
from lxml import etree
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from nova.api.openstack.compute.contrib import instance_actions
|
from nova.api.openstack.compute.plugins.v3 import instance_actions
|
||||||
from nova.compute import api as compute_api
|
from nova.compute import api as compute_api
|
||||||
from nova import db
|
from nova import db
|
||||||
from nova.db.sqlalchemy import models
|
from nova.db.sqlalchemy import models
|
||||||
@ -57,7 +57,7 @@ class InstanceActionsPolicyTest(test.TestCase):
|
|||||||
|
|
||||||
def test_list_actions_restricted_by_project(self):
|
def test_list_actions_restricted_by_project(self):
|
||||||
rules = policy.Rules({'compute:get': policy.parse_rule(''),
|
rules = policy.Rules({'compute:get': policy.parse_rule(''),
|
||||||
'compute_extension:instance_actions':
|
'compute_extension:v3:os-instance-actions':
|
||||||
policy.parse_rule('project_id:%(project_id)s')})
|
policy.parse_rule('project_id:%(project_id)s')})
|
||||||
policy.set_rules(rules)
|
policy.set_rules(rules)
|
||||||
|
|
||||||
@ -68,13 +68,13 @@ class InstanceActionsPolicyTest(test.TestCase):
|
|||||||
context.project_id})
|
context.project_id})
|
||||||
|
|
||||||
self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid)
|
self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid)
|
||||||
req = fakes.HTTPRequest.blank('/v2/123/servers/12/os-instance-actions')
|
req = fakes.HTTPRequestV3.blank('/servers/12/os-instance-actions')
|
||||||
self.assertRaises(exception.NotAuthorized, self.controller.index, req,
|
self.assertRaises(exception.NotAuthorized, self.controller.index, req,
|
||||||
str(uuid.uuid4()))
|
str(uuid.uuid4()))
|
||||||
|
|
||||||
def test_get_action_restricted_by_project(self):
|
def test_get_action_restricted_by_project(self):
|
||||||
rules = policy.Rules({'compute:get': policy.parse_rule(''),
|
rules = policy.Rules({'compute:get': policy.parse_rule(''),
|
||||||
'compute_extension:instance_actions':
|
'compute_extension:v3:os-instance-actions':
|
||||||
policy.parse_rule('project_id:%(project_id)s')})
|
policy.parse_rule('project_id:%(project_id)s')})
|
||||||
policy.set_rules(rules)
|
policy.set_rules(rules)
|
||||||
|
|
||||||
@ -85,8 +85,8 @@ class InstanceActionsPolicyTest(test.TestCase):
|
|||||||
context.project_id})
|
context.project_id})
|
||||||
|
|
||||||
self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid)
|
self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid)
|
||||||
req = fakes.HTTPRequest.blank(
|
req = fakes.HTTPRequestV3.blank(
|
||||||
'/v2/123/servers/12/os-instance-actions/1')
|
'/servers/12/os-instance-actions/1')
|
||||||
self.assertRaises(exception.NotAuthorized, self.controller.show, req,
|
self.assertRaises(exception.NotAuthorized, self.controller.show, req,
|
||||||
str(uuid.uuid4()), '1')
|
str(uuid.uuid4()), '1')
|
||||||
|
|
||||||
@ -101,8 +101,11 @@ class InstanceActionsTest(test.TestCase):
|
|||||||
def fake_get(self, context, instance_uuid):
|
def fake_get(self, context, instance_uuid):
|
||||||
return {'uuid': instance_uuid}
|
return {'uuid': instance_uuid}
|
||||||
|
|
||||||
def fake_instance_get_by_uuid(context, instance_id):
|
def fake_instance_get_by_uuid(context, instance_id,
|
||||||
return {'name': 'fake', 'project_id': context.project_id}
|
columns_to_join=None):
|
||||||
|
return fake_instance.fake_db_instance(
|
||||||
|
**{'name': 'fake', 'project_id': '%s_unequal' %
|
||||||
|
context.project_id})
|
||||||
|
|
||||||
self.stubs.Set(compute_api.API, 'get', fake_get)
|
self.stubs.Set(compute_api.API, 'get', fake_get)
|
||||||
self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid)
|
self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid)
|
||||||
@ -117,9 +120,9 @@ class InstanceActionsTest(test.TestCase):
|
|||||||
return actions
|
return actions
|
||||||
|
|
||||||
self.stubs.Set(db, 'actions_get', fake_get_actions)
|
self.stubs.Set(db, 'actions_get', fake_get_actions)
|
||||||
req = fakes.HTTPRequest.blank('/v2/123/servers/12/os-instance-actions')
|
req = fakes.HTTPRequestV3.blank('/servers/12/os-instance-actions')
|
||||||
res_dict = self.controller.index(req, FAKE_UUID)
|
res_dict = self.controller.index(req, FAKE_UUID)
|
||||||
for res in res_dict['instanceActions']:
|
for res in res_dict['instance_actions']:
|
||||||
fake_action = self.fake_actions[FAKE_UUID][res['request_id']]
|
fake_action = self.fake_actions[FAKE_UUID][res['request_id']]
|
||||||
fake_action = format_action(fake_action)
|
fake_action = format_action(fake_action)
|
||||||
self.assertEqual(fake_action, res)
|
self.assertEqual(fake_action, res)
|
||||||
@ -140,8 +143,8 @@ class InstanceActionsTest(test.TestCase):
|
|||||||
|
|
||||||
self.stubs.Set(db, 'action_get_by_request_id', fake_get_action)
|
self.stubs.Set(db, 'action_get_by_request_id', fake_get_action)
|
||||||
self.stubs.Set(db, 'action_events_get', fake_get_events)
|
self.stubs.Set(db, 'action_events_get', fake_get_events)
|
||||||
req = fakes.HTTPRequest.blank(
|
req = fakes.HTTPRequestV3.blank(
|
||||||
'/v2/123/servers/12/os-instance-actions/1',
|
'/servers/12/os-instance-actions/1',
|
||||||
use_admin_context=True)
|
use_admin_context=True)
|
||||||
res_dict = self.controller.show(req, FAKE_UUID, FAKE_REQUEST_ID)
|
res_dict = self.controller.show(req, FAKE_UUID, FAKE_REQUEST_ID)
|
||||||
fake_action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID]
|
fake_action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID]
|
||||||
@ -149,7 +152,7 @@ class InstanceActionsTest(test.TestCase):
|
|||||||
fake_events = [format_event(event) for event in fake_events]
|
fake_events = [format_event(event) for event in fake_events]
|
||||||
fake_action = format_action(fake_action)
|
fake_action = format_action(fake_action)
|
||||||
fake_action['events'] = fake_events
|
fake_action['events'] = fake_events
|
||||||
self.assertEqual(fake_action, res_dict['instanceAction'])
|
self.assertEqual(fake_action, res_dict['instance_action'])
|
||||||
|
|
||||||
def test_get_action_with_events_not_allowed(self):
|
def test_get_action_with_events_not_allowed(self):
|
||||||
def fake_get_action(context, uuid, request_id):
|
def fake_get_action(context, uuid, request_id):
|
||||||
@ -160,26 +163,27 @@ class InstanceActionsTest(test.TestCase):
|
|||||||
|
|
||||||
self.stubs.Set(db, 'action_get_by_request_id', fake_get_action)
|
self.stubs.Set(db, 'action_get_by_request_id', fake_get_action)
|
||||||
self.stubs.Set(db, 'action_events_get', fake_get_events)
|
self.stubs.Set(db, 'action_events_get', fake_get_events)
|
||||||
rules = policy.Rules({'compute:get': policy.parse_rule(''),
|
rules = policy.Rules({
|
||||||
'compute_extension:instance_actions':
|
'compute:get': policy.parse_rule(''),
|
||||||
|
'compute_extension:v3:os-instance-actions':
|
||||||
policy.parse_rule(''),
|
policy.parse_rule(''),
|
||||||
'compute_extension:instance_actions:events':
|
'compute_extension:v3:os-instance-actions:events':
|
||||||
policy.parse_rule('is_admin:True')})
|
policy.parse_rule('is_admin:True')})
|
||||||
policy.set_rules(rules)
|
policy.set_rules(rules)
|
||||||
req = fakes.HTTPRequest.blank(
|
req = fakes.HTTPRequestV3.blank(
|
||||||
'/v2/123/servers/12/os-instance-actions/1')
|
'/servers/12/os-instance-actions/1')
|
||||||
res_dict = self.controller.show(req, FAKE_UUID, FAKE_REQUEST_ID)
|
res_dict = self.controller.show(req, FAKE_UUID, FAKE_REQUEST_ID)
|
||||||
fake_action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID]
|
fake_action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID]
|
||||||
fake_action = format_action(fake_action)
|
fake_action = format_action(fake_action)
|
||||||
self.assertEqual(fake_action, res_dict['instanceAction'])
|
self.assertEqual(fake_action, res_dict['instance_action'])
|
||||||
|
|
||||||
def test_action_not_found(self):
|
def test_action_not_found(self):
|
||||||
def fake_no_action(context, uuid, action_id):
|
def fake_no_action(context, uuid, action_id):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
self.stubs.Set(db, 'action_get_by_request_id', fake_no_action)
|
self.stubs.Set(db, 'action_get_by_request_id', fake_no_action)
|
||||||
req = fakes.HTTPRequest.blank(
|
req = fakes.HTTPRequestV3.blank(
|
||||||
'/v2/123/servers/12/os-instance-actions/1')
|
'/servers/12/os-instance-actions/1')
|
||||||
self.assertRaises(exc.HTTPNotFound, self.controller.show, req,
|
self.assertRaises(exc.HTTPNotFound, self.controller.show, req,
|
||||||
FAKE_UUID, FAKE_REQUEST_ID)
|
FAKE_UUID, FAKE_REQUEST_ID)
|
||||||
|
|
||||||
@ -187,10 +191,18 @@ class InstanceActionsTest(test.TestCase):
|
|||||||
def fake_get(self, context, instance_uuid):
|
def fake_get(self, context, instance_uuid):
|
||||||
raise exception.InstanceNotFound(instance_id=instance_uuid)
|
raise exception.InstanceNotFound(instance_id=instance_uuid)
|
||||||
self.stubs.Set(compute_api.API, 'get', fake_get)
|
self.stubs.Set(compute_api.API, 'get', fake_get)
|
||||||
req = fakes.HTTPRequest.blank('/v2/123/servers/12/os-instance-actions')
|
req = fakes.HTTPRequestV3.blank('/servers/12/os-instance-actions')
|
||||||
self.assertRaises(exc.HTTPNotFound, self.controller.index, req,
|
self.assertRaises(exc.HTTPNotFound, self.controller.index, req,
|
||||||
FAKE_UUID)
|
FAKE_UUID)
|
||||||
|
|
||||||
|
def test_instance_not_found_in_show(self):
|
||||||
|
def fake_get(self, context, instance_uuid):
|
||||||
|
raise exception.InstanceNotFound(instance_id=instance_uuid)
|
||||||
|
self.stubs.Set(compute_api.API, 'get', fake_get)
|
||||||
|
req = fakes.HTTPRequestV3.blank('/servers/12/os-instance-actions/1')
|
||||||
|
self.assertRaises(exc.HTTPNotFound, self.controller.show, req,
|
||||||
|
FAKE_UUID, FAKE_REQUEST_ID)
|
||||||
|
|
||||||
|
|
||||||
class InstanceActionsSerializerTest(test.TestCase):
|
class InstanceActionsSerializerTest(test.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -212,11 +224,11 @@ class InstanceActionsSerializerTest(test.TestCase):
|
|||||||
def test_instance_action_serializer(self):
|
def test_instance_action_serializer(self):
|
||||||
serializer = instance_actions.InstanceActionTemplate()
|
serializer = instance_actions.InstanceActionTemplate()
|
||||||
action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID]
|
action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID]
|
||||||
text = serializer.serialize({'instanceAction': action})
|
text = serializer.serialize({'instance_action': action})
|
||||||
tree = etree.fromstring(text)
|
tree = etree.fromstring(text)
|
||||||
|
|
||||||
action = format_action(action)
|
action = format_action(action)
|
||||||
self.assertEqual('instanceAction', tree.tag)
|
self.assertEqual('instance_action', tree.tag)
|
||||||
self._verify_instance_action_attachment(action, tree)
|
self._verify_instance_action_attachment(action, tree)
|
||||||
found_events = False
|
found_events = False
|
||||||
for child in tree:
|
for child in tree:
|
||||||
@ -229,11 +241,11 @@ class InstanceActionsSerializerTest(test.TestCase):
|
|||||||
action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID]
|
action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID]
|
||||||
event = self.fake_events[action['id']][0]
|
event = self.fake_events[action['id']][0]
|
||||||
action['events'] = [event, event]
|
action['events'] = [event, event]
|
||||||
text = serializer.serialize({'instanceAction': action})
|
text = serializer.serialize({'instance_action': action})
|
||||||
tree = etree.fromstring(text)
|
tree = etree.fromstring(text)
|
||||||
|
|
||||||
action = format_action(action)
|
action = format_action(action)
|
||||||
self.assertEqual('instanceAction', tree.tag)
|
self.assertEqual('instance_action', tree.tag)
|
||||||
self._verify_instance_action_attachment(action, tree)
|
self._verify_instance_action_attachment(action, tree)
|
||||||
|
|
||||||
event = format_event(event)
|
event = format_event(event)
|
||||||
@ -248,14 +260,14 @@ class InstanceActionsSerializerTest(test.TestCase):
|
|||||||
def test_instance_actions_serializer(self):
|
def test_instance_actions_serializer(self):
|
||||||
serializer = instance_actions.InstanceActionsTemplate()
|
serializer = instance_actions.InstanceActionsTemplate()
|
||||||
action_list = self.fake_actions[FAKE_UUID].values()
|
action_list = self.fake_actions[FAKE_UUID].values()
|
||||||
text = serializer.serialize({'instanceActions': action_list})
|
text = serializer.serialize({'instance_actions': action_list})
|
||||||
tree = etree.fromstring(text)
|
tree = etree.fromstring(text)
|
||||||
|
|
||||||
action_list = [format_action(action) for action in action_list]
|
action_list = [format_action(action) for action in action_list]
|
||||||
self.assertEqual('instanceActions', tree.tag)
|
self.assertEqual('instance_actions', tree.tag)
|
||||||
self.assertEqual(len(action_list), len(tree))
|
self.assertEqual(len(action_list), len(tree))
|
||||||
for idx, child in enumerate(tree):
|
for idx, child in enumerate(tree):
|
||||||
self.assertEqual('instanceAction', child.tag)
|
self.assertEqual('instance_action', child.tag)
|
||||||
request_id = child.get('request_id')
|
request_id = child.get('request_id')
|
||||||
self._verify_instance_action_attachment(
|
self._verify_instance_action_attachment(
|
||||||
self.fake_actions[FAKE_UUID][request_id],
|
self.fake_actions[FAKE_UUID][request_id],
|
||||||
|
@ -174,7 +174,9 @@ policy_data = """
|
|||||||
"compute_extension:v3:os-image-metadata": "",
|
"compute_extension:v3:os-image-metadata": "",
|
||||||
"compute_extension:v3:os-images": "",
|
"compute_extension:v3:os-images": "",
|
||||||
"compute_extension:instance_actions": "",
|
"compute_extension:instance_actions": "",
|
||||||
|
"compute_extension:v3:os-instance-actions": "",
|
||||||
"compute_extension:instance_actions:events": "is_admin:True",
|
"compute_extension:instance_actions:events": "is_admin:True",
|
||||||
|
"compute_extension:v3:os-instance-actions:events": "is_admin:True",
|
||||||
"compute_extension:instance_usage_audit_log": "",
|
"compute_extension:instance_usage_audit_log": "",
|
||||||
"compute_extension:v3:os-instance-usage-audit-log": "",
|
"compute_extension:v3:os-instance-usage-audit-log": "",
|
||||||
"compute_extension:keypairs": "",
|
"compute_extension:keypairs": "",
|
||||||
|
@ -77,6 +77,7 @@ nova.api.v3.extensions =
|
|||||||
hypervisors = nova.api.openstack.compute.plugins.v3.hypervisors:Hypervisors
|
hypervisors = nova.api.openstack.compute.plugins.v3.hypervisors:Hypervisors
|
||||||
image_metadata = nova.api.openstack.compute.plugins.v3.image_metadata:ImageMetadata
|
image_metadata = nova.api.openstack.compute.plugins.v3.image_metadata:ImageMetadata
|
||||||
images = nova.api.openstack.compute.plugins.v3.images:Images
|
images = nova.api.openstack.compute.plugins.v3.images:Images
|
||||||
|
instance_actions = nova.api.openstack.compute.plugins.v3.instance_actions:InstanceActions
|
||||||
ips = nova.api.openstack.compute.plugins.v3.ips:IPs
|
ips = nova.api.openstack.compute.plugins.v3.ips:IPs
|
||||||
instance_usage_audit_log = nova.api.openstack.compute.plugins.v3.instance_usage_audit_log:InstanceUsageAuditLog
|
instance_usage_audit_log = nova.api.openstack.compute.plugins.v3.instance_usage_audit_log:InstanceUsageAuditLog
|
||||||
keypairs = nova.api.openstack.compute.plugins.v3.keypairs:Keypairs
|
keypairs = nova.api.openstack.compute.plugins.v3.keypairs:Keypairs
|
||||||
|
Loading…
Reference in New Issue
Block a user