Include exception in custom constraints errors

This refactors constraints to use a shared base class that includes the
error message when validation errors happen.

Co-Authored-By: ala.rezmerita@cloudwatt.com
Closes-Bug: #1297371
Change-Id: Ia382f53d85d83c8c474ad8bda93c6d65f16cfca9
This commit is contained in:
Thomas Herve 2014-03-25 17:19:11 +01:00
parent 2d41233814
commit 66158c6c06
6 changed files with 63 additions and 44 deletions

View File

@ -17,6 +17,7 @@ import re
import six
from heat.engine import clients
from heat.engine import resources
from heat.common import exception
@ -508,3 +509,31 @@ class CustomConstraint(Constraint):
if not constraint:
return False
return constraint.validate(value, context)
class BaseCustomConstraint(object):
"""A base class for validation using API clients.
It will provide a better error message, and reduce a bit of duplication.
Subclass must provide `expected_exceptions` and implement
`validate_with_client`.
"""
expected_exceptions = ()
_error_message = None
def error(self, value):
if self._error_message is None:
return _("Error validating value %(value)r") % {"value": value}
return _("Error validating value %(value)r: %(message)s") % {
"value": value, "message": self._error_message}
def validate(self, value, context):
client = clients.Clients(context)
try:
self.validate_with_client(client, value)
except self.expected_exceptions as e:
self._error_message = str(e)
return False
else:
return True

View File

@ -12,20 +12,17 @@
# under the License.
from heat.common import exception
from heat.engine import clients
from heat.engine.resources import nova_utils
from heat.engine import constraints
class ImageConstraint(object):
class ImageConstraint(constraints.BaseCustomConstraint):
def validate(self, value, context):
try:
nova_client = clients.Clients(context).nova()
nova_utils.get_image_id(nova_client, value)
except exception.ImageNotFound:
return False
else:
return True
expected_exceptions = (exception.ImageNotFound,)
def validate_with_client(self, client, value):
nova_client = client.nova()
nova_utils.get_image_id(nova_client, value)
def constraint_mapping():

View File

@ -12,6 +12,7 @@
# under the License.
from heat.engine import clients
from heat.engine import constraints
from heat.engine import properties
from heat.engine.resources.neutron import neutron
@ -166,17 +167,14 @@ class Net(neutron.NeutronResource):
raise ex
class NetworkConstraint(object):
class NetworkConstraint(constraints.BaseCustomConstraint):
def validate(self, value, context):
try:
neutron_client = clients.Clients(context).neutron()
neutronV20.find_resourceid_by_name_or_id(
neutron_client, 'network', value)
except neutron_exp.NeutronClientException:
return False
else:
return True
expected_exceptions = (neutron_exp.NeutronClientException,)
def validate_with_client(self, client, value):
neutron_client = client.neutron()
neutronV20.find_resourceid_by_name_or_id(
neutron_client, 'network', value)
def constraint_mapping():

View File

@ -14,7 +14,7 @@
from novaclient import exceptions as nova_exceptions
from heat.common import exception
from heat.engine.clients import Clients
from heat.engine import constraints
from heat.engine import properties
from heat.engine import resource
from heat.engine.resources import nova_utils
@ -117,19 +117,17 @@ class KeyPair(resource.Resource):
return self.resource_id
class KeypairConstraint(object):
class KeypairConstraint(constraints.BaseCustomConstraint):
def validate(self, value, context):
expected_exceptions = (exception.UserKeyPairMissing,)
def validate_with_client(self, client, value):
if not value:
# Don't validate empty key, which can happen when you use a KeyPair
# resource
return True
try:
nova_utils.get_keypair(Clients(context).nova(), value)
except exception.UserKeyPairMissing:
return False
else:
return True
nova_client = client.nova()
nova_utils.get_keypair(nova_client, value)
def constraint_mapping():

View File

@ -1039,16 +1039,13 @@ class Server(stack_user.StackUser):
return self._check_active(server)
class FlavorConstraint(object):
class FlavorConstraint(constraints.BaseCustomConstraint):
def validate(self, value, context):
nova_client = clients.Clients(context).nova()
try:
nova_utils.get_flavor_id(nova_client, value)
except exception.FlavorMissing:
return False
else:
return True
expected_exceptions = (exception.FlavorMissing,)
def validate_with_client(self, client, value):
nova_client = client.nova()
nova_utils.get_flavor_id(nova_client, value)
def constraint_mapping():

View File

@ -292,8 +292,8 @@ class ServersTest(HeatTestCase):
error = self.assertRaises(ValueError, server.handle_create)
self.assertEqual(
'server_create_image_err: image "Slackware" does not '
'validate glance.image',
'server_create_image_err: image Error validating value '
'\'Slackware\': The Image (Slackware) could not be found.',
str(error))
self.m.VerifyAll()
@ -343,8 +343,8 @@ class ServersTest(HeatTestCase):
error = self.assertRaises(ValueError, server.handle_create)
self.assertEqual(
'server_create_image_err: image "1" does not '
'validate glance.image',
'server_create_image_err: image Error validating value \'1\': '
'The Image (1) could not be found.',
str(error))
self.m.VerifyAll()
@ -816,8 +816,8 @@ class ServersTest(HeatTestCase):
error = self.assertRaises(exception.StackValidationFailed,
server.validate)
self.assertEqual(
'Property error : server_validate_test: key_name "test2" does '
'not validate nova.keypair',
'Property error : server_validate_test: key_name Error validating '
'value \'test2\': The Key (test2) could not be found.',
str(error))
self.m.VerifyAll()