Validate bay type on creating resources
Ensure k8s resource (i.e. Pod/Service/RC) to be created only on a k8s bay, and docker swarm resource (i.e. Container) to be created only on a swarm bay. Also, return a 400 error if the bay type is not matched. Change-Id: I88b747c590f13a2e0da2bd59f1b0cbcc389d9b14 Closes-Bug: 1470963
This commit is contained in:
parent
eb7abda967
commit
f6963a52c6
|
@ -27,6 +27,7 @@ from magnum.api.controllers import link
|
|||
from magnum.api.controllers.v1 import collection
|
||||
from magnum.api.controllers.v1 import types
|
||||
from magnum.api.controllers.v1 import utils as api_utils
|
||||
from magnum.api import validation
|
||||
from magnum.common import exception
|
||||
from magnum import objects
|
||||
|
||||
|
@ -346,6 +347,7 @@ class ContainersController(rest.RestController):
|
|||
return Container.convert_with_links(res_container)
|
||||
|
||||
@wsme_pecan.wsexpose(Container, body=Container, status_code=201)
|
||||
@validation.enforce_bay_types('swarm')
|
||||
def post(self, container):
|
||||
"""Create a new container.
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ from magnum.api.controllers.v1 import base as v1_base
|
|||
from magnum.api.controllers.v1 import collection
|
||||
from magnum.api.controllers.v1 import types
|
||||
from magnum.api.controllers.v1 import utils as api_utils
|
||||
from magnum.api import validation
|
||||
from magnum.common import exception
|
||||
from magnum.common import k8s_manifest
|
||||
from magnum import objects
|
||||
|
@ -249,6 +250,7 @@ class PodsController(rest.RestController):
|
|||
return Pod.convert_with_links(rpc_pod)
|
||||
|
||||
@wsme_pecan.wsexpose(Pod, body=Pod, status_code=201)
|
||||
@validation.enforce_bay_types('kubernetes')
|
||||
def post(self, pod):
|
||||
"""Create a new pod.
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ from magnum.api.controllers.v1 import base as v1_base
|
|||
from magnum.api.controllers.v1 import collection
|
||||
from magnum.api.controllers.v1 import types
|
||||
from magnum.api.controllers.v1 import utils as api_utils
|
||||
from magnum.api import validation
|
||||
from magnum.common import exception
|
||||
from magnum.common import k8s_manifest
|
||||
from magnum import objects
|
||||
|
@ -283,6 +284,7 @@ class ReplicationControllersController(rest.RestController):
|
|||
|
||||
@wsme_pecan.wsexpose(ReplicationController, body=ReplicationController,
|
||||
status_code=201)
|
||||
@validation.enforce_bay_types('kubernetes')
|
||||
def post(self, rc):
|
||||
"""Create a new ReplicationController.
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ from magnum.api.controllers.v1 import base as v1_base
|
|||
from magnum.api.controllers.v1 import collection
|
||||
from magnum.api.controllers.v1 import types
|
||||
from magnum.api.controllers.v1 import utils as api_utils
|
||||
from magnum.api import validation
|
||||
from magnum.common import exception
|
||||
from magnum.common import k8s_manifest
|
||||
from magnum import objects
|
||||
|
@ -260,6 +261,7 @@ class ServicesController(rest.RestController):
|
|||
return Service.convert_with_links(rpc_service)
|
||||
|
||||
@wsme_pecan.wsexpose(Service, body=Service, status_code=201)
|
||||
@validation.enforce_bay_types('kubernetes')
|
||||
def post(self, service):
|
||||
"""Create a new service.
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
# Copyright 2015 Huawei Technologies Co.,LTD.
|
||||
#
|
||||
# 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 decorator
|
||||
import pecan
|
||||
|
||||
from magnum.common import exception
|
||||
from magnum import objects
|
||||
|
||||
|
||||
def enforce_bay_types(*bay_types):
|
||||
def decorate(func):
|
||||
@decorator.decorator
|
||||
def handler(func, *args, **kwargs):
|
||||
obj = args[1]
|
||||
bay = objects.Bay.get_by_uuid(pecan.request.context, obj.bay_uuid)
|
||||
baymodel = objects.BayModel.get_by_uuid(pecan.request.context,
|
||||
bay.baymodel_id)
|
||||
if baymodel.coe not in bay_types:
|
||||
raise exception.InvalidParameterValue(
|
||||
'cannot fulfill request with a %(bay_type)s bay, '
|
||||
'expecting a %(supported_bay_types)s bay.' %
|
||||
{'bay_type': baymodel.coe,
|
||||
'supported_bay_types': '/'.join(bay_types)})
|
||||
|
||||
return func(*args, **kwargs)
|
||||
return handler(func)
|
||||
|
||||
return decorate
|
|
@ -22,14 +22,18 @@ from webtest.app import AppError
|
|||
class TestContainerController(db_base.DbTestCase):
|
||||
def setUp(self):
|
||||
super(TestContainerController, self).setUp()
|
||||
self.bay_get_by_uuid_patch = patch('magnum.objects.Bay.get_by_uuid')
|
||||
self.mock_bay_get_by_uuid = self.bay_get_by_uuid_patch.start()
|
||||
self.addCleanup(self.bay_get_by_uuid_patch.stop)
|
||||
p = patch('magnum.objects.Bay.get_by_uuid')
|
||||
self.mock_bay_get_by_uuid = p.start()
|
||||
self.addCleanup(p.stop)
|
||||
p = patch('magnum.objects.BayModel.get_by_uuid')
|
||||
self.mock_baymodel_get_by_uuid = p.start()
|
||||
self.addCleanup(p.stop)
|
||||
|
||||
def fake_get_by_uuid(context, uuid):
|
||||
return objects.Bay(self.context, **utils.get_test_bay(uuid=uuid))
|
||||
|
||||
self.mock_bay_get_by_uuid.side_effect = fake_get_by_uuid
|
||||
self.mock_baymodel_get_by_uuid.return_value.coe = 'swarm'
|
||||
|
||||
@patch('magnum.conductor.api.API.container_create')
|
||||
def test_create_container(self, mock_container_create,):
|
||||
|
|
|
@ -371,6 +371,10 @@ class TestPost(api_base.FunctionalTest):
|
|||
self.mock_pod_create = p.start()
|
||||
self.mock_pod_create.side_effect = self._simulate_rpc_pod_create
|
||||
self.addCleanup(p.stop)
|
||||
p = mock.patch('magnum.objects.BayModel.get_by_uuid')
|
||||
self.mock_baymodel_get_by_uuid = p.start()
|
||||
self.mock_baymodel_get_by_uuid.return_value.coe = 'kubernetes'
|
||||
self.addCleanup(p.stop)
|
||||
|
||||
def _simulate_rpc_pod_create(self, pod):
|
||||
pod.create()
|
||||
|
|
|
@ -358,6 +358,10 @@ class TestPost(api_base.FunctionalTest):
|
|||
self.mock_rc_create = p.start()
|
||||
self.mock_rc_create.side_effect = self._simulate_rpc_rc_create
|
||||
self.addCleanup(p.stop)
|
||||
p = mock.patch('magnum.objects.BayModel.get_by_uuid')
|
||||
self.mock_baymodel_get_by_uuid = p.start()
|
||||
self.mock_baymodel_get_by_uuid.return_value.coe = 'kubernetes'
|
||||
self.addCleanup(p.stop)
|
||||
|
||||
def _simulate_rpc_rc_create(self, rc):
|
||||
rc.create(self.context)
|
||||
|
|
|
@ -311,6 +311,10 @@ class TestPost(api_base.FunctionalTest):
|
|||
self.mock_service_create.side_effect = (
|
||||
self._simulate_rpc_service_create)
|
||||
self.addCleanup(p.stop)
|
||||
p = mock.patch('magnum.objects.BayModel.get_by_uuid')
|
||||
self.mock_baymodel_get_by_uuid = p.start()
|
||||
self.mock_baymodel_get_by_uuid.return_value.coe = 'kubernetes'
|
||||
self.addCleanup(p.stop)
|
||||
|
||||
def _simulate_rpc_service_create(self, service):
|
||||
service.create()
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
# Copyright 2015 Huawei Technologies Co.,LTD.
|
||||
#
|
||||
# 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 magnum.api import validation as v
|
||||
from magnum.common import exception
|
||||
from magnum.tests import base
|
||||
|
||||
|
||||
class TestValidation(base.BaseTestCase):
|
||||
|
||||
def _test_enforce_bay_types(
|
||||
self,
|
||||
mock_bay_get_by_uuid,
|
||||
mock_baymodel_get_by_uuid,
|
||||
mock_pecan_request,
|
||||
bay_type,
|
||||
allowed_bay_types,
|
||||
assert_raised=False):
|
||||
|
||||
@v.enforce_bay_types(*allowed_bay_types)
|
||||
def test(self, obj):
|
||||
return obj.name
|
||||
|
||||
context = mock_pecan_request.context
|
||||
obj = mock.MagicMock()
|
||||
obj.name = 'test_object'
|
||||
obj.bay_uuid = 'bay_uuid'
|
||||
bay = mock.MagicMock()
|
||||
bay.baymodel_id = 'baymodel_id'
|
||||
baymodel = mock.MagicMock()
|
||||
baymodel.coe = bay_type
|
||||
|
||||
mock_bay_get_by_uuid.return_value = bay
|
||||
mock_baymodel_get_by_uuid.return_value = baymodel
|
||||
|
||||
if assert_raised:
|
||||
self.assertRaises(exception.InvalidParameterValue, test, self, obj)
|
||||
else:
|
||||
ret = test(self, obj)
|
||||
mock_bay_get_by_uuid.assert_called_once_with(context, 'bay_uuid')
|
||||
mock_baymodel_get_by_uuid.assert_called_once_with(
|
||||
context, 'baymodel_id')
|
||||
self.assertEqual(ret, 'test_object')
|
||||
|
||||
@mock.patch('pecan.request')
|
||||
@mock.patch('magnum.objects.BayModel.get_by_uuid')
|
||||
@mock.patch('magnum.objects.Bay.get_by_uuid')
|
||||
def test_enforce_bay_types_one_allowed(
|
||||
self,
|
||||
mock_bay_get_by_uuid,
|
||||
mock_baymodel_get_by_uuid,
|
||||
mock_pecan_request):
|
||||
|
||||
bay_type = 'type1'
|
||||
allowed_bay_types = ['type1']
|
||||
self._test_enforce_bay_types(
|
||||
mock_bay_get_by_uuid, mock_baymodel_get_by_uuid,
|
||||
mock_pecan_request, bay_type, allowed_bay_types)
|
||||
|
||||
@mock.patch('pecan.request')
|
||||
@mock.patch('magnum.objects.BayModel.get_by_uuid')
|
||||
@mock.patch('magnum.objects.Bay.get_by_uuid')
|
||||
def test_enforce_bay_types_two_allowed(
|
||||
self,
|
||||
mock_bay_get_by_uuid,
|
||||
mock_baymodel_get_by_uuid,
|
||||
mock_pecan_request):
|
||||
|
||||
bay_type = 'type1'
|
||||
allowed_bay_types = ['type1', 'type2']
|
||||
self._test_enforce_bay_types(
|
||||
mock_bay_get_by_uuid, mock_baymodel_get_by_uuid,
|
||||
mock_pecan_request, bay_type, allowed_bay_types)
|
||||
|
||||
@mock.patch('pecan.request')
|
||||
@mock.patch('magnum.objects.BayModel.get_by_uuid')
|
||||
@mock.patch('magnum.objects.Bay.get_by_uuid')
|
||||
def test_enforce_bay_types_not_allowed(
|
||||
self,
|
||||
mock_bay_get_by_uuid,
|
||||
mock_baymodel_get_by_uuid,
|
||||
mock_pecan_request):
|
||||
|
||||
bay_type = 'type1'
|
||||
allowed_bay_types = ['type2']
|
||||
self._test_enforce_bay_types(
|
||||
mock_bay_get_by_uuid, mock_baymodel_get_by_uuid,
|
||||
mock_pecan_request, bay_type, allowed_bay_types,
|
||||
assert_raised=True)
|
Loading…
Reference in New Issue