summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/nova/policy.json6
-rw-r--r--nova/api/openstack/compute/plugins/v3/extension_info.py23
-rw-r--r--nova/api/openstack/extensions.py4
-rw-r--r--nova/tests/api/openstack/compute/plugins/v3/test_extension_info.py108
4 files changed, 137 insertions, 4 deletions
diff --git a/etc/nova/policy.json b/etc/nova/policy.json
index f33feb689..a528bc887 100644
--- a/etc/nova/policy.json
+++ b/etc/nova/policy.json
@@ -37,6 +37,7 @@
"compute_extension:cloudpipe": "rule:admin_api",
"compute_extension:cloudpipe_update": "rule:admin_api",
"compute_extension:console_output": "",
+ "compute_extension:v3:consoles:discoverable": "",
"compute_extension:consoles": "",
"compute_extension:coverage_ext": "rule:admin_api",
"compute_extension:createserverext": "",
@@ -49,7 +50,9 @@
"compute_extension:extended_ips": "",
"compute_extension:extended_ips_mac": "",
"compute_extension:extended_vif_net": "",
+ "compute_extension:v3:extension_info:discoverable": "",
"compute_extension:fixed_ips": "rule:admin_api",
+ "compute_extension:v3:os-fixed-ips:discoverable": "",
"compute_extension:v3:os-fixed-ips": "rule:admin_api",
"compute_extension:flavor_access": "",
"compute_extension:flavor_disabled": "",
@@ -75,7 +78,9 @@
"compute_extension:instance_actions": "",
"compute_extension:instance_actions:events": "rule:admin_api",
"compute_extension:instance_usage_audit_log": "rule:admin_api",
+ "compute_extension:v3:ips:discoverable": "",
"compute_extension:keypairs": "",
+ "compute_extension:v3:os-keypairs:discoverable": "",
"compute_extension:v3:os-keypairs": "",
"compute_extension:multinic": "",
"compute_extension:networks": "rule:admin_api",
@@ -92,6 +97,7 @@
"compute_extension:server_password": "",
"compute_extension:server_usage": "",
"compute_extension:services": "rule:admin_api",
+ "compute_extension:v3:servers:discoverable": "",
"compute_extension:simple_tenant_usage:show": "rule:admin_or_owner",
"compute_extension:simple_tenant_usage:list": "rule:admin_api",
"compute_extension:users": "rule:admin_api",
diff --git a/nova/api/openstack/compute/plugins/v3/extension_info.py b/nova/api/openstack/compute/plugins/v3/extension_info.py
index 43b0551c7..c626f6104 100644
--- a/nova/api/openstack/compute/plugins/v3/extension_info.py
+++ b/nova/api/openstack/compute/plugins/v3/extension_info.py
@@ -19,6 +19,10 @@ import webob.exc
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
+from nova.openstack.common import log as logging
+
+
+LOG = logging.getLogger(__name__)
def make_ext(elem):
@@ -64,11 +68,25 @@ class ExtensionInfoController(object):
ext_data['version'] = ext.version
return ext_data
+ def _get_extensions(self, context):
+ """Filter extensions list based on policy"""
+
+ discoverable_extensions = dict()
+ for alias, ext in self.extension_info.get_extensions().iteritems():
+ authorize = extensions.soft_extension_authorizer(
+ 'compute', 'v3:' + alias)
+ if authorize(context, action='discoverable'):
+ discoverable_extensions[alias] = ext
+ else:
+ LOG.debug(_("Filter out extension %s from discover list"), alias)
+ return discoverable_extensions
+
@wsgi.serializers(xml=ExtensionsTemplate)
def index(self, req):
+ context = req.environ['nova.context']
sorted_ext_list = sorted(
- self.extension_info.get_extensions().iteritems())
+ self._get_extensions(context).iteritems())
extensions = []
for _alias, ext in sorted_ext_list:
@@ -77,9 +95,10 @@ class ExtensionInfoController(object):
@wsgi.serializers(xml=ExtensionTemplate)
def show(self, req, id):
+ context = req.environ['nova.context']
try:
# NOTE(dprince): the extensions alias is used as the 'id' for show
- ext = self.extension_info.get_extensions()[id]
+ ext = self._get_extensions(context)[id]
except KeyError:
raise webob.exc.HTTPNotFound()
diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py
index 6cbc5bb78..2f3494ca4 100644
--- a/nova/api/openstack/extensions.py
+++ b/nova/api/openstack/extensions.py
@@ -392,9 +392,9 @@ def extension_authorizer(api_name, extension_name):
def soft_extension_authorizer(api_name, extension_name):
hard_authorize = extension_authorizer(api_name, extension_name)
- def authorize(context):
+ def authorize(context, action=None):
try:
- hard_authorize(context)
+ hard_authorize(context, action=action)
return True
except exception.NotAuthorized:
return False
diff --git a/nova/tests/api/openstack/compute/plugins/v3/test_extension_info.py b/nova/tests/api/openstack/compute/plugins/v3/test_extension_info.py
new file mode 100644
index 000000000..a19d28064
--- /dev/null
+++ b/nova/tests/api/openstack/compute/plugins/v3/test_extension_info.py
@@ -0,0 +1,108 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corp.
+#
+# 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 nova.api.openstack.compute import plugins
+from nova.api.openstack.compute.plugins.v3 import extension_info
+from nova import exception
+from nova import policy
+from nova import test
+from nova.tests.api.openstack import fakes
+
+
+class fake_extension(object):
+ def __init__(self, name, alias, description, namespace, version):
+ self.name = name
+ self.alias = alias
+ self.__doc__ = description
+ self.namespace = namespace
+ self.version = version
+
+
+fake_extensions = {
+ 'ext1-alias': fake_extension('ext1', 'ext1-alias', 'ext1 description',
+ 'ext1 namespace', 1),
+ 'ext2-alias': fake_extension('ext2', 'ext2-alias', 'ext2 description',
+ 'ext2 namespace', 2),
+ 'ext3-alias': fake_extension('ext3', 'ext3-alias', 'ext3 description',
+ 'ext3 namespace', 1)
+}
+
+def fake_policy_enforce(context, action, target, do_raise=True):
+ return True
+
+def fake_policy_enforce_selective(context, action, target, do_raise=True):
+ if action == 'compute_extension:v3:ext1-alias:discoverable':
+ raise exception.NotAuthorized
+ else:
+ return True
+
+
+class ExtensionInfoTest(test.TestCase):
+
+ def setUp(self):
+ super(ExtensionInfoTest, self).setUp()
+ ext_info = plugins.LoadedExtensionInfo()
+ ext_info.extensions = fake_extensions
+ self.controller = extension_info.ExtensionInfoController(ext_info)
+
+ def test_extension_info_list(self):
+ self.stubs.Set(policy, 'enforce', fake_policy_enforce)
+ req = fakes.HTTPRequestV3.blank('/extensions')
+ res_dict = self.controller.index(req)
+ self.assertEqual(3, len(res_dict['extensions']))
+ for e in res_dict['extensions']:
+ self.assertIn(e['alias'], fake_extensions)
+ self.assertEqual(e['name'], fake_extensions[e['alias']].name)
+ self.assertEqual(e['alias'], fake_extensions[e['alias']].alias)
+ self.assertEqual(e['description'],
+ fake_extensions[e['alias']].__doc__)
+ self.assertEqual(e['namespace'],
+ fake_extensions[e['alias']].namespace)
+ self.assertEqual(e['version'],
+ fake_extensions[e['alias']].version)
+
+ def test_extension_info_show(self):
+ self.stubs.Set(policy, 'enforce', fake_policy_enforce)
+ req = fakes.HTTPRequestV3.blank('/extensions/ext1-alias')
+ res_dict = self.controller.show(req, 'ext1-alias')
+ self.assertEqual(1, len(res_dict))
+ self.assertEqual(res_dict['extension']['name'],
+ fake_extensions['ext1-alias'].name)
+ self.assertEqual(res_dict['extension']['alias'],
+ fake_extensions['ext1-alias'].alias)
+ self.assertEqual(res_dict['extension']['description'],
+ fake_extensions['ext1-alias'].__doc__)
+ self.assertEqual(res_dict['extension']['namespace'],
+ fake_extensions['ext1-alias'].namespace)
+ self.assertEqual(res_dict['extension']['version'],
+ fake_extensions['ext1-alias'].version)
+
+ def test_extension_info_list_not_all_discoverable(self):
+ self.stubs.Set(policy, 'enforce', fake_policy_enforce_selective)
+ req = fakes.HTTPRequestV3.blank('/extensions')
+ res_dict = self.controller.index(req)
+ self.assertEqual(2, len(res_dict['extensions']))
+ for e in res_dict['extensions']:
+ self.assertNotEqual('ext1-alias', e['alias'])
+ self.assertIn(e['alias'], fake_extensions)
+ self.assertEqual(e['name'], fake_extensions[e['alias']].name)
+ self.assertEqual(e['alias'], fake_extensions[e['alias']].alias)
+ self.assertEqual(e['description'],
+ fake_extensions[e['alias']].__doc__)
+ self.assertEqual(e['namespace'],
+ fake_extensions[e['alias']].namespace)
+ self.assertEqual(e['version'],
+ fake_extensions[e['alias']].version)