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:
parent
2d41233814
commit
66158c6c06
|
@ -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
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
Loading…
Reference in New Issue