diff --git a/heat/engine/resource.py b/heat/engine/resource.py index 999ebda549..777929c089 100644 --- a/heat/engine/resource.py +++ b/heat/engine/resource.py @@ -155,9 +155,13 @@ class Resource(object): return super(Resource, cls).__new__(ResourceClass) def __init__(self, name, definition, stack): - if '/' in name: - raise ValueError(_('Resource name may not contain "/"')) + def _validate_name(res_name): + if '/' in res_name: + message = _('Resource name may not contain "/"') + raise exception.StackValidationFailed(message=message) + + _validate_name(name) self.stack = stack self.context = stack.context self.name = name diff --git a/heat/engine/stack.py b/heat/engine/stack.py index 3a69319e89..e033c59a34 100644 --- a/heat/engine/stack.py +++ b/heat/engine/stack.py @@ -86,12 +86,15 @@ class Stack(collections.Mapping): stack is already in the database. ''' + def _validate_stack_name(name): + if not re.match("[a-zA-Z][a-zA-Z0-9_.-]*$", name): + message = _('Invalid stack name %s must contain ' + 'only alphanumeric or \"_-.\" characters, ' + 'must start with alpha') % name + raise exception.StackValidationFailed(message=message) + if owner_id is None: - if re.match("[a-zA-Z][a-zA-Z0-9_.-]*$", stack_name) is None: - raise ValueError(_('Invalid stack name %s' - ' must contain only alphanumeric or ' - '\"_-.\" characters, must start with alpha' - ) % stack_name) + _validate_stack_name(stack_name) self.id = stack_id self.owner_id = owner_id diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index 27e590300a..e5687f41d7 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -592,7 +592,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase): stack_name = 'service_create/test_stack' stack = get_wordpress_stack('test_stack', self.ctx) - self.assertRaises(ValueError, + self.assertRaises(dispatcher.ExpectedException, self.man.create_stack, self.ctx, stack_name, stack.t.t, {}, None, {}) @@ -603,7 +603,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase): tmpl['Resources']['Web/Server'] = tmpl['Resources']['WebServer'] del tmpl['Resources']['WebServer'] - self.assertRaises(ValueError, + self.assertRaises(dispatcher.ExpectedException, self.man.create_stack, self.ctx, stack_name, stack.t.t, {}, None, {}) diff --git a/heat/tests/test_parser.py b/heat/tests/test_parser.py index b6e89b99f6..dbc4fd9e38 100644 --- a/heat/tests/test_parser.py +++ b/heat/tests/test_parser.py @@ -3671,38 +3671,13 @@ class StackTest(common.HeatTestCase): self.assertIsInstance(stack, parser.Stack) def test_stack_name_invalid(self): - self.assertRaises(ValueError, parser.Stack, self.ctx, '_foo', - self.tmpl) - self.assertRaises(ValueError, parser.Stack, self.ctx, '1bad', - self.tmpl) - self.assertRaises(ValueError, parser.Stack, self.ctx, '.kcats', - self.tmpl) - self.assertRaises(ValueError, parser.Stack, self.ctx, 'test stack', - self.tmpl) - self.assertRaises(ValueError, parser.Stack, self.ctx, ' teststack', - self.tmpl) - self.assertRaises(ValueError, parser.Stack, self.ctx, '^-^', - self.tmpl) - self.assertRaises(ValueError, parser.Stack, self.ctx, '\"stack\"', - self.tmpl) - self.assertRaises(ValueError, parser.Stack, self.ctx, '1234', - self.tmpl) - self.assertRaises(ValueError, parser.Stack, self.ctx, 'cat|dog', - self.tmpl) - self.assertRaises(ValueError, parser.Stack, self.ctx, '$(foo)', - self.tmpl) - self.assertRaises(ValueError, parser.Stack, self.ctx, 'test/stack', - self.tmpl) - self.assertRaises(ValueError, parser.Stack, self.ctx, 'test\stack', - self.tmpl) - self.assertRaises(ValueError, parser.Stack, self.ctx, 'test::stack', - self.tmpl) - self.assertRaises(ValueError, parser.Stack, self.ctx, 'test;stack', - self.tmpl) - self.assertRaises(ValueError, parser.Stack, self.ctx, 'test~stack', - self.tmpl) - self.assertRaises(ValueError, parser.Stack, self.ctx, '#test', - self.tmpl) + stack_names = ['_foo', '1bad', '.kcats', 'test stack', ' teststack', + '^-^', '\"stack\"', '1234', 'cat|dog', '$(foo)', + 'test/stack', 'test\stack', 'test::stack', 'test;stack', + 'test~stack', '#test'] + for stack_name in stack_names: + self.assertRaises(exception.StackValidationFailed, parser.Stack, + self.ctx, stack_name, self.tmpl) def test_resource_state_get_att(self): tmpl = { diff --git a/heat/tests/test_resource.py b/heat/tests/test_resource.py index 65eeb754d7..7a7c24225b 100644 --- a/heat/tests/test_resource.py +++ b/heat/tests/test_resource.py @@ -80,6 +80,15 @@ class ResourceTest(common.HeatTestCase): self.assertIsInstance(res, generic_rsrc.GenericResource) self.assertEqual("INIT", res.action) + def test_resource_invalid_name(self): + snippet = rsrc_defn.ResourceDefinition('wrong/name', + 'GenericResourceType') + ex = self.assertRaises(exception.StackValidationFailed, + resource.Resource, 'wrong/name', + snippet, self.stack) + self.assertEqual('Resource name may not contain "/"', + six.text_type(ex)) + def test_resource_new_stack_not_stored(self): snippet = rsrc_defn.ResourceDefinition('aresource', 'GenericResourceType')