From 7a307caa7d06d1daef0de043c3426e3b2af8efdb Mon Sep 17 00:00:00 2001 From: Angus Salkeld Date: Wed, 19 Jun 2013 18:54:51 +1000 Subject: [PATCH] Initial provider template uploading blueprint provider-upload Change-Id: Iee475c6cccaa7ab87c630036cff120f46ab42103 --- heat/api/cfn/v1/stacks.py | 1 + heat/api/openstack/v1/stacks.py | 7 +++++ heat/engine/service.py | 21 ++++++++------ heat/engine/template.py | 3 +- heat/rpc/client.py | 13 ++++++--- heat/tests/test_api_cfn_v1.py | 6 ++++ heat/tests/test_api_openstack_v1.py | 45 +++++++++++++++++++++++++++++ heat/tests/test_engine_service.py | 26 +++++++++-------- heat/tests/test_rpc_client.py | 2 ++ 9 files changed, 98 insertions(+), 26 deletions(-) diff --git a/heat/api/cfn/v1/stacks.py b/heat/api/cfn/v1/stacks.py index 21966d05..422f24f1 100644 --- a/heat/api/cfn/v1/stacks.py +++ b/heat/api/cfn/v1/stacks.py @@ -324,6 +324,7 @@ class StackController(object): args = {'template': stack, 'params': stack_parms, + 'files': {}, 'args': create_args} try: stack_name = req.params['StackName'] diff --git a/heat/api/openstack/v1/stacks.py b/heat/api/openstack/v1/stacks.py index 6e7f897d..2d28d003 100644 --- a/heat/api/openstack/v1/stacks.py +++ b/heat/api/openstack/v1/stacks.py @@ -45,12 +45,14 @@ class InstantiationData(object): PARAM_TEMPLATE_URL, PARAM_USER_PARAMS, PARAM_ENVIRONMENT, + PARAM_FILES, ) = ( 'stack_name', 'template', 'template_url', 'parameters', 'environment', + 'files', ) def __init__(self, data): @@ -129,6 +131,9 @@ class InstantiationData(object): env[self.PARAM_USER_PARAMS].update(parameters) return env + def files(self): + return self.data.get(self.PARAM_FILES, {}) + def args(self): """ Get any additional arguments supplied by the user. @@ -205,6 +210,7 @@ class StackController(object): data.stack_name(), data.template(), data.environment(), + data.files(), data.args()) except rpc_common.RemoteError as ex: return util.remote_error(ex) @@ -280,6 +286,7 @@ class StackController(object): identity, data.template(), data.environment(), + data.files(), data.args()) except rpc_common.RemoteError as ex: return util.remote_error(ex) diff --git a/heat/engine/service.py b/heat/engine/service.py index 3f103003..853bf155 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -184,17 +184,19 @@ class EngineService(service.Service): return list(format_stack_details(stacks)) @request_context - def create_stack(self, cnxt, stack_name, template, params, args): + def create_stack(self, cnxt, stack_name, template, params, files, args): """ The create_stack method creates a new stack using the template provided. Note that at this stage the template has already been fetched from the heat-api process if using a template-url. - arg1 -> RPC context. - arg2 -> Name of the stack you want to create. - arg3 -> Template of stack you want to create. - arg4 -> Stack Input Params - arg4 -> Request parameters/args passed from API + :param cnxt: RPC context. + :param stack_name: Name of the stack you want to create. + :param template: Template of stack you want to create. + :param params: Stack Input Params + :param files: Files referenced from the template + (currently provider templates). + :param args: Request parameters/args passed from API """ logger.info('template is %s' % template) @@ -211,7 +213,7 @@ class EngineService(service.Service): if db_api.stack_get_by_name(cnxt, stack_name): raise exception.StackExists(stack_name=stack_name) - tmpl = parser.Template(template) + tmpl = parser.Template(template, files=files) # Extract the common query parameters common_params = api.extract_args(args) @@ -228,7 +230,8 @@ class EngineService(service.Service): return dict(stack.identifier()) @request_context - def update_stack(self, cnxt, stack_identity, template, params, args): + def update_stack(self, cnxt, stack_identity, template, params, + files, args): """ The update_stack method updates an existing stack based on the provided template and parameters. @@ -249,7 +252,7 @@ class EngineService(service.Service): # Now parse the template and any parameters for the updated # stack definition. - tmpl = parser.Template(template) + tmpl = parser.Template(template, files=files) stack_name = current_stack.name common_params = api.extract_args(args) env = environment.Environment(params) diff --git a/heat/engine/template.py b/heat/engine/template.py index 342bbaae..4b298ccb 100644 --- a/heat/engine/template.py +++ b/heat/engine/template.py @@ -38,12 +38,13 @@ class Template(collections.Mapping): return super(Template, cls).__new__(cls) - def __init__(self, template, template_id=None): + def __init__(self, template, template_id=None, files=None): ''' Initialise the template with a JSON object and a set of Parameters ''' self.id = template_id self.t = template + self.files = files or {} self.maps = self[MAPPINGS] @classmethod diff --git a/heat/rpc/client.py b/heat/rpc/client.py index 6a73b81c..2b6a4d48 100644 --- a/heat/rpc/client.py +++ b/heat/rpc/client.py @@ -67,7 +67,7 @@ class EngineClient(heat.openstack.common.rpc.proxy.RpcProxy): return self.call(ctxt, self.make_msg('show_stack', stack_identity=stack_identity)) - def create_stack(self, ctxt, stack_name, template, params, args): + def create_stack(self, ctxt, stack_name, template, params, files, args): """ The create_stack method creates a new stack using the template provided. @@ -78,14 +78,16 @@ class EngineClient(heat.openstack.common.rpc.proxy.RpcProxy): :param stack_name: Name of the stack you want to create. :param template: Template of stack you want to create. :param params: Stack Input Params/Environment + :param files: files referenced from the environment. :param args: Request parameters/args passed from API """ return self.call(ctxt, self.make_msg('create_stack', stack_name=stack_name, template=template, - params=params, args=args)) + params=params, files=files, args=args)) - def update_stack(self, ctxt, stack_identity, template, params, args): + def update_stack(self, ctxt, stack_identity, template, params, + files, args): """ The update_stack method updates an existing stack based on the provided template and parameters. @@ -96,12 +98,15 @@ class EngineClient(heat.openstack.common.rpc.proxy.RpcProxy): :param stack_name: Name of the stack you want to create. :param template: Template of stack you want to create. :param params: Stack Input Params/Environment + :param files: files referenced from the environment. :param args: Request parameters/args passed from API """ return self.call(ctxt, self.make_msg('update_stack', stack_identity=stack_identity, template=template, - params=params, args=args)) + params=params, + files=files, + args=args)) def validate_template(self, ctxt, template): """ diff --git a/heat/tests/test_api_cfn_v1.py b/heat/tests/test_api_cfn_v1.py index cf00633c..9fa8e0f6 100644 --- a/heat/tests/test_api_cfn_v1.py +++ b/heat/tests/test_api_cfn_v1.py @@ -474,6 +474,7 @@ class CfnStackControllerTest(HeatTestCase): 'args': {'stack_name': stack_name, 'template': template, 'params': engine_parms, + 'files': {}, 'args': engine_args}, 'version': self.api_version}, None).AndReturn(engine_resp) @@ -537,6 +538,7 @@ class CfnStackControllerTest(HeatTestCase): 'args': {'stack_name': stack_name, 'template': template, 'params': engine_parms, + 'files': {}, 'args': engine_args}, 'version': self.api_version}, None ).AndRaise(rpc_common.RemoteError("AttributeError")) @@ -546,6 +548,7 @@ class CfnStackControllerTest(HeatTestCase): 'args': {'stack_name': stack_name, 'template': template, 'params': engine_parms, + 'files': {}, 'args': engine_args}, 'version': self.api_version}, None ).AndRaise(rpc_common.RemoteError("UnknownUserParameter")) @@ -588,6 +591,7 @@ class CfnStackControllerTest(HeatTestCase): 'args': {'stack_name': stack_name, 'template': template, 'params': engine_parms, + 'files': {}, 'args': engine_args}, 'version': self.api_version}, None ).AndRaise(rpc_common.RemoteError("StackExists")) @@ -623,6 +627,7 @@ class CfnStackControllerTest(HeatTestCase): 'args': {'stack_name': stack_name, 'template': template, 'params': engine_parms, + 'files': {}, 'args': engine_args}, 'version': self.api_version}, None).AndRaise( rpc_common.RemoteError( @@ -666,6 +671,7 @@ class CfnStackControllerTest(HeatTestCase): 'args': {'stack_identity': identity, 'template': template, 'params': engine_parms, + 'files': {}, 'args': engine_args}, 'version': self.api_version}, None).AndReturn(identity) diff --git a/heat/tests/test_api_openstack_v1.py b/heat/tests/test_api_openstack_v1.py index cb336611..7afc2de1 100644 --- a/heat/tests/test_api_openstack_v1.py +++ b/heat/tests/test_api_openstack_v1.py @@ -358,6 +358,43 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'args': {'stack_name': identity.stack_name, 'template': template, 'params': {'parameters': parameters}, + 'files': {}, + 'args': {'timeout_mins': 30}}, + 'version': self.api_version}, + None).AndReturn(dict(identity)) + self.m.ReplayAll() + + try: + response = self.controller.create(req, + tenant_id=identity.tenant, + body=body) + except webob.exc.HTTPCreated as created: + self.assertEqual(created.location, self._url(identity)) + else: + self.fail('HTTPCreated not raised') + self.m.VerifyAll() + + def test_create_with_files(self): + identity = identifier.HeatIdentifier(self.tenant, 'wordpress', '1') + template = {u'Foo': u'bar'} + json_template = json.dumps(template) + parameters = {u'InstanceType': u'm1.xlarge'} + body = {'template': template, + 'stack_name': identity.stack_name, + 'parameters': parameters, + 'files': {'my.yaml': 'This is the file contents.'}, + 'timeout_mins': 30} + + req = self._post('/stacks', json.dumps(body)) + + self.m.StubOutWithMock(rpc, 'call') + rpc.call(req.context, self.topic, + {'namespace': None, + 'method': 'create_stack', + 'args': {'stack_name': identity.stack_name, + 'template': template, + 'params': {'parameters': parameters}, + 'files': {'my.yaml': 'This is the file contents.'}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, None).AndReturn(dict(identity)) @@ -392,6 +429,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'args': {'stack_name': stack_name, 'template': template, 'params': {'parameters': parameters}, + 'files': {}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, None).AndRaise(rpc_common.RemoteError("AttributeError")) @@ -401,6 +439,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'args': {'stack_name': stack_name, 'template': template, 'params': {'parameters': parameters}, + 'files': {}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, None).AndRaise(rpc_common.RemoteError("UnknownUserParameter")) @@ -435,6 +474,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'args': {'stack_name': stack_name, 'template': template, 'params': {'parameters': parameters}, + 'files': {}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, None).AndRaise(rpc_common.RemoteError("StackExists")) @@ -464,6 +504,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'args': {'stack_name': stack_name, 'template': template, 'params': {'parameters': parameters}, + 'files': {}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, None).AndRaise(rpc_common.RemoteError( @@ -741,6 +782,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): parameters = {u'InstanceType': u'm1.xlarge'} body = {'template': template, 'parameters': parameters, + 'files': {}, 'timeout_mins': 30} req = self._put('/stacks/%(stack_name)s/%(stack_id)s' % identity, @@ -753,6 +795,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'args': {'stack_identity': dict(identity), 'template': template, 'params': {'parameters': parameters}, + 'files': {}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, None).AndReturn(dict(identity)) @@ -773,6 +816,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): parameters = {u'InstanceType': u'm1.xlarge'} body = {'template': template, 'parameters': parameters, + 'files': {}, 'timeout_mins': 30} req = self._put('/stacks/%(stack_name)s/%(stack_id)s' % identity, @@ -785,6 +829,7 @@ class StackControllerTest(ControllerTest, HeatTestCase): 'args': {'stack_identity': dict(identity), 'template': template, 'params': {u'parameters': parameters}, + 'files': {}, 'args': {'timeout_mins': 30}}, 'version': self.api_version}, None).AndRaise(rpc_common.RemoteError("StackNotFound")) diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index 55018db6..d22f99af 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -246,7 +246,7 @@ class stackServiceCreateUpdateDeleteTest(HeatTestCase): self.m.StubOutWithMock(environment, 'Environment') self.m.StubOutWithMock(parser, 'Stack') - parser.Template(template).AndReturn(stack.t) + parser.Template(template, files=None).AndReturn(stack.t) environment.Environment(params).AndReturn(stack.env) parser.Stack(self.ctx, stack.name, stack.t, stack.env).AndReturn(stack) @@ -260,7 +260,7 @@ class stackServiceCreateUpdateDeleteTest(HeatTestCase): self.m.ReplayAll() result = self.man.create_stack(self.ctx, stack_name, - template, params, {}) + template, params, None, {}) self.assertEqual(result, stack.identifier()) self.assertTrue(isinstance(result, dict)) self.assertTrue(result['stack_id']) @@ -277,7 +277,7 @@ class stackServiceCreateUpdateDeleteTest(HeatTestCase): self.m.StubOutWithMock(environment, 'Environment') self.m.StubOutWithMock(parser, 'Stack') - parser.Template(template).AndReturn(stack.t) + parser.Template(template, files=None).AndReturn(stack.t) environment.Environment(params).AndReturn(stack.env) parser.Stack(self.ctx, stack.name, stack.t, @@ -293,7 +293,7 @@ class stackServiceCreateUpdateDeleteTest(HeatTestCase): exception.StackValidationFailed, self.man.create_stack, self.ctx, stack_name, - template, params, {}) + template, params, None, {}) self.m.VerifyAll() def test_stack_create_invalid_stack_name(self): @@ -302,7 +302,7 @@ class stackServiceCreateUpdateDeleteTest(HeatTestCase): self.assertRaises(ValueError, self.man.create_stack, - self.ctx, stack_name, stack.t, {}, {}) + self.ctx, stack_name, stack.t, {}, None, {}) def test_stack_create_invalid_resource_name(self): stack_name = 'service_create_test_stack_invalid_res' @@ -314,7 +314,7 @@ class stackServiceCreateUpdateDeleteTest(HeatTestCase): self.assertRaises(ValueError, self.man.create_stack, self.ctx, stack_name, - stack.t, {}, {}) + stack.t, {}, None, {}) def test_stack_validate(self): stack_name = 'service_create_test_validate' @@ -391,7 +391,7 @@ class stackServiceCreateUpdateDeleteTest(HeatTestCase): self.m.StubOutWithMock(parser, 'Template') self.m.StubOutWithMock(environment, 'Environment') - parser.Template(template).AndReturn(stack.t) + parser.Template(template, files=None).AndReturn(stack.t) environment.Environment(params).AndReturn(stack.env) parser.Stack(self.ctx, stack.name, stack.t, stack.env).AndReturn(stack) @@ -405,7 +405,7 @@ class stackServiceCreateUpdateDeleteTest(HeatTestCase): self.m.ReplayAll() result = self.man.update_stack(self.ctx, old_stack.identifier(), - template, params, {}) + template, params, None, {}) self.assertEqual(result, old_stack.identifier()) self.assertTrue(isinstance(result, dict)) self.assertTrue(result['stack_id']) @@ -430,7 +430,7 @@ class stackServiceCreateUpdateDeleteTest(HeatTestCase): self.m.StubOutWithMock(parser, 'Template') self.m.StubOutWithMock(environment, 'Environment') - parser.Template(template).AndReturn(stack.t) + parser.Template(template, files=None).AndReturn(stack.t) environment.Environment(params).AndReturn(stack.env) parser.Stack(self.ctx, stack.name, stack.t, stack.env).AndReturn(stack) @@ -445,7 +445,7 @@ class stackServiceCreateUpdateDeleteTest(HeatTestCase): exception.StackValidationFailed, self.man.update_stack, self.ctx, old_stack.identifier(), - template, params, {}) + template, params, None, {}) self.m.VerifyAll() def test_stack_update_nonexist(self): @@ -458,7 +458,8 @@ class stackServiceCreateUpdateDeleteTest(HeatTestCase): self.assertRaises(exception.StackNotFound, self.man.update_stack, - self.ctx, stack.identifier(), template, params, {}) + self.ctx, stack.identifier(), template, params, + None, {}) self.m.VerifyAll() @@ -508,7 +509,8 @@ class stackServiceTest(HeatTestCase): @stack_context('service_create_existing_test_stack', False) def test_stack_create_existing(self): self.assertRaises(exception.StackExists, self.eng.create_stack, - self.ctx, self.stack.name, self.stack.t, {}, {}) + self.ctx, self.stack.name, self.stack.t, {}, + None, {}) @stack_context('service_name_tenants_test_stack', False) def test_stack_by_name_tenants(self): diff --git a/heat/tests/test_rpc_client.py b/heat/tests/test_rpc_client.py index f3b128c8..e4326bef 100644 --- a/heat/tests/test_rpc_client.py +++ b/heat/tests/test_rpc_client.py @@ -92,6 +92,7 @@ class EngineRpcAPITestCase(testtools.TestCase): self._test_engine_api('create_stack', 'call', stack_name='wordpress', template={u'Foo': u'bar'}, params={u'InstanceType': u'm1.xlarge'}, + files={u'a_file': u'the contents'}, args={'timeout_mins': u'30'}) def test_update_stack(self): @@ -99,6 +100,7 @@ class EngineRpcAPITestCase(testtools.TestCase): stack_identity=self.identity, template={u'Foo': u'bar'}, params={u'InstanceType': u'm1.xlarge'}, + files={}, args={}) def test_validate_template(self): -- 2.45.2