Merge "API: Move validate_properties to REST API layer"
This commit is contained in:
commit
3279334987
@ -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
|
||||
@ -321,6 +322,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']))
|
||||
|
@ -145,25 +145,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
Block a user