Port availability zones to core API
Changes: - Register availability zones API as core API using old link. - Remove extension code for availability zones. - Leave rename of API url for future update which will be done with bump of microversion after port of all extensions to core API. Partially implements bp ext-to-core Change-Id: Ifc75ef2d16121634ad12e5e12960c928e4d24b90
This commit is contained in:
parent
099145a07b
commit
e4428f5e6c
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
"admin_api": "is_admin:True",
|
"admin_api": "is_admin:True",
|
||||||
|
|
||||||
|
"availability_zone:index": "rule:default",
|
||||||
|
|
||||||
"share:create": "",
|
"share:create": "",
|
||||||
"share:delete": "rule:default",
|
"share:delete": "rule:default",
|
||||||
"share:get": "rule:default",
|
"share:get": "rule:default",
|
||||||
|
@ -31,6 +31,7 @@ from manila import exception
|
|||||||
from manila.i18n import _
|
from manila.i18n import _
|
||||||
from manila.i18n import _LE
|
from manila.i18n import _LE
|
||||||
from manila.i18n import _LI
|
from manila.i18n import _LI
|
||||||
|
from manila import policy
|
||||||
from manila import wsgi
|
from manila import wsgi
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
@ -1110,6 +1111,12 @@ class Controller(object):
|
|||||||
|
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
def authorize(self, context, action):
|
||||||
|
try:
|
||||||
|
policy.check_policy(context, self.resource_name, action)
|
||||||
|
except exception.PolicyNotAuthorized:
|
||||||
|
raise webob.exc.HTTPForbidden()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_valid_body(body, entity_name):
|
def is_valid_body(body, entity_name):
|
||||||
if not (body and entity_name in body):
|
if not (body and entity_name in body):
|
||||||
|
@ -13,31 +13,26 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from manila.api import extensions
|
|
||||||
from manila.api.openstack import wsgi
|
from manila.api.openstack import wsgi
|
||||||
|
from manila.api.views import availability_zones as availability_zones_views
|
||||||
from manila import db
|
from manila import db
|
||||||
|
|
||||||
authorize = extensions.extension_authorizer('share', 'availability_zones')
|
|
||||||
|
|
||||||
|
class AvailabilityZoneController(wsgi.Controller):
|
||||||
|
"""The Availability Zone API controller for the OpenStack API."""
|
||||||
|
|
||||||
|
resource_name = "availability_zone"
|
||||||
|
_view_builder_class = availability_zones_views.ViewBuilder
|
||||||
|
|
||||||
class Controller(wsgi.Controller):
|
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
|
self.authorize(req.environ['manila.context'], 'index')
|
||||||
|
return self._index(req)
|
||||||
|
|
||||||
|
def _index(self, req):
|
||||||
"""Describe all known availability zones."""
|
"""Describe all known availability zones."""
|
||||||
context = req.environ['manila.context']
|
views = db.availability_zone_get_all(req.environ['manila.context'])
|
||||||
authorize(context)
|
return self._view_builder.detail_list(views)
|
||||||
azs = db.availability_zone_get_all(context)
|
|
||||||
return {'availability_zones': azs}
|
|
||||||
|
|
||||||
|
|
||||||
class Availability_zones(extensions.ExtensionDescriptor):
|
def create_resource():
|
||||||
"""Describe Availability Zones."""
|
return wsgi.Resource(AvailabilityZoneController())
|
||||||
|
|
||||||
name = 'AvailabilityZones'
|
|
||||||
alias = 'os-availability-zone'
|
|
||||||
updated = '2015-07-28T00:00:00+00:00'
|
|
||||||
|
|
||||||
def get_resources(self):
|
|
||||||
controller = Controller()
|
|
||||||
res = extensions.ResourceExtension(Availability_zones.alias,
|
|
||||||
controller)
|
|
||||||
return [res]
|
|
@ -23,6 +23,7 @@ from oslo_log import log
|
|||||||
|
|
||||||
from manila.api import extensions
|
from manila.api import extensions
|
||||||
import manila.api.openstack
|
import manila.api.openstack
|
||||||
|
from manila.api.v1 import availability_zones
|
||||||
from manila.api.v1 import cgsnapshots
|
from manila.api.v1 import cgsnapshots
|
||||||
from manila.api.v1 import consistency_groups
|
from manila.api.v1 import consistency_groups
|
||||||
from manila.api.v1 import limits
|
from manila.api.v1 import limits
|
||||||
@ -56,6 +57,14 @@ class APIRouter(manila.api.openstack.APIRouter):
|
|||||||
|
|
||||||
mapper.redirect("", "/")
|
mapper.redirect("", "/")
|
||||||
|
|
||||||
|
self.resources["availability_zones"] = (
|
||||||
|
availability_zones.create_resource())
|
||||||
|
mapper.resource("availability-zone",
|
||||||
|
# TODO(vponomaryov): rename 'os-availability-zone' to
|
||||||
|
# 'availability-zones' when API urls rename happens.
|
||||||
|
"os-availability-zone",
|
||||||
|
controller=self.resources["availability_zones"])
|
||||||
|
|
||||||
self.resources['shares'] = shares.create_resource()
|
self.resources['shares'] = shares.create_resource()
|
||||||
mapper.resource("share", "shares",
|
mapper.resource("share", "shares",
|
||||||
controller=self.resources['shares'],
|
controller=self.resources['shares'],
|
||||||
|
@ -19,7 +19,6 @@ from manila.api.openstack import wsgi
|
|||||||
from manila.api.views import share_instance as instance_view
|
from manila.api.views import share_instance as instance_view
|
||||||
from manila import db
|
from manila import db
|
||||||
from manila import exception
|
from manila import exception
|
||||||
from manila import policy
|
|
||||||
from manila import share
|
from manila import share
|
||||||
|
|
||||||
|
|
||||||
@ -33,16 +32,10 @@ class ShareInstancesController(wsgi.Controller):
|
|||||||
self.share_api = share.API()
|
self.share_api = share.API()
|
||||||
super(ShareInstancesController, self).__init__()
|
super(ShareInstancesController, self).__init__()
|
||||||
|
|
||||||
def _authorize(self, context, action):
|
|
||||||
try:
|
|
||||||
policy.check_policy(context, self.resource_name, action)
|
|
||||||
except exception.PolicyNotAuthorized:
|
|
||||||
raise exc.HTTPForbidden()
|
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.3")
|
@wsgi.Controller.api_version("2.3")
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
context = req.environ['manila.context']
|
context = req.environ['manila.context']
|
||||||
self._authorize(context, 'index')
|
self.authorize(context, 'index')
|
||||||
|
|
||||||
instances = db.share_instances_get_all(context)
|
instances = db.share_instances_get_all(context)
|
||||||
return self._view_builder.detail_list(req, instances)
|
return self._view_builder.detail_list(req, instances)
|
||||||
@ -50,7 +43,7 @@ class ShareInstancesController(wsgi.Controller):
|
|||||||
@wsgi.Controller.api_version("2.3")
|
@wsgi.Controller.api_version("2.3")
|
||||||
def show(self, req, id):
|
def show(self, req, id):
|
||||||
context = req.environ['manila.context']
|
context = req.environ['manila.context']
|
||||||
self._authorize(context, 'show')
|
self.authorize(context, 'show')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
instance = db.share_instance_get(context, id)
|
instance = db.share_instance_get(context, id)
|
||||||
@ -62,7 +55,7 @@ class ShareInstancesController(wsgi.Controller):
|
|||||||
@wsgi.Controller.api_version("2.3")
|
@wsgi.Controller.api_version("2.3")
|
||||||
def get_share_instances(self, req, share_id):
|
def get_share_instances(self, req, share_id):
|
||||||
context = req.environ['manila.context']
|
context = req.environ['manila.context']
|
||||||
self._authorize(context, 'index')
|
self.authorize(context, 'index')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
share = self.share_api.get(context, share_id)
|
share = self.share_api.get(context, share_id)
|
||||||
@ -74,4 +67,4 @@ class ShareInstancesController(wsgi.Controller):
|
|||||||
|
|
||||||
|
|
||||||
def create_resource():
|
def create_resource():
|
||||||
return wsgi.Resource(ShareInstancesController())
|
return wsgi.Resource(ShareInstancesController())
|
||||||
|
31
manila/api/views/availability_zones.py
Normal file
31
manila/api/views/availability_zones.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Copyright (c) 2015 Mirantis inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 manila.api import common
|
||||||
|
|
||||||
|
|
||||||
|
class ViewBuilder(common.ViewBuilder):
|
||||||
|
|
||||||
|
_collection_name = "availability_zones"
|
||||||
|
|
||||||
|
def _detail(self, availability_zone):
|
||||||
|
"""Detailed view of an single availability zone."""
|
||||||
|
keys = ('id', 'name', 'created_at', 'updated_at')
|
||||||
|
return {key: availability_zone.get(key) for key in keys}
|
||||||
|
|
||||||
|
def detail_list(self, availability_zones):
|
||||||
|
"""Detailed view of a list of availability zones."""
|
||||||
|
azs = [self._detail(az) for az in availability_zones]
|
||||||
|
return {self._collection_name: azs}
|
@ -1,38 +0,0 @@
|
|||||||
# Copyright 2015 Mirantis Inc.
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
import mock
|
|
||||||
|
|
||||||
from manila.api.contrib import availability_zones
|
|
||||||
from manila import db
|
|
||||||
from manila import test
|
|
||||||
from manila.tests.api import fakes
|
|
||||||
|
|
||||||
|
|
||||||
class AvailabilityZonesApiTest(test.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(AvailabilityZonesApiTest, self).setUp()
|
|
||||||
self.controller = availability_zones.Controller()
|
|
||||||
|
|
||||||
def test_index(self):
|
|
||||||
fake_az = [{'test': 'test'}]
|
|
||||||
self.mock_object(db, 'availability_zone_get_all',
|
|
||||||
mock.Mock(return_value=fake_az))
|
|
||||||
req = fakes.HTTPRequest.blank('/v2/fake/types/1')
|
|
||||||
|
|
||||||
actual_result = self.controller.index(req)
|
|
||||||
|
|
||||||
self.assertDictMatch({'availability_zones': fake_az}, actual_result)
|
|
||||||
db.availability_zone_get_all.assert_called_once_with(mock.ANY)
|
|
71
manila/tests/api/v1/test_availability_zones.py
Normal file
71
manila/tests/api/v1/test_availability_zones.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# Copyright (c) 2015 Mirantis inc.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import ddt
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from manila.api.v1 import availability_zones
|
||||||
|
from manila import context
|
||||||
|
from manila import test
|
||||||
|
from manila.tests.api import fakes
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class AvailabilityZonesAPITest(test.TestCase):
|
||||||
|
|
||||||
|
def test_instantiate_controller(self):
|
||||||
|
controller = availability_zones.AvailabilityZoneController()
|
||||||
|
|
||||||
|
self.assertTrue(hasattr(controller, "resource_name"))
|
||||||
|
self.assertEqual("availability_zone", controller.resource_name)
|
||||||
|
self.assertTrue(hasattr(controller, "_view_builder"))
|
||||||
|
self.assertTrue(hasattr(controller._view_builder, "detail_list"))
|
||||||
|
|
||||||
|
@ddt.data('1.0', '2.0', '2.6')
|
||||||
|
def test_index(self, version):
|
||||||
|
azs = [
|
||||||
|
{
|
||||||
|
"id": "fake_id1",
|
||||||
|
"name": "fake_name1",
|
||||||
|
"created_at": "fake_created_at",
|
||||||
|
"updated_at": "fake_updated_at",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "fake_id2",
|
||||||
|
"name": "fake_name2",
|
||||||
|
"created_at": "fake_created_at",
|
||||||
|
"updated_at": "fake_updated_at",
|
||||||
|
"deleted": "False",
|
||||||
|
"redundant_key": "redundant_value",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
self.mock_object(availability_zones.db, 'availability_zone_get_all',
|
||||||
|
mock.Mock(return_value=azs))
|
||||||
|
controller = availability_zones.AvailabilityZoneController()
|
||||||
|
ctxt = context.RequestContext("admin", "fake", True)
|
||||||
|
req = fakes.HTTPRequest.blank('/shares', version=version)
|
||||||
|
req.environ['manila.context'] = ctxt
|
||||||
|
|
||||||
|
result = controller.index(req)
|
||||||
|
|
||||||
|
availability_zones.db.availability_zone_get_all.\
|
||||||
|
assert_called_once_with(ctxt)
|
||||||
|
self.assertTrue(isinstance(result, dict))
|
||||||
|
self.assertEqual(["availability_zones"], list(result.keys()))
|
||||||
|
self.assertTrue(isinstance(result["availability_zones"], list))
|
||||||
|
self.assertEqual(2, len(result["availability_zones"]))
|
||||||
|
self.assertTrue(azs[0] in result["availability_zones"])
|
||||||
|
azs[1].pop("deleted")
|
||||||
|
azs[1].pop("redundant_key")
|
||||||
|
self.assertTrue(azs[1] in result["availability_zones"])
|
@ -4,6 +4,8 @@
|
|||||||
"admin_or_owner": "is_admin:True or project_id:%(project_id)s",
|
"admin_or_owner": "is_admin:True or project_id:%(project_id)s",
|
||||||
"default": "rule:admin_or_owner",
|
"default": "rule:admin_or_owner",
|
||||||
|
|
||||||
|
"availability_zone:index": "rule:default",
|
||||||
|
|
||||||
"share:create": "",
|
"share:create": "",
|
||||||
"share:list_by_share_server_id": "rule:admin_api",
|
"share:list_by_share_server_id": "rule:admin_api",
|
||||||
"share:get": "",
|
"share:get": "",
|
||||||
|
@ -24,10 +24,13 @@ class AvailabilityZonesTest(base.BaseSharesTest):
|
|||||||
self.assertTrue(len(availability_zones) > 0)
|
self.assertTrue(len(availability_zones) > 0)
|
||||||
keys = ("created_at", "updated_at", "name", "id")
|
keys = ("created_at", "updated_at", "name", "id")
|
||||||
for az in availability_zones:
|
for az in availability_zones:
|
||||||
|
self.assertEqual(len(keys), len(az))
|
||||||
for key in keys:
|
for key in keys:
|
||||||
self.assertIn(key, az)
|
self.assertIn(key, az)
|
||||||
|
|
||||||
@test.attr(type=["smoke", "gate"])
|
@test.attr(type=["smoke", "gate"])
|
||||||
def test_list_availability_zones_extension(self):
|
def test_list_availability_zones_extension_url(self):
|
||||||
|
# NOTE(vponomaryov): remove this test with removal of availability zone
|
||||||
|
# extension url support.
|
||||||
azs = self.shares_client.list_availability_zones()
|
azs = self.shares_client.list_availability_zones()
|
||||||
self._list_availability_zones_assertions(azs)
|
self._list_availability_zones_assertions(azs)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user