Пример #1
0
 def test_with_default_policy(self, mock_get_stack_info,
                              mock_get_access_control_role_name,
                              mock_put_role_policy, mock_create_role):
     id_data = {}
     created_role_arn = role_utils.create_access_control_role(
         _STACK_INFO_MANAGER,
         id_data,
         self.stack_arn,
         self.logical_role_name,
         self.assume_role_service,
         delay_for_propagation=False,
         default_policy=self.default_policy)
     self.assertEqual(created_role_arn, self.role_arn)
     self.assertEquals(
         id_data,
         {'AbstractRoleMappings': {
             self.logical_role_name: self.role_name
         }})
     mock_get_access_control_role_name.assert_called_once_with(
         self.stack_arn, self.logical_role_name)
     mock_create_role.assert_called_once_with(
         RoleName=self.role_name,
         AssumeRolePolicyDocument=self.assume_role_policy_document_matcher,
         Path=self.path)
     mock_put_role_policy.assert_called_once_with(
         RoleName=self.role_name,
         PolicyName='Default',
         PolicyDocument=self.default_policy)
     mock_get_stack_info.assert_called_once_with(self.stack_arn)
Пример #2
0
 def test_with_delay_for_propagation_false(
         self, mock_get_stack_info, mock_get_access_control_role_name,
         mock_create_role):
     id_data = {}
     role_utils.PROPAGATION_DELAY_SECONDS = 2
     start_time = time.clock()
     created_role_arn = role_utils.create_access_control_role(
         _STACK_INFO_MANAGER,
         id_data,
         self.stack_arn,
         self.logical_role_name,
         self.assume_role_service,
         delay_for_propagation=False)
     stop_time = time.clock()
     delay_time = stop_time - start_time
     self.assertAlmostEqual(delay_time, 0, delta=0.1)
     self.assertEqual(created_role_arn, self.role_arn)
     self.assertEquals(
         id_data,
         {'AbstractRoleMappings': {
             self.logical_role_name: self.role_name
         }})
     mock_get_access_control_role_name.assert_called_once_with(
         self.stack_arn, self.logical_role_name)
     mock_create_role.assert_called_once_with(
         RoleName=self.role_name,
         AssumeRolePolicyDocument=self.assume_role_policy_document_matcher,
         Path=self.path)
     mock_get_stack_info.assert_called_once_with(self.stack_arn)
def handler(event, context):
    props = properties.load(event, PROPERTIES_SCHEMA)

    request_type = event['RequestType']
    stack_arn = event['StackId']
    logical_role_name = props.FunctionName
    stack_manager = stack_info.StackInfoManager()

    id_data = aws_utils.get_data_from_custom_physical_resource_id(
        event.get('PhysicalResourceId', None))

    if request_type == 'Delete':
        role_utils.delete_access_control_role(id_data, logical_role_name)

        response_data = {}

    else:
        stack = stack_manager.get_stack_info(stack_arn)

        if request_type == 'Create':

            project_service_lambda_arn = _get_project_service_lambda_arn(stack)
            assume_role_service = 'lambda.amazonaws.com'
            role_arn = role_utils.create_access_control_role(
                stack_manager,
                id_data,
                stack_arn,
                logical_role_name,
                assume_role_service,
                default_policy=get_default_policy(project_service_lambda_arn))

        elif request_type == 'Update':

            role_arn = role_utils.get_access_control_role_arn(
                id_data, logical_role_name)

        else:
            raise RuntimeError(
                'Unexpected request type: {}'.format(request_type))

        _add_built_in_settings(props.Settings.__dict__, stack)
        # Check if we have a folder just for this function, if not use the default
        output_key = input_key = _get_input_key(props)
        if not props.IgnoreAppendingSettingsToZip:
            output_key = _inject_settings(props.Settings.__dict__,
                                          props.Runtime,
                                          props.ConfigurationBucket, input_key,
                                          props.FunctionName)

        cc_settings = copy.deepcopy(props.Settings.__dict__)
        # Remove "Services" from settings because they get injected into the python code package during _inject_settings
        # TODO: move handling of project-level service interfaces to the same code as cross-gem interfaces
        if "Services" in cc_settings:
            del cc_settings["Services"]

        response_data = {
            'ConfigurationBucket':
            props.ConfigurationBucket,
            'ConfigurationKey':
            output_key,
            'Runtime':
            props.Runtime,
            'Role':
            role_arn,
            'RoleName':
            role_utils.get_access_control_role_name(stack_arn,
                                                    logical_role_name),
            'ComposedLambdaConfiguration': {
                'Code': {
                    'S3Bucket': props.ConfigurationBucket,
                    'S3Key': output_key
                },
                "Environment": {
                    "Variables": cc_settings
                },
                'Role': role_arn,
                'Runtime': props.Runtime
            },
            "CCSettings":
            cc_settings
        }

    physical_resource_id = aws_utils.construct_custom_physical_resource_id_with_data(
        stack_arn, event['LogicalResourceId'], id_data)
    custom_resource_response.succeed(event, context, response_data,
                                     physical_resource_id)
Пример #4
0
def handler(event, context):
    """Entry point for the Custom::ServiceApi resource handler."""
    stack_id = event['StackId']
    request_type = event['RequestType']
    logical_resource_id = event['LogicalResourceId']
    logical_role_name = logical_resource_id
    stack_manager = stack_info.StackInfoManager()
    stack = stack_manager.get_stack_info(stack_id)

    rest_api_resource_name = stack.stack_name + '-' + logical_resource_id
    id_data = aws_utils.get_data_from_custom_physical_resource_id(
        event.get('PhysicalResourceId', None))

    response_data = {}
    project_tags = {
        constant.PROJECT_NAME_TAG: stack.project_stack.project_name,
        constant.STACK_ID_TAG: stack_id
    }

    if request_type == 'Create':

        props = properties.load(event, PROPERTY_SCHEMA)
        role_arn = role_utils.create_access_control_role(
            stack_manager, id_data, stack.stack_arn, logical_role_name,
            API_GATEWAY_SERVICE_NAME)
        swagger_content = get_configured_swagger_content(
            stack, props, role_arn, rest_api_resource_name)
        rest_api_id = create_api_gateway(rest_api_resource_name, props,
                                         swagger_content)
        service_url = get_service_url(rest_api_id, stack.region)

        register_service_interfaces(stack, service_url, swagger_content)
        update_api_gateway_tags(rest_api_id, event, project_tags)

        response_data['Url'] = service_url
        id_data['RestApiId'] = rest_api_id

    elif request_type == 'Update':

        rest_api_id = id_data.get('RestApiId', None)
        if not rest_api_id:
            raise RuntimeError(
                'No RestApiId found in id_data: {}'.format(id_data))

        props = properties.load(event, PROPERTY_SCHEMA)
        role_arn = role_utils.get_access_control_role_arn(
            id_data, logical_role_name)
        swagger_content = get_configured_swagger_content(
            stack, props, role_arn, rest_api_resource_name)
        update_api_gateway(rest_api_id, props, swagger_content)
        service_url = get_service_url(rest_api_id, stack.region)
        register_service_interfaces(stack, service_url, swagger_content)

        update_api_gateway_tags(rest_api_id, event, project_tags)

        response_data['Url'] = service_url

    elif request_type == 'Delete':

        if not id_data:

            # The will be no data in the id if Cloud Formation cancels a resource creation
            # (due to a failure in another resource) before it processes the resource create
            # response. Apparently Cloud Formation has an internal temporary id for the
            # resource and uses it for the delete request.
            #
            # Unfortunately there isn't a good way to deal with this case. We don't have the
            # id data, so we can't clean up the things it identifies. At best we can allow the
            # stack cleanup to continue, leaving the rest API behind and role behind.

            print('WARNING: No id_data provided on delete.')

        else:

            rest_api_id = id_data.get('RestApiId', None)
            if not rest_api_id:
                raise RuntimeError(
                    'No RestApiId found in id_data: {}'.format(id_data))

            delete_api_gateway(rest_api_id)
            service_url = get_service_url(rest_api_id, stack.region)
            unregister_service_interfaces(stack, service_url)

            del id_data['RestApiId']

            role_utils.delete_access_control_role(id_data, logical_role_name)

    else:

        raise RuntimeError('Invalid RequestType: {}'.format(request_type))

    physical_resource_id = aws_utils.construct_custom_physical_resource_id_with_data(
        event['StackId'], logical_resource_id, id_data)

    return custom_resource_response.success_response(response_data,
                                                     physical_resource_id)
def handler(event, context):

    props = properties.load(event, PROPERTIES_SCHEMA)

    request_type = event['RequestType']
    stack_arn = event['StackId']
    logical_role_name = props.FunctionName
    stack_manager = stack_info.StackInfoManager()

    id_data = aws_utils.get_data_from_custom_physical_resource_id(event.get('PhysicalResourceId', None))

    if request_type == 'Delete':

        role_utils.delete_access_control_role(
            id_data,
            logical_role_name)

        response_data = {}

    else:

        stack = stack_manager.get_stack_info(stack_arn)

        if request_type == 'Create':

            project_service_lambda_arn = _get_project_service_lambda_arn(stack)
            assume_role_service = 'lambda.amazonaws.com'
            role_arn = role_utils.create_access_control_role(
                stack_manager,
                id_data,
                stack_arn,
                logical_role_name,
                assume_role_service,
                default_policy = get_default_policy(project_service_lambda_arn))

        elif request_type == 'Update':

            role_arn = role_utils.get_access_control_role_arn(
                id_data,
                logical_role_name)

        else:
            raise RuntimeError('Unexpected request type: {}'.format(request_type))
        _add_built_in_settings(props.Settings.__dict__, stack)
        # give access to project level ServiceDirectory APIs
        # Other deployment-level APIs are handled in InterfaceDependeny resolver custom resource type
        permitted_arns = _add_services_settings(stack, props.Settings.__dict__, props.Services)
        _add_service_access_policy_to_role(role_arn, permitted_arns)
        # Check if we have a folder just for this function, if not use the default
        output_key = input_key = _get_input_key(props)
        if not props.IgnoreAppendingSettingsToZip:
            output_key = _inject_settings(props.Settings.__dict__, props.Runtime, props.ConfigurationBucket, input_key, props.FunctionName)
        response_data = {
            'ConfigurationBucket': props.ConfigurationBucket,
            'ConfigurationKey': output_key,
            'Runtime': props.Runtime,
            'Role': role_arn,
            'RoleName': role_utils.get_access_control_role_name(stack_arn, logical_role_name),
            'ComposedLambdaConfiguration': {
                'Code': {
                    'S3Bucket': props.ConfigurationBucket,
                    'S3Key': output_key
                },
                'Role': role_arn,
                'Runtime': props.Runtime
            }
        }
        
    physical_resource_id = aws_utils.construct_custom_physical_resource_id_with_data(stack_arn, event['LogicalResourceId'], id_data)
    custom_resource_response.succeed(event, context, response_data, physical_resource_id)