Ejemplo n.º 1
0
def validate_template(req_data):
    LOGGER.debug(req_data)
    response_content = """
        <Capabilities></Capabilities>
        <CapabilitiesReason></CapabilitiesReason>
        <DeclaredTransforms></DeclaredTransforms>
        <Description></Description>
        <Parameters>
        </Parameters>
    """

    try:
        template_deployer.template_to_json(req_data.get('TemplateBody')[0])
        response = make_response('ValidateTemplate', response_content)
        return response
    except Exception as err:
        response = error_response('Template Validation Error: %s' % err)
        return response
Ejemplo n.º 2
0
    def return_response(self, method, path, data, headers, response):
        req_data = None
        if method == 'POST' and path == '/':
            req_data = urlparse.parse_qs(to_str(data))
            action = req_data.get('Action')[0]

        if req_data:
            if action == 'DescribeStackResources':
                if response.status_code < 300:
                    response_dict = xmltodict.parse(response.content)['DescribeStackResourcesResponse']
                    resources = response_dict['DescribeStackResourcesResult']['StackResources']
                    if not resources:
                        # Check if stack exists
                        stack_name = req_data.get('StackName')[0]
                        cloudformation_client = aws_stack.connect_to_service('cloudformation')
                        try:
                            cloudformation_client.describe_stacks(StackName=stack_name)
                        except Exception:
                            return error_response('Stack with id %s does not exist' % stack_name, code=404)
            if action == 'DescribeStackResource':
                if response.status_code >= 500:
                    # fix an error in moto where it fails with 500 if the stack does not exist
                    return error_response('Stack resource does not exist', code=404)
            if action == 'ListStackResources':
                response_dict = xmltodict.parse(response.content, force_list=('member'))['ListStackResourcesResponse']
                resources = response_dict['ListStackResourcesResult']['StackResourceSummaries']
                if resources:
                    sqs_client = aws_stack.connect_to_service('sqs')
                    content_str = content_str_original = to_str(response.content)
                    new_response = Response()
                    new_response.status_code = response.status_code
                    new_response.headers = response.headers
                    for resource in resources['member']:
                        if resource['ResourceType'] == 'AWS::SQS::Queue':
                            try:
                                queue_name = resource['PhysicalResourceId']
                                queue_url = sqs_client.get_queue_url(QueueName=queue_name)['QueueUrl']
                            except Exception:
                                stack_name = req_data.get('StackName')[0]
                                return error_response('Stack with id %s does not exist' % stack_name, code=404)
                            content_str = re.sub(resource['PhysicalResourceId'], queue_url, content_str)
                    new_response._content = content_str
                    if content_str_original != new_response._content:
                        # if changes have been made, return patched response
                        new_response.headers['content-length'] = len(new_response._content)
                        return new_response
            elif action in ('CreateStack', 'UpdateStack'):
                if response.status_code >= 400:
                    return response
                # run the actual deployment
                template = template_deployer.template_to_json(req_data.get('TemplateBody')[0])
                template_deployer.deploy_template(template, req_data.get('StackName')[0])
Ejemplo n.º 3
0
    def test_list_stack_resources_returns_queue_urls(self):
        cloudformation = aws_stack.connect_to_resource('cloudformation')
        template = template_deployer.template_to_json(load_file(TEST_TEMPLATE_2))
        cloudformation.create_stack(StackName=TEST_STACK_NAME_2, TemplateBody=template)

        def check_stack():
            stack = get_stack_details(TEST_STACK_NAME_2)
            assert stack['StackStatus'] == 'CREATE_COMPLETE'

        retry(check_stack, retries=3, sleep=2)

        list_stack_summaries = list_stack_resources(TEST_STACK_NAME_2)
        queue_urls = get_queue_urls()

        for resource in list_stack_summaries:
            assert resource['PhysicalResourceId'] in queue_urls
Ejemplo n.º 4
0
    def test_apply_template(self):
        cloudformation = aws_stack.connect_to_resource('cloudformation')
        template = template_deployer.template_to_json(load_file(TEST_TEMPLATE_1))

        # deploy template
        cloudformation.create_stack(StackName=TEST_STACK_NAME, TemplateBody=template)

        # wait for deployment to finish
        def check_stack():
            stack = get_stack_details(TEST_STACK_NAME)
            assert stack['StackStatus'] == 'CREATE_COMPLETE'

        retry(check_stack, retries=3, sleep=2)

        # assert that bucket has been created
        assert bucket_exists('cf-test-bucket-1')
        # assert that queue has been created
        assert queue_exists('cf-test-queue-1')
        # assert that stream has been created
        assert stream_exists('cf-test-stream-1')
        # assert that queue has been created
        resource = describe_stack_resource(TEST_STACK_NAME, 'SQSQueueNoNameProperty')
        assert queue_exists(resource['PhysicalResourceId'])
Ejemplo n.º 5
0
def execute_change_set(req_data):
    cs_arn = req_data.get('ChangeSetName')[0]
    stack_name = req_data.get('StackName')[0]
    cs_details = CHANGE_SETS.get(cs_arn)
    if not cs_details:
        return error_response('Change Set %s does not exist' % cs_arn, 404, 'ChangeSetNotFound')

    # convert to JSON (might have been YAML, and update_stack/create_stack seem to only work with JSON)
    template = template_deployer.template_to_json(cs_details.get('TemplateBody')[0])

    # update stack information
    cloudformation_service = aws_stack.connect_to_service('cloudformation')
    if stack_exists(stack_name):
        cloudformation_service.update_stack(StackName=stack_name,
            TemplateBody=template)
    else:
        cloudformation_service.create_stack(StackName=stack_name,
            TemplateBody=template)

    # now run the actual deployment
    template_deployer.deploy_template(template, stack_name)

    response = make_response('ExecuteChangeSet')
    return response
 def test_validate_template(self):
     cloudformation = aws_stack.connect_to_service('cloudformation')
     template = template_deployer.template_to_json(
         load_file(TEST_TEMPLATE_1))
     response = cloudformation.validate_template(TemplateBody=template)
     self.assertEqual(response['ResponseMetadata']['HTTPStatusCode'], 200)
    def test_create_delete_stack(self):
        cloudformation = aws_stack.connect_to_resource('cloudformation')
        cf_client = aws_stack.connect_to_service('cloudformation')
        s3 = aws_stack.connect_to_service('s3')
        sns = aws_stack.connect_to_service('sns')
        sqs = aws_stack.connect_to_service('sqs')
        apigateway = aws_stack.connect_to_service('apigateway')
        template = template_deployer.template_to_json(
            load_file(TEST_TEMPLATE_1))

        # deploy template
        stack_name = 'stack-%s' % short_uid()
        cloudformation.create_stack(StackName=stack_name,
                                    TemplateBody=template)

        # wait for deployment to finish
        def check_stack():
            stack = get_stack_details(stack_name)
            self.assertEqual(stack['StackStatus'], 'CREATE_COMPLETE')

        retry(check_stack, retries=3, sleep=2)

        # assert that resources have been created
        assert bucket_exists('cf-test-bucket-1')
        queue_url = queue_exists('cf-test-queue-1')
        assert queue_url
        topic_arn = topic_exists('%s-test-topic-1-1' % stack_name)
        assert topic_arn
        assert stream_exists('cf-test-stream-1')
        resource = describe_stack_resource(stack_name,
                                           'SQSQueueNoNameProperty')
        assert queue_exists(resource['PhysicalResourceId'])
        assert ssm_param_exists('cf-test-param-1')

        # assert that tags have been created
        tags = s3.get_bucket_tagging(Bucket='cf-test-bucket-1')['TagSet']
        self.assertEqual(
            tags, [{
                'Key': 'foobar',
                'Value': aws_stack.get_sqs_queue_url('cf-test-queue-1')
            }])
        tags = sns.list_tags_for_resource(ResourceArn=topic_arn)['Tags']
        self.assertEqual(
            tags, [{
                'Key': 'foo',
                'Value': 'cf-test-bucket-1'
            }, {
                'Key': 'bar',
                'Value': aws_stack.s3_bucket_arn('cf-test-bucket-1')
            }])
        queue_tags = sqs.list_queue_tags(QueueUrl=queue_url)
        self.assertIn('Tags', queue_tags)
        self.assertEqual(queue_tags['Tags'], {
            'key1': 'value1',
            'key2': 'value2'
        })

        # assert that bucket notifications have been created
        notifications = s3.get_bucket_notification_configuration(
            Bucket='cf-test-bucket-1')
        self.assertIn('QueueConfigurations', notifications)
        self.assertIn('LambdaFunctionConfigurations', notifications)
        self.assertEqual(notifications['QueueConfigurations'][0]['QueueArn'],
                         'aws:arn:sqs:test:testqueue')
        self.assertEqual(notifications['QueueConfigurations'][0]['Events'],
                         ['s3:ObjectDeleted:*'])
        self.assertEqual(
            notifications['LambdaFunctionConfigurations'][0]
            ['LambdaFunctionArn'], 'aws:arn:lambda:test:testfunc')
        self.assertEqual(
            notifications['LambdaFunctionConfigurations'][0]['Events'],
            ['s3:ObjectCreated:*'])

        # assert that subscriptions have been created
        subs = sns.list_subscriptions()['Subscriptions']
        subs = [
            s for s in subs
            if (':%s:cf-test-queue-1' % TEST_AWS_ACCOUNT_ID) in s['Endpoint']
        ]
        self.assertEqual(len(subs), 1)
        self.assertIn(
            ':%s:%s-test-topic-1-1' % (TEST_AWS_ACCOUNT_ID, stack_name),
            subs[0]['TopicArn'])
        # assert that subscription attributes are added properly
        attrs = sns.get_subscription_attributes(
            SubscriptionArn=subs[0]['SubscriptionArn'])['Attributes']
        self.assertEqual(
            attrs, {
                'Endpoint': subs[0]['Endpoint'],
                'Protocol': 'sqs',
                'SubscriptionArn': subs[0]['SubscriptionArn'],
                'TopicArn': subs[0]['TopicArn'],
                'FilterPolicy': json.dumps({'eventType': ['created']})
            })

        # assert that Gateway responses have been created
        test_api_name = 'test-api'
        api = [
            a for a in apigateway.get_rest_apis()['items']
            if a['name'] == test_api_name
        ][0]
        responses = apigateway.get_gateway_responses(
            restApiId=api['id'])['items']
        self.assertEqual(len(responses), 2)
        types = [r['responseType'] for r in responses]
        self.assertEqual(set(types), set(['UNAUTHORIZED', 'DEFAULT_5XX']))

        # delete the stack
        cf_client.delete_stack(StackName=stack_name)

        # assert that resources have been deleted
        assert not bucket_exists('cf-test-bucket-1')
        assert not queue_exists('cf-test-queue-1')
        assert not topic_exists('%s-test-topic-1-1' % stack_name)
        retry(lambda: self.assertFalse(stream_exists('cf-test-stream-1')))
Ejemplo n.º 8
0
 def test_validate_template(self):
     cloudformation = aws_stack.connect_to_service('cloudformation')
     template = template_deployer.template_to_json(load_file(TEST_TEMPLATE_1))
     response = cloudformation.validate_template(TemplateBody=template)
     assert response['ResponseMetadata']['HTTPStatusCode'] == 200
Ejemplo n.º 9
0
    def test_create_delete_stack(self):
        cloudformation = aws_stack.connect_to_resource('cloudformation')
        cf_client = aws_stack.connect_to_service('cloudformation')
        s3 = aws_stack.connect_to_service('s3')
        sns = aws_stack.connect_to_service('sns')
        apigateway = aws_stack.connect_to_service('apigateway')
        template = template_deployer.template_to_json(
            load_file(TEST_TEMPLATE_1))

        # deploy template
        stack_name = 'stack-%s' % short_uid()
        cloudformation.create_stack(StackName=stack_name,
                                    TemplateBody=template)

        # wait for deployment to finish
        def check_stack():
            stack = get_stack_details(stack_name)
            self.assertEqual(stack['StackStatus'], 'CREATE_COMPLETE')

        retry(check_stack, retries=3, sleep=2)

        # assert that resources have been created
        assert bucket_exists('cf-test-bucket-1')
        assert queue_exists('cf-test-queue-1')
        topic_arn = topic_exists('%s-test-topic-1-1' % stack_name)
        assert topic_arn
        assert stream_exists('cf-test-stream-1')
        resource = describe_stack_resource(stack_name,
                                           'SQSQueueNoNameProperty')
        assert queue_exists(resource['PhysicalResourceId'])

        # assert that tags have been created
        tags = s3.get_bucket_tagging(Bucket='cf-test-bucket-1')['TagSet']
        self.assertEqual(
            tags, [{
                'Key': 'foobar',
                'Value': aws_stack.get_sqs_queue_url('cf-test-queue-1')
            }])
        tags = sns.list_tags_for_resource(ResourceArn=topic_arn)['Tags']
        self.assertEqual(
            tags, [{
                'Key': 'foo',
                'Value': 'cf-test-bucket-1'
            }, {
                'Key': 'bar',
                'Value': aws_stack.s3_bucket_arn('cf-test-bucket-1')
            }])

        # assert that subscriptions have been created
        subs = sns.list_subscriptions()['Subscriptions']
        subs = [
            s for s in subs
            if (':%s:cf-test-queue-1' % TEST_AWS_ACCOUNT_ID) in s['Endpoint']
        ]
        self.assertEqual(len(subs), 1)
        self.assertIn(
            ':%s:%s-test-topic-1-1' % (TEST_AWS_ACCOUNT_ID, stack_name),
            subs[0]['TopicArn'])

        # assert that Gateway responses have been created
        test_api_name = 'test-api'
        api = [
            a for a in apigateway.get_rest_apis()['items']
            if a['name'] == test_api_name
        ][0]
        responses = apigateway.get_gateway_responses(
            restApiId=api['id'])['items']
        self.assertEqual(len(responses), 2)
        types = [r['responseType'] for r in responses]
        self.assertEqual(set(types), set(['UNAUTHORIZED', 'DEFAULT_5XX']))

        # delete the stack
        cf_client.delete_stack(StackName=stack_name)

        # assert that resources have been deleted
        assert not bucket_exists('cf-test-bucket-1')
        assert not queue_exists('cf-test-queue-1')
        assert not topic_exists('%s-test-topic-1-1' % stack_name)
        retry(lambda: self.assertFalse(stream_exists('cf-test-stream-1')))
Ejemplo n.º 10
0
    def return_response(self, method, path, data, headers, response):
        req_data = None
        if method == 'POST' and path == '/':
            req_data = urlparse.parse_qs(to_str(data))
            action = req_data.get('Action')[0]

        if req_data:
            if action == 'DescribeStackResources':
                if response.status_code < 300:
                    response_dict = xmltodict.parse(
                        response.content)['DescribeStackResourcesResponse']
                    resources = response_dict['DescribeStackResourcesResult'][
                        'StackResources']
                    if not resources:
                        # Check if stack exists
                        stack_name = req_data.get('StackName')[0]
                        cloudformation_client = aws_stack.connect_to_service(
                            'cloudformation')
                        try:
                            cloudformation_client.describe_stacks(
                                StackName=stack_name)
                        except Exception:
                            return error_response(
                                'Stack with name %s does not exist' %
                                stack_name,
                                code=404)
            if action == 'DescribeStackResource':
                if response.status_code >= 500:
                    # fix an error in moto where it fails with 500 if the stack does not exist
                    return error_response('Stack resource does not exist',
                                          code=404)
            if action == 'ListStackResources':
                response_dict = xmltodict.parse(
                    response.content,
                    force_list=('member'))['ListStackResourcesResponse']
                resources = response_dict['ListStackResourcesResult'][
                    'StackResourceSummaries']
                if resources:
                    sqs_client = aws_stack.connect_to_service('sqs')
                    content_str = content_str_original = to_str(
                        response.content)
                    new_response = Response()
                    new_response.status_code = response.status_code
                    new_response.headers = response.headers
                    for resource in resources['member']:
                        if resource['ResourceType'] == 'AWS::SQS::Queue':
                            try:
                                queue_name = resource['PhysicalResourceId']
                                queue_url = sqs_client.get_queue_url(
                                    QueueName=queue_name)['QueueUrl']
                            except Exception:
                                stack_name = req_data.get('StackName')[0]
                                return error_response(
                                    'Stack with name %s does not exist' %
                                    stack_name,
                                    code=404)
                            content_str = re.sub(
                                resource['PhysicalResourceId'], queue_url,
                                content_str)
                    new_response._content = content_str
                    if content_str_original != new_response._content:
                        # if changes have been made, return patched response
                        new_response.headers['content-length'] = len(
                            new_response._content)
                        return new_response
            elif action in ('CreateStack', 'UpdateStack'):
                if response.status_code >= 400:
                    return response
                # run the actual deployment
                template = template_deployer.template_to_json(
                    req_data.get('TemplateBody')[0])
                template_deployer.deploy_template(template,
                                                  req_data.get('StackName')[0])
Ejemplo n.º 11
0
def update_cloudformation(method,
                          path,
                          data,
                          headers,
                          response=None,
                          return_forward_info=False):
    req_data = None
    if method == 'POST' and path == '/':
        req_data = urlparse.parse_qs(data)
        action = req_data.get('Action')[0]

    if return_forward_info:
        if req_data:
            if action == 'CreateChangeSet':
                return create_change_set(req_data)
            elif action == 'DescribeChangeSet':
                return describe_change_set(req_data)
            elif action == 'ExecuteChangeSet':
                return execute_change_set(req_data)
            elif action == 'UpdateStack' and req_data.get('TemplateURL'):
                # Temporary fix until the moto CF backend can handle TemplateURL (currently fails)
                url = re.sub(r'https?://s3\.amazonaws\.com',
                             aws_stack.get_local_service_url('s3'),
                             req_data.get('TemplateURL')[0])
                req_data['TemplateBody'] = requests.get(url).content
                modified_data = urlparse.urlencode(req_data, doseq=True)
                return Request(data=modified_data,
                               headers=headers,
                               method=method)
        return True

    if req_data:
        if action == 'DescribeStackResources':
            if response.status_code < 300:
                response_dict = xmltodict.parse(
                    response.content)['DescribeStackResourcesResponse']
                resources = response_dict['DescribeStackResourcesResult'][
                    'StackResources']
                if not resources:
                    # Check if stack exists
                    stack_name = req_data.get('StackName')[0]
                    cloudformation_client = aws_stack.connect_to_service(
                        'cloudformation')
                    try:
                        cloudformation_client.describe_stacks(
                            StackName=stack_name)
                    except Exception as e:
                        return error_response(
                            'Stack with id %s does not exist' % stack_name,
                            code=404)
        if action == 'DescribeStackResource':
            if response.status_code >= 500:
                # fix an error in moto where it fails with 500 if the stack does not exist
                return error_response('Stack resource does not exist',
                                      code=404)
        elif action == 'CreateStack' or action == 'UpdateStack':
            # run the actual deployment
            template = template_deployer.template_to_json(
                req_data.get('TemplateBody')[0])
            template_deployer.deploy_template(template,
                                              req_data.get('StackName')[0])
            if response.status_code >= 400:
                return make_response(action)