Merge "Port instance_actions API to v3 Part 2"

This commit is contained in:
Jenkins 2013-07-15 12:47:23 +00:00 committed by Gerrit Code Review
commit fe1e15678e
5 changed files with 74 additions and 46 deletions

View File

@ -110,7 +110,9 @@
"compute_extension:v3:os-image-metadata": "",
"compute_extension:v3:os-images": "",
"compute_extension:instance_actions": "",
"compute_extension:v3:os-instance-actions": "",
"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:v3:os-instance-usage-audit-log": "rule:admin_api",
"compute_extension:v3:ips:discoverable": "",

View File

@ -21,10 +21,11 @@ from nova.api.openstack import xmlutil
from nova import compute
from nova import exception
ALIAS = "os-instance-actions"
authorize_actions = extensions.extension_authorizer('compute',
'instance_actions')
'v3:' + ALIAS)
authorize_events = extensions.soft_extension_authorizer('compute',
'instance_actions:events')
'v3:' + ALIAS + ':events')
ACTION_KEYS = ['action', 'instance_uuid', 'request_id', 'user_id',
'project_id', 'start_time', 'message']
@ -47,17 +48,17 @@ def make_action(elem):
class InstanceActionsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('instanceActions')
elem = xmlutil.SubTemplateElement(root, 'instanceAction',
selector='instanceActions')
root = xmlutil.TemplateElement('instance_actions')
elem = xmlutil.SubTemplateElement(root, 'instance_action',
selector='instance_actions')
make_actions(elem)
return xmlutil.MasterTemplate(root, 1)
class InstanceActionTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('instanceAction',
selector='instanceAction')
root = xmlutil.TemplateElement('instance_action',
selector='instance_action')
make_action(root)
return xmlutil.MasterTemplate(root, 1)
@ -92,18 +93,22 @@ class InstanceActionsController(wsgi.Controller):
authorize_actions(context, target=instance)
actions_raw = self.action_api.actions_get(context, instance)
actions = [self._format_action(action) for action in actions_raw]
return {'instanceActions': actions}
return {'instance_actions': actions}
@wsgi.serializers(xml=InstanceActionTemplate)
def show(self, req, server_id, id):
"""Return data about the given instance action."""
context = req.environ['nova.context']
instance = self.compute_api.get(context, server_id)
try:
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)
action = self.action_api.action_get_by_request_id(context, instance,
id)
if action is None:
raise exc.HTTPNotFound()
msg = _("Action %s not found") % id
raise exc.HTTPNotFound(msg)
action_id = action['id']
action = self._format_action(action)
@ -111,17 +116,17 @@ class InstanceActionsController(wsgi.Controller):
events_raw = self.action_api.action_events_get(context, instance,
action_id)
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."""
name = "InstanceActions"
alias = "os-instance-actions"
alias = ALIAS
namespace = ("http://docs.openstack.org/compute/ext/"
"instance-actions/api/v1.1")
updated = "2013-02-08T00:00:00+00:00"
"instance-actions/api/v3")
version = 1
def get_resources(self):
ext = extensions.ResourceExtension('os-instance-actions',
@ -130,3 +135,9 @@ class Instance_actions(extensions.ExtensionDescriptor):
member_name='server',
collection_name='servers'))
return [ext]
def get_controller_extensions(self):
"""It's an abstract function V3APIExtensionBase and the extension
will not be loaded without it.
"""
return []

View File

@ -19,7 +19,7 @@ import uuid
from lxml import etree
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 import db
from nova.db.sqlalchemy import models
@ -57,7 +57,7 @@ class InstanceActionsPolicyTest(test.TestCase):
def test_list_actions_restricted_by_project(self):
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.set_rules(rules)
@ -68,13 +68,13 @@ class InstanceActionsPolicyTest(test.TestCase):
context.project_id})
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,
str(uuid.uuid4()))
def test_get_action_restricted_by_project(self):
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.set_rules(rules)
@ -85,8 +85,8 @@ class InstanceActionsPolicyTest(test.TestCase):
context.project_id})
self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid)
req = fakes.HTTPRequest.blank(
'/v2/123/servers/12/os-instance-actions/1')
req = fakes.HTTPRequestV3.blank(
'/servers/12/os-instance-actions/1')
self.assertRaises(exception.NotAuthorized, self.controller.show, req,
str(uuid.uuid4()), '1')
@ -101,8 +101,11 @@ class InstanceActionsTest(test.TestCase):
def fake_get(self, context, instance_uuid):
return {'uuid': instance_uuid}
def fake_instance_get_by_uuid(context, instance_id):
return {'name': 'fake', 'project_id': context.project_id}
def fake_instance_get_by_uuid(context, instance_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(db, 'instance_get_by_uuid', fake_instance_get_by_uuid)
@ -117,9 +120,9 @@ class InstanceActionsTest(test.TestCase):
return 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)
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 = format_action(fake_action)
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_events_get', fake_get_events)
req = fakes.HTTPRequest.blank(
'/v2/123/servers/12/os-instance-actions/1',
req = fakes.HTTPRequestV3.blank(
'/servers/12/os-instance-actions/1',
use_admin_context=True)
res_dict = self.controller.show(req, 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_action = format_action(fake_action)
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 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_events_get', fake_get_events)
rules = policy.Rules({'compute:get': policy.parse_rule(''),
'compute_extension:instance_actions':
policy.parse_rule(''),
'compute_extension:instance_actions:events':
policy.parse_rule('is_admin:True')})
rules = policy.Rules({
'compute:get': policy.parse_rule(''),
'compute_extension:v3:os-instance-actions':
policy.parse_rule(''),
'compute_extension:v3:os-instance-actions:events':
policy.parse_rule('is_admin:True')})
policy.set_rules(rules)
req = fakes.HTTPRequest.blank(
'/v2/123/servers/12/os-instance-actions/1')
req = fakes.HTTPRequestV3.blank(
'/servers/12/os-instance-actions/1')
res_dict = self.controller.show(req, FAKE_UUID, FAKE_REQUEST_ID)
fake_action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID]
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 fake_no_action(context, uuid, action_id):
return None
self.stubs.Set(db, 'action_get_by_request_id', fake_no_action)
req = fakes.HTTPRequest.blank(
'/v2/123/servers/12/os-instance-actions/1')
req = fakes.HTTPRequestV3.blank(
'/servers/12/os-instance-actions/1')
self.assertRaises(exc.HTTPNotFound, self.controller.show, req,
FAKE_UUID, FAKE_REQUEST_ID)
@ -187,10 +191,18 @@ class InstanceActionsTest(test.TestCase):
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.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,
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):
def setUp(self):
@ -212,11 +224,11 @@ class InstanceActionsSerializerTest(test.TestCase):
def test_instance_action_serializer(self):
serializer = instance_actions.InstanceActionTemplate()
action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID]
text = serializer.serialize({'instanceAction': action})
text = serializer.serialize({'instance_action': action})
tree = etree.fromstring(text)
action = format_action(action)
self.assertEqual('instanceAction', tree.tag)
self.assertEqual('instance_action', tree.tag)
self._verify_instance_action_attachment(action, tree)
found_events = False
for child in tree:
@ -229,11 +241,11 @@ class InstanceActionsSerializerTest(test.TestCase):
action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID]
event = self.fake_events[action['id']][0]
action['events'] = [event, event]
text = serializer.serialize({'instanceAction': action})
text = serializer.serialize({'instance_action': action})
tree = etree.fromstring(text)
action = format_action(action)
self.assertEqual('instanceAction', tree.tag)
self.assertEqual('instance_action', tree.tag)
self._verify_instance_action_attachment(action, tree)
event = format_event(event)
@ -248,14 +260,14 @@ class InstanceActionsSerializerTest(test.TestCase):
def test_instance_actions_serializer(self):
serializer = instance_actions.InstanceActionsTemplate()
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)
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))
for idx, child in enumerate(tree):
self.assertEqual('instanceAction', child.tag)
self.assertEqual('instance_action', child.tag)
request_id = child.get('request_id')
self._verify_instance_action_attachment(
self.fake_actions[FAKE_UUID][request_id],

View File

@ -186,7 +186,9 @@ policy_data = """
"compute_extension:v3:os-image-metadata": "",
"compute_extension:v3:os-images": "",
"compute_extension:instance_actions": "",
"compute_extension:v3:os-instance-actions": "",
"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:v3:os-instance-usage-audit-log": "",
"compute_extension:keypairs": "",

View File

@ -79,6 +79,7 @@ nova.api.v3.extensions =
hypervisors = nova.api.openstack.compute.plugins.v3.hypervisors:Hypervisors
image_metadata = nova.api.openstack.compute.plugins.v3.image_metadata:ImageMetadata
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
instance_usage_audit_log = nova.api.openstack.compute.plugins.v3.instance_usage_audit_log:InstanceUsageAuditLog
keypairs = nova.api.openstack.compute.plugins.v3.keypairs:Keypairs