API: Move validate_properties to REST API layer
We restrict that only node_count can be modified, this can be moved into REST API layer before we send request to conductor though rpc. Besides, remove some bad test case in REST API layer Change-Id: I5a73488d0c7529ea2e1416a9e41b4893f220a25a
This commit is contained in:
parent
547780e22b
commit
f9a087e912
|
@ -26,6 +26,7 @@ from magnum.api.controllers.v1 import collection
|
|||
from magnum.api.controllers.v1 import types
|
||||
from magnum.api import expose
|
||||
from magnum.api import utils as api_utils
|
||||
from magnum.api.validation import validate_bay_properties
|
||||
from magnum.common import exception
|
||||
from magnum.common import policy
|
||||
from magnum import objects
|
||||
|
@ -325,6 +326,10 @@ class BaysController(rest.RestController):
|
|||
if rpc_bay[field] != patch_val:
|
||||
rpc_bay[field] = patch_val
|
||||
|
||||
delta = rpc_bay.obj_what_changed()
|
||||
|
||||
validate_bay_properties(delta)
|
||||
|
||||
res_bay = pecan.request.rpcapi.bay_update(rpc_bay)
|
||||
return Bay.convert_with_links(res_bay)
|
||||
|
||||
|
|
|
@ -56,6 +56,9 @@ baymodel_opts = [
|
|||
cfg.CONF.register_opts(baymodel_opts, group='baymodel')
|
||||
|
||||
|
||||
bay_update_allowed_properties = set(['node_count'])
|
||||
|
||||
|
||||
def enforce_bay_types(*bay_types):
|
||||
"""Enforce that bay_type is in supported list."""
|
||||
@decorator.decorator
|
||||
|
@ -154,6 +157,15 @@ def _enforce_volume_driver_types(baymodel):
|
|||
validator.validate_volume_driver(baymodel['volume_driver'])
|
||||
|
||||
|
||||
def validate_bay_properties(delta):
|
||||
|
||||
update_disallowed_properties = delta - bay_update_allowed_properties
|
||||
if update_disallowed_properties:
|
||||
err = (_("cannot change bay property(ies) %s.") %
|
||||
", ".join(update_disallowed_properties))
|
||||
raise exception.InvalidParameterValue(err=err)
|
||||
|
||||
|
||||
class Validator(object):
|
||||
|
||||
validators = {}
|
||||
|
|
|
@ -124,8 +124,6 @@ def _update_stack(context, osc, bay, scale_manager=None):
|
|||
|
||||
class Handler(object):
|
||||
|
||||
_update_allowed_properties = set(['node_count'])
|
||||
|
||||
def __init__(self):
|
||||
super(Handler, self).__init__()
|
||||
|
||||
|
@ -163,13 +161,6 @@ class Handler(object):
|
|||
|
||||
return bay
|
||||
|
||||
def _validate_properties(self, delta):
|
||||
update_disallowed_properties = delta - self._update_allowed_properties
|
||||
if update_disallowed_properties:
|
||||
err = (_("cannot change bay property(ies) %s.") %
|
||||
", ".join(update_disallowed_properties))
|
||||
raise exception.InvalidParameterValue(err=err)
|
||||
|
||||
def bay_update(self, context, bay):
|
||||
LOG.debug('bay_heat bay_update')
|
||||
|
||||
|
@ -194,8 +185,6 @@ class Handler(object):
|
|||
if not delta:
|
||||
return bay
|
||||
|
||||
self._validate_properties(delta)
|
||||
|
||||
manager = scale_manager.ScaleManager(context, osc, bay)
|
||||
|
||||
_update_stack(context, osc, bay, manager)
|
||||
|
|
|
@ -200,47 +200,47 @@ class TestPatch(api_base.FunctionalTest):
|
|||
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_replace_ok(self, mock_utcnow):
|
||||
name = 'bay_example_B'
|
||||
new_node_count = 4
|
||||
test_time = datetime.datetime(2000, 1, 1, 0, 0)
|
||||
mock_utcnow.return_value = test_time
|
||||
|
||||
response = self.patch_json('/bays/%s' % self.bay.uuid,
|
||||
[{'path': '/name', 'value': name,
|
||||
[{'path': '/node_count',
|
||||
'value': new_node_count,
|
||||
'op': 'replace'}])
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(200, response.status_code)
|
||||
|
||||
response = self.get_json('/bays/%s' % self.bay.uuid)
|
||||
self.assertEqual(name, response['name'])
|
||||
self.assertEqual(new_node_count, response['node_count'])
|
||||
return_updated_at = timeutils.parse_isotime(
|
||||
response['updated_at']).replace(tzinfo=None)
|
||||
self.assertEqual(test_time, return_updated_at)
|
||||
# Assert nothing else was changed
|
||||
self.assertEqual(self.bay.uuid, response['uuid'])
|
||||
self.assertEqual(self.bay.baymodel_id, response['baymodel_id'])
|
||||
self.assertEqual(self.bay.node_count, response['node_count'])
|
||||
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_replace_ok_by_name(self, mock_utcnow):
|
||||
name = 'bay_example_B'
|
||||
new_node_count = 4
|
||||
test_time = datetime.datetime(2000, 1, 1, 0, 0)
|
||||
mock_utcnow.return_value = test_time
|
||||
|
||||
response = self.patch_json('/bays/%s' % self.bay.name,
|
||||
[{'path': '/name', 'value': name,
|
||||
[{'path': '/node_count',
|
||||
'value': new_node_count,
|
||||
'op': 'replace'}])
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(200, response.status_code)
|
||||
|
||||
response = self.get_json('/bays/%s' % self.bay.uuid)
|
||||
self.assertEqual(name, response['name'])
|
||||
self.assertEqual(new_node_count, response['node_count'])
|
||||
return_updated_at = timeutils.parse_isotime(
|
||||
response['updated_at']).replace(tzinfo=None)
|
||||
self.assertEqual(test_time, return_updated_at)
|
||||
# Assert nothing else was changed
|
||||
self.assertEqual(self.bay.uuid, response['uuid'])
|
||||
self.assertEqual(self.bay.baymodel_id, response['baymodel_id'])
|
||||
self.assertEqual(self.bay.node_count, response['node_count'])
|
||||
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_replace_ok_by_name_not_found(self, mock_utcnow):
|
||||
|
@ -255,6 +255,18 @@ class TestPatch(api_base.FunctionalTest):
|
|||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(404, response.status_code)
|
||||
|
||||
def test_replace_baymodel_id_failed(self):
|
||||
baymodel = obj_utils.create_test_baymodel(self.context,
|
||||
uuid=utils.generate_uuid())
|
||||
response = self.patch_json('/bays/%s' % self.bay.uuid,
|
||||
[{'path': '/baymodel_id',
|
||||
'value': baymodel.uuid,
|
||||
'op': 'replace'}],
|
||||
expect_errors=True)
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(400, response.status_code)
|
||||
self.assertTrue(response.json['error_message'])
|
||||
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_replace_ok_by_name_multiple_bay(self, mock_utcnow):
|
||||
test_time = datetime.datetime(2000, 1, 1, 0, 0)
|
||||
|
@ -272,17 +284,6 @@ class TestPatch(api_base.FunctionalTest):
|
|||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(409, response.status_code)
|
||||
|
||||
def test_replace_baymodel_id(self):
|
||||
baymodel = obj_utils.create_test_baymodel(self.context,
|
||||
uuid=utils.generate_uuid())
|
||||
response = self.patch_json('/bays/%s' % self.bay.uuid,
|
||||
[{'path': '/baymodel_id',
|
||||
'value': baymodel.uuid,
|
||||
'op': 'replace'}],
|
||||
expect_errors=True)
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(200, response.status_code)
|
||||
|
||||
def test_replace_non_existent_baymodel_id(self):
|
||||
response = self.patch_json('/bays/%s' % self.bay.uuid,
|
||||
[{'path': '/baymodel_id',
|
||||
|
@ -312,6 +313,16 @@ class TestPatch(api_base.FunctionalTest):
|
|||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertTrue(response.json['error_message'])
|
||||
|
||||
def test_replace_bay_name_failed(self):
|
||||
response = self.patch_json('/bays/%s' % self.bay.uuid,
|
||||
[{'path': '/name',
|
||||
'value': 'bay_example_B',
|
||||
'op': 'replace'}],
|
||||
expect_errors=True)
|
||||
self.assertEqual(400, response.status_int)
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertTrue(response.json['error_message'])
|
||||
|
||||
def test_add_non_existent_property(self):
|
||||
response = self.patch_json(
|
||||
'/bays/%s' % self.bay.uuid,
|
||||
|
@ -326,16 +337,17 @@ class TestPatch(api_base.FunctionalTest):
|
|||
self.assertIsNotNone(response['name'])
|
||||
|
||||
response = self.patch_json('/bays/%s' % self.bay.uuid,
|
||||
[{'path': '/name', 'op': 'remove'}])
|
||||
[{'path': '/node_count', 'op': 'remove'}])
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(200, response.status_code)
|
||||
|
||||
response = self.get_json('/bays/%s' % self.bay.uuid)
|
||||
self.assertIsNone(response['name'])
|
||||
# only allow node_count for bay, and default value is 1
|
||||
self.assertEqual(1, response['node_count'])
|
||||
# Assert nothing else was changed
|
||||
self.assertEqual(self.bay.uuid, response['uuid'])
|
||||
self.assertEqual(self.bay.baymodel_id, response['baymodel_id'])
|
||||
self.assertEqual(self.bay.node_count, response['node_count'])
|
||||
self.assertEqual(self.bay.name, response['name'])
|
||||
self.assertEqual(self.bay.master_count, response['master_count'])
|
||||
|
||||
def test_remove_uuid(self):
|
||||
|
|
|
@ -411,3 +411,10 @@ class TestValidation(base.BaseTestCase):
|
|||
self._test_enforce_volume_driver_types_update(
|
||||
volume_driver_type='cinder',
|
||||
op='remove')
|
||||
|
||||
def test_validate_bay_properties_pass(self):
|
||||
v.validate_bay_properties(set(['node_count']))
|
||||
|
||||
def test_validate_bay_properties_failed(self):
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
v.validate_bay_properties, set(['name']))
|
||||
|
|
|
@ -146,25 +146,6 @@ class TestHandler(db_base.DbTestCase):
|
|||
def test_update_bay_status_adopt_compelete(self):
|
||||
self._test_update_bay_status_complete(bay_status.ADOPT_COMPLETE)
|
||||
|
||||
@patch('magnum.common.clients.OpenStackClients')
|
||||
def test_update_bay_with_invalid_params(
|
||||
self, mock_openstack_client_class):
|
||||
mock_heat_stack = mock.MagicMock()
|
||||
mock_heat_stack.stack_status = bay_status.CREATE_COMPLETE
|
||||
mock_heat_client = mock.MagicMock()
|
||||
mock_heat_client.stacks.get.return_value = mock_heat_stack
|
||||
mock_openstack_client = mock_openstack_client_class.return_value
|
||||
mock_openstack_client.heat.return_value = mock_heat_client
|
||||
|
||||
self.bay.node_count = 2
|
||||
self.bay.api_address = '7.7.7.7'
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
self.handler.bay_update,
|
||||
self.context,
|
||||
self.bay)
|
||||
bay = objects.Bay.get(self.context, self.bay.uuid)
|
||||
self.assertEqual(1, bay.node_count)
|
||||
|
||||
@patch('magnum.conductor.handlers.bay_conductor.HeatPoller')
|
||||
@patch('magnum.conductor.handlers.bay_conductor.cert_manager')
|
||||
@patch('magnum.conductor.handlers.bay_conductor._create_stack')
|
||||
|
|
Loading…
Reference in New Issue