diff options
author | Vijendar Komalla <vijendar.komalla@RACKSPACE.COM> | 2014-09-30 13:38:52 -0500 |
---|---|---|
committer | Zane Bitter <zbitter@redhat.com> | 2014-10-08 10:07:36 -0400 |
commit | 1eee0560548cafe7ca7ee533f46dfbae9a7681d2 (patch) | |
tree | e84cd9504cc0080d5a6ba111d8d2798048098e87 | |
parent | bd71400191ec117d2df2b85c6771da3145dc273d (diff) | |
download | heat-1eee0560548cafe7ca7ee533f46dfbae9a7681d2.tar.gz |
Template not required on stack-adopt
With this change, template is not required on stack-adopt and
also parameters from the original stack are adopted.
Change-Id: Id5a28400bb8e27a3b852f12d9af4c2dc7c144725
Closes-Bug: #1300336
(cherry picked from commit 8c54f483189fef2799357457c3b1e8bc0f9e87c5)
-rw-r--r-- | heat/api/openstack/v1/stacks.py | 20 | ||||
-rw-r--r-- | heat/engine/service.py | 7 | ||||
-rw-r--r-- | heat/tests/test_api_openstack_v1.py | 79 | ||||
-rw-r--r-- | heat/tests/test_engine_service.py | 33 |
4 files changed, 136 insertions, 3 deletions
diff --git a/heat/api/openstack/v1/stacks.py b/heat/api/openstack/v1/stacks.py index 0dcc66474..63944f3f1 100644 --- a/heat/api/openstack/v1/stacks.py +++ b/heat/api/openstack/v1/stacks.py @@ -94,10 +94,24 @@ class InstantiationData(object): def template(self): """ - Get template file contents, either inline or from a URL, in JSON - or YAML format. + Get template file contents, either inline, from stack adopt data or + from a URL, in JSON or YAML format. """ - if self.PARAM_TEMPLATE in self.data: + if engine_api.PARAM_ADOPT_STACK_DATA in self.data: + adopt_data = self.data[engine_api.PARAM_ADOPT_STACK_DATA] + try: + adopt_data = template_format.simple_parse(adopt_data) + + if not isinstance(adopt_data, dict): + raise exc.HTTPBadRequest( + _('Adopt data %s invalid. Adopt data must be a dict.') + % adopt_data) + + return adopt_data['template'] + except (ValueError, KeyError) as ex: + err_reason = _('Invalid data: %s') % ex + raise exc.HTTPBadRequest(err_reason) + elif self.PARAM_TEMPLATE in self.data: template_data = self.data[self.PARAM_TEMPLATE] if isinstance(template_data, dict): return template_data diff --git a/heat/engine/service.py b/heat/engine/service.py index aaa098f92..cd3ab0730 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -535,7 +535,14 @@ class EngineService(service.Service): tmpl = templatem.Template(template, files=files) self._validate_new_stack(cnxt, stack_name, tmpl) + # If it is stack-adopt, use parameters from adopt_stack_data common_params = api.extract_args(args) + + if rpc_api.PARAM_ADOPT_STACK_DATA in common_params: + params[rpc_api.STACK_PARAMETERS] = common_params[ + rpc_api.PARAM_ADOPT_STACK_DATA]['environment'][ + rpc_api.STACK_PARAMETERS] + env = environment.Environment(params) stack = parser.Stack(cnxt, stack_name, tmpl, env, owner_id=owner_id, diff --git a/heat/tests/test_api_openstack_v1.py b/heat/tests/test_api_openstack_v1.py index 6b935ee18..0352a8f14 100644 --- a/heat/tests/test_api_openstack_v1.py +++ b/heat/tests/test_api_openstack_v1.py @@ -728,6 +728,85 @@ class StackControllerTest(ControllerTest, HeatTestCase): self.m.VerifyAll() + def test_adopt(self, mock_enforce): + self._mock_enforce_setup(mock_enforce, 'create', True) + identity = identifier.HeatIdentifier(self.tenant, 'wordpress', '1') + template = { + "heat_template_version": "2013-05-23", + "parameters": {"app_dbx": {"type": "string"}}, + "resources": {"res1": {"type": "GenericResourceType"}}} + + parameters = {"app_dbx": "test"} + adopt_data = { + "status": "COMPLETE", + "name": "rtrove1", + "parameters": parameters, + "template": template, + "action": "CREATE", + "id": "8532f0d3-ea84-444e-b2bb-2543bb1496a4", + "resources": {"res1": { + "status": "COMPLETE", + "name": "database_password", + "resource_id": "yBpuUROjfGQ2gKOD", + "action": "CREATE", + "type": "GenericResourceType", + "metadata": {}}}} + body = {'template': None, + 'stack_name': identity.stack_name, + 'parameters': parameters, + 'timeout_mins': 30, + 'adopt_stack_data': str(adopt_data)} + + req = self._post('/stacks', json.dumps(body)) + + self.m.StubOutWithMock(rpc_client.EngineClient, 'call') + rpc_client.EngineClient.call( + req.context, + ('create_stack', + {'stack_name': identity.stack_name, + 'template': template, + 'params': {'parameters': parameters, + 'resource_registry': {}}, + 'files': {}, + 'args': {'timeout_mins': 30, + 'adopt_stack_data': str(adopt_data)}, + 'owner_id': None}) + ).AndReturn(dict(identity)) + self.m.ReplayAll() + + response = self.controller.create(req, + tenant_id=identity.tenant, + body=body) + + expected = {'stack': + {'id': '1', + 'links': [{'href': self._url(identity), 'rel': 'self'}]}} + self.assertEqual(expected, response) + self.m.VerifyAll() + + def test_adopt_error(self, mock_enforce): + self._mock_enforce_setup(mock_enforce, 'create', True) + identity = identifier.HeatIdentifier(self.tenant, 'wordpress', '1') + parameters = {"app_dbx": "test"} + adopt_data = ["Test"] + body = {'template': None, + 'stack_name': identity.stack_name, + 'parameters': parameters, + 'timeout_mins': 30, + 'adopt_stack_data': str(adopt_data)} + + req = self._post('/stacks', json.dumps(body)) + + self.m.ReplayAll() + resp = request_with_middleware(fault.FaultWrapper, + self.controller.create, + req, tenant_id=self.tenant, + body=body) + self.assertEqual(400, resp.status_code) + self.assertEqual('400 Bad Request', resp.status) + self.assertIn('Adopt data must be a dict.', resp.text) + self.m.VerifyAll() + def test_create_with_files(self, mock_enforce): self._mock_enforce_setup(mock_enforce, 'create', True) identity = identifier.HeatIdentifier(self.tenant, 'wordpress', '1') diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index 15362df44..a9e55f67f 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -546,6 +546,39 @@ class StackServiceCreateUpdateDeleteTest(HeatTestCase): self.assertEqual(ex.exc_info[0], exception.StackValidationFailed) self.m.VerifyAll() + def test_stack_adopt_with_params(self): + template = { + "heat_template_version": "2013-05-23", + "parameters": {"app_dbx": {"type": "string"}}, + "resources": {"res1": {"type": "GenericResourceType"}}} + + environment = {'parameters': {"app_dbx": "test"}} + adopt_data = { + "status": "COMPLETE", + "name": "rtrove1", + "environment": environment, + "template": template, + "action": "CREATE", + "id": "8532f0d3-ea84-444e-b2bb-2543bb1496a4", + "resources": {"res1": { + "status": "COMPLETE", + "name": "database_password", + "resource_id": "yBpuUROjfGQ2gKOD", + "action": "CREATE", + "type": "GenericResourceType", + "metadata": {}}}} + + res._register_class('GenericResourceType', + generic_rsrc.GenericResource) + result = self.man.create_stack(self.ctx, "test_adopt_stack", + template, {}, None, + {'adopt_stack_data': str(adopt_data)}) + + stack = db_api.stack_get(self.ctx, result['stack_id']) + self.assertEqual(template, stack.raw_template.template) + self.assertEqual(environment['parameters'], + stack.parameters['parameters']) + def test_stack_create_invalid_stack_name(self): stack_name = 'service_create/test_stack' stack = get_wordpress_stack('test_stack', self.ctx) |