def get_template_summary(req_params): stack_name = req_params.get('StackName') stack = None if stack_name: stack = find_stack(stack_name) if not stack: return stack_not_found_error(stack_name) template_deployer.prepare_template_body(req_params) template = template_preparer.parse_template(req_params['TemplateBody']) req_params['StackName'] = 'tmp-stack' stack = Stack(req_params, template) result = stack.describe_details() id_summaries = {} for resource_id, resource in stack.template_resources.items(): res_type = resource['Type'] id_summaries[res_type] = id_summaries.get(res_type) or [] id_summaries[res_type].append(resource_id) result['ResourceTypes'] = list(id_summaries.keys()) result['ResourceIdentifierSummaries'] = [{ 'ResourceType': key, 'LogicalResourceIds': { 'member': values } } for key, values in id_summaries.items()] return result
def create_stack(req_params): state = CloudFormationRegion.get() template_deployer.prepare_template_body(req_params) template = template_preparer.parse_template(req_params['TemplateBody']) stack_name = template['StackName'] = req_params.get('StackName') stack = Stack(req_params, template) # find existing stack with same name, and remove it if this stack is in DELETED state existing = ([s for s in state.stacks.values() if s.stack_name == stack_name] or [None])[0] if existing: if 'DELETE' not in existing.status: return error_response('Stack named "%s" already exists with status "%s"' % ( stack_name, existing.status), code=400, code_string='ValidationError') state.stacks.pop(existing.stack_id) state.stacks[stack.stack_id] = stack LOG.debug('Creating stack "%s" with %s resources ...' % (stack.stack_name, len(stack.template_resources))) deployer = template_deployer.TemplateDeployer(stack) try: deployer.deploy_stack() except Exception as e: stack.set_stack_status('CREATE_FAILED') msg = 'Unable to create stack "%s": %s' % (stack.stack_name, e) LOG.debug('%s %s' % (msg, traceback.format_exc())) return error_response(msg, code=400, code_string='ValidationError') result = {'StackId': stack.stack_id} return result
def create_change_set(req_params): stack_name = req_params.get('StackName') template_deployer.prepare_template_body(req_params) template = template_preparer.parse_template(req_params.pop('TemplateBody')) template['StackName'] = stack_name template['ChangeSetName'] = req_params.get('ChangeSetName') stack = existing = find_stack(stack_name) if not existing: # automatically create (empty) stack if none exists yet state = CloudFormationRegion.get() empty_stack_template = dict(template) empty_stack_template['Resources'] = {} req_params_copy = clone_stack_params(req_params) stack = Stack(req_params_copy, empty_stack_template) state.stacks[stack.stack_id] = stack stack.set_stack_status('CREATE_COMPLETE') change_set = StackChangeSet(req_params, template) deployer = template_deployer.TemplateDeployer(stack) deployer.construct_changes(stack, change_set, change_set_id=change_set.change_set_id, append_to_changeset=True) stack.change_sets.append(change_set) change_set.metadata['Status'] = 'CREATE_COMPLETE' change_set.metadata['ExecutionStatus'] = 'AVAILABLE' change_set.metadata['StatusReason'] = 'Changeset created' return {'StackId': change_set.stack_id, 'Id': change_set.change_set_id}
def get_template_summary( self, context: RequestContext, request: GetTemplateSummaryInput, ) -> GetTemplateSummaryOutput: stack_name = request.get("StackName") if stack_name: stack = find_stack(stack_name) if not stack: return stack_not_found_error(stack_name) else: template_deployer.prepare_template_body(request) template = template_preparer.parse_template(request["TemplateBody"]) request["StackName"] = "tmp-stack" stack = Stack(request, template) result: GetTemplateSummaryOutput = stack.describe_details() id_summaries = {} for resource_id, resource in stack.template_resources.items(): res_type = resource["Type"] id_summaries[res_type] = id_summaries.get(res_type) or [] id_summaries[res_type].append(resource_id) result["ResourceTypes"] = list(id_summaries.keys()) result["ResourceIdentifierSummaries"] = [ {"ResourceType": key, "LogicalResourceIds": values} for key, values in id_summaries.items() ] return result
def create_stack(self, context: RequestContext, request: CreateStackInput) -> CreateStackOutput: state = CloudFormationRegion.get() template_deployer.prepare_template_body(request) # TODO: avoid mutating request directly template = template_preparer.parse_template(request["TemplateBody"]) stack_name = template["StackName"] = request.get("StackName") stack = Stack(request, template) # find existing stack with same name, and remove it if this stack is in DELETED state existing = ([s for s in state.stacks.values() if s.stack_name == stack_name] or [None])[0] if existing: if "DELETE" not in existing.status: raise ValidationError( f'Stack named "{stack_name}" already exists with status "{existing.status}"' ) state.stacks.pop(existing.stack_id) state.stacks[stack.stack_id] = stack LOG.debug( 'Creating stack "%s" with %s resources ...', stack.stack_name, len(stack.template_resources), ) deployer = template_deployer.TemplateDeployer(stack) try: # TODO: create separate step to first resolve parameters deployer.deploy_stack() except Exception as e: stack.set_stack_status("CREATE_FAILED") msg = 'Unable to create stack "%s": %s' % (stack.stack_name, e) LOG.exception("%s") raise ValidationError(msg) from e return CreateStackOutput(StackId=stack.stack_id)
def get_template_summary(req_params): stack_name = req_params.get("StackName") stack = None if stack_name: stack = find_stack(stack_name) if not stack: return stack_not_found_error(stack_name) else: template_deployer.prepare_template_body(req_params) template = template_preparer.parse_template(req_params["TemplateBody"]) req_params["StackName"] = "tmp-stack" stack = Stack(req_params, template) result = stack.describe_details() id_summaries = {} for resource_id, resource in stack.template_resources.items(): res_type = resource["Type"] id_summaries[res_type] = id_summaries.get(res_type) or [] id_summaries[res_type].append(resource_id) result["ResourceTypes"] = list(id_summaries.keys()) result["ResourceIdentifierSummaries"] = [{ "ResourceType": key, "LogicalResourceIds": { "member": values } } for key, values in id_summaries.items()] return result
def create_change_set(req_params): stack_name = req_params.get("StackName") template_deployer.prepare_template_body(req_params) template = template_preparer.parse_template(req_params.pop("TemplateBody")) template["StackName"] = stack_name template["ChangeSetName"] = req_params.get("ChangeSetName") stack = existing = find_stack(stack_name) if not existing: # automatically create (empty) stack if none exists yet state = CloudFormationRegion.get() empty_stack_template = dict(template) empty_stack_template["Resources"] = {} req_params_copy = clone_stack_params(req_params) stack = Stack(req_params_copy, empty_stack_template) state.stacks[stack.stack_id] = stack stack.set_stack_status("CREATE_COMPLETE") change_set = StackChangeSet(req_params, template) deployer = template_deployer.TemplateDeployer(stack) deployer.construct_changes( stack, change_set, change_set_id=change_set.change_set_id, append_to_changeset=True, ) stack.change_sets.append(change_set) change_set.metadata["Status"] = "CREATE_COMPLETE" change_set.metadata["ExecutionStatus"] = "AVAILABLE" change_set.metadata["StatusReason"] = "Changeset created" return {"StackId": change_set.stack_id, "Id": change_set.change_set_id}
def create_stack(req_params): state = CloudFormationRegion.get() template_deployer.prepare_template_body(req_params) # TODO: avoid mutating req_params directly template = template_preparer.parse_template(req_params["TemplateBody"]) stack_name = template["StackName"] = req_params.get("StackName") stack = Stack(req_params, template) # find existing stack with same name, and remove it if this stack is in DELETED state existing = ([s for s in state.stacks.values() if s.stack_name == stack_name] or [None])[0] if existing: if "DELETE" not in existing.status: return error_response( 'Stack named "%s" already exists with status "%s"' % (stack_name, existing.status), code=400, code_string="ValidationError", ) state.stacks.pop(existing.stack_id) state.stacks[stack.stack_id] = stack LOG.debug( 'Creating stack "%s" with %s resources ...' % (stack.stack_name, len(stack.template_resources)) ) deployer = template_deployer.TemplateDeployer(stack) try: # TODO: create separate step to first resolve parameters deployer.deploy_stack() except Exception as e: stack.set_stack_status("CREATE_FAILED") msg = 'Unable to create stack "%s": %s' % (stack.stack_name, e) LOG.debug("%s %s" % (msg, traceback.format_exc())) return error_response(msg, code=400, code_string="ValidationError") result = {"StackId": stack.stack_id} return result
def create_stack(req_params): state = CloudFormationRegion.get() template_deployer.prepare_template_body(req_params) template = template_preparer.parse_template(req_params['TemplateBody']) template['StackName'] = req_params.get('StackName') stack = Stack(req_params, template) state.stacks[stack.stack_id] = stack LOG.debug('Creating stack "%s" with %s resources ...' % (stack.stack_name, len(stack.template_resources))) deployer = template_deployer.TemplateDeployer(stack) try: deployer.deploy_stack() except Exception as e: stack.set_stack_status('CREATE_FAILED') msg = 'Unable to create stack "%s": %s' % (stack.stack_name, e) LOG.debug('%s %s' % (msg, traceback.format_exc())) return error_response(msg, code=400, code_string='ValidationError') result = {'StackId': stack.stack_id} return result
def create_change_set(req_params): stack_name = req_params.get('StackName') template_deployer.prepare_template_body(req_params) template = template_preparer.parse_template(req_params['TemplateBody']) template['StackName'] = stack_name template['ChangeSetName'] = req_params.get('ChangeSetName') stack = existing = find_stack(stack_name) if not existing: # automatically create (empty) stack if none exists yet state = CloudFormationRegion.get() empty_stack_template = dict(template) empty_stack_template['Resources'] = {} stack = Stack(clone(req_params), empty_stack_template) state.stacks[stack.stack_id] = stack stack.set_stack_status('CREATE_COMPLETE') change_set = StackChangeSet(req_params, template) stack.change_sets.append(change_set) change_set.metadata['Status'] = 'CREATE_COMPLETE' return {'StackId': change_set.stack_id, 'Id': change_set.change_set_id}
def forward_request(self, method, path, data, headers): if method == 'OPTIONS': return 200 data = data or '' data_orig = data data = aws_stack.fix_account_id_in_arns( data, existing='%3A{}%3Astack/'.format(TEST_AWS_ACCOUNT_ID), replace='%3A{}%3Astack/'.format(MOTO_CLOUDFORMATION_ACCOUNT_ID), colon_delimiter='') data = aws_stack.fix_account_id_in_arns( data, existing='%3A{}%3AchangeSet/'.format(TEST_AWS_ACCOUNT_ID), replace='%3A{}%3AchangeSet/'.format( MOTO_CLOUDFORMATION_ACCOUNT_ID), colon_delimiter='') data = aws_stack.fix_account_id_in_arns(data, existing=TEST_AWS_ACCOUNT_ID, replace=MOTO_ACCOUNT_ID, colon_delimiter='%3A') req_data = None if method == 'POST' and path == '/': req_data = urlparse.parse_qs(to_str(data)) req_data = dict([(k, v[0]) for k, v in req_data.items()]) action = req_data.get('Action') stack_name = req_data.get('StackName') if action == 'CreateStack': event_publisher.fire_event( event_publisher.EVENT_CLOUDFORMATION_CREATE_STACK, payload={'n': event_publisher.get_hash(stack_name)}) if action == 'DeleteStack': client = aws_stack.connect_to_service('cloudformation') stack_resources = client.list_stack_resources( StackName=stack_name)['StackResourceSummaries'] from localstack.utils.cloudformation import template_deployer_old template_deployer_old.delete_stack(stack_name, stack_resources) if action == 'DescribeStackEvents': # fix an issue where moto cannot handle ARNs as stack names (or missing names) run_fix = not stack_name if stack_name: if stack_name.startswith('arn:aws:cloudformation'): run_fix = True pattern = r'arn:aws:cloudformation:[^:]+:[^:]+:stack/([^/]+)(/.+)?' stack_name = re.sub(pattern, r'\1', stack_name) if run_fix: stack_names = [ stack_name ] if stack_name else self._list_stack_names() client = aws_stack.connect_to_service('cloudformation') events = [] for stack_name in stack_names: tmp = client.describe_stack_events( StackName=stack_name)['StackEvents'][:1] events.extend(tmp) events = [{'member': e} for e in events] response_content = '<StackEvents>%s</StackEvents>' % obj_to_xml( events) return make_response('DescribeStackEvents', response_content) if req_data: if action == 'ValidateTemplate': return template_preparer.validate_template(req_data) if action in ['CreateStack', 'UpdateStack', 'CreateChangeSet']: modified = template_deployer.prepare_template_body(req_data) if modified: data = urlparse.urlencode(req_data, doseq=True) return Request(data=data, headers=headers, method=method) if data != data_orig or action in [ 'DescribeChangeSet', 'ExecuteChangeSet' ]: return Request(data=urlparse.urlencode(req_data, doseq=True), headers=headers, method=method) return True