Add policy_validate function to engine

This function will do a deep check to policy properties.

Change-Id: Ie633a732ad69792ad6bd1516a250a071c71b4eef
This commit is contained in:
Ethan Lynn 2016-08-22 16:39:22 +08:00
parent c853a4e8cb
commit c167430eaf
4 changed files with 101 additions and 31 deletions

View File

@ -566,6 +566,44 @@ class EngineService(service.Service):
project_safe=project_safe)
return [p.to_dict() for p in policies]
@request_context
def _validate_policy(self, context, spec, name=None, validate_props=False):
"""Validate a policy.
:param context: An instance of the request context.
:param spec: A dictionary containing the spec for the policy.
:param name: The name for the policy to be created.
:param validate_props: Whether to validate the value of property.
:return: Validated policy object.
"""
type_name, version = schema.get_spec_version(spec)
type_str = "-".join([type_name, version])
try:
plugin = environment.global_env().get_policy(type_str)
except exception.PolicyTypeNotFound:
msg = _("The specified policy type (%(name)s) is not found."
) % {"name": type_str}
raise exception.SpecValidationFailed(message=msg)
kwargs = {
'user': context.user,
'project': context.project,
'domain': context.domain,
}
if name is None:
name = 'validated_policy'
policy = plugin(name, spec, **kwargs)
try:
policy.validate(validate_props=validate_props)
except exception.InvalidSpec as ex:
msg = six.text_type(ex)
LOG.error(_LE("Failed in validating policy: %s"), msg)
raise exception.SpecValidationFailed(message=msg)
return policy
@request_context
def policy_create(self, context, name, spec):
"""Create a policy with the given name and spec.
@ -582,31 +620,10 @@ class EngineService(service.Service):
) % {"name": name}
raise exception.BadRequest(msg=msg)
type_name, version = schema.get_spec_version(spec)
type_str = "-".join([type_name, version])
try:
plugin = environment.global_env().get_policy(type_str)
except exception.PolicyTypeNotFound:
msg = _("The specified policy type (%(name)s) is not found."
) % {"name": type_str}
raise exception.BadRequest(msg=msg)
policy = self._validate_policy(context, spec, name=name)
LOG.info(_LI("Creating policy %(type)s '%(name)s'"),
{'type': type_str, 'name': name})
kwargs = {
'user': context.user,
'project': context.project,
'domain': context.domain,
}
policy = plugin(name, spec, **kwargs)
try:
policy.validate()
except exception.InvalidSpec as ex:
msg = six.text_type(ex)
LOG.error(_LE("Failed in creating policy: %s"), msg)
raise exception.BadRequest(msg=msg)
{'type': policy.type, 'name': policy.name})
policy.store(context)
LOG.info(_LI("Policy '%(name)s' is created: %(id)s."),
@ -672,6 +689,19 @@ class EngineService(service.Service):
LOG.info(_LI("Policy '%s' is deleted."), identity)
@request_context
def policy_validate(self, context, spec):
"""Validate a policy with the given properties.
:param context: An instance of the request context.
:param spec: A dictionary containing the spec for the policy.
:return: A dictionary containing the details of the policy object
validated.
"""
policy = self._validate_policy(context, spec, validate_props=True)
return policy.to_dict()
def cluster_find(self, context, identity, project_safe=True):
"""Find a cluster with the given identity.

View File

@ -191,7 +191,7 @@ class Policy(object):
return self.id
def validate(self):
def validate(self, validate_props=False):
'''Validate the schema and the data provided.'''
self.spec_data.validate()
self.properties.validate()

View File

@ -268,11 +268,13 @@ class LoadBalancingPolicy(base.Policy):
self.validate()
self.lb = None
def validate(self):
def validate(self, validate_props=False):
super(LoadBalancingPolicy, self).validate()
# validate subnet's exists
# subnet = self.nc.subnet_get(vip[self.VIP_SUBNET])
# TODO(elynn): Check if subnet exists
if validate_props:
pass
# subnet = self.nc.subnet_get(vip[self.VIP_SUBNET])
def attach(self, cluster):
"""Routine to be invoked when policy is to be attached to a cluster.

View File

@ -247,8 +247,8 @@ class PolicyTest(base.SenlinTestCase):
self.eng.policy_create,
self.ctx, 'p-2', spec)
self.assertEqual(exc.BadRequest, ex.exc_info[0])
self.assertEqual("The request is malformed: The specified policy "
self.assertEqual(exc.SpecValidationFailed, ex.exc_info[0])
self.assertEqual("The specified policy "
"type (FakePolicy-1.0) is not found.",
six.text_type(ex.exc_info[1]))
@ -275,8 +275,46 @@ class PolicyTest(base.SenlinTestCase):
ex = self.assertRaises(rpc.ExpectedException,
self.eng.policy_create,
self.ctx, 'p-2', self.spec)
self.assertEqual(exc.BadRequest, ex.exc_info[0])
self.assertEqual('The request is malformed: BOOM',
self.assertEqual(exc.SpecValidationFailed, ex.exc_info[0])
self.assertEqual('BOOM',
six.text_type(ex.exc_info[1]))
def test_policy_validate_pass(self):
self._setup_fakes()
expected_resp = {
'created_at': None,
'domain': '',
'id': None,
'data': {},
'name': 'validated_policy',
'project': 'policy_test_project',
'type': 'TestPolicy-1.0',
'updated_at': None,
'user': 'test_user_id',
'spec': {
'type': 'TestPolicy',
'version': '1.0',
'properties': {
'KEY2': 6
}
}
}
resp = self.eng.policy_validate(self.ctx, self.spec)
self.assertEqual(expected_resp, resp)
def test_policy_validate_failed(self):
self._setup_fakes()
mock_validate = self.patchobject(fakes.TestPolicy, 'validate')
mock_validate.side_effect = exc.SpecValidationFailed(message='BOOM')
ex = self.assertRaises(rpc.ExpectedException,
self.eng.policy_validate,
self.ctx, self.spec)
self.assertEqual(exc.SpecValidationFailed, ex.exc_info[0])
self.assertEqual('BOOM',
six.text_type(ex.exc_info[1]))
@mock.patch.object(pb.Policy, 'load')