def test_transform_method_must_inject_plugins_when_creating_resources(
            self, prepare_plugins_mock, sam_plugins_class_mock,
            resource_from_dict_mock):
        manifest = {
            "Resources": {
                "MyTable": {
                    "Type": "AWS::Serverless::SimpleTable",
                    "Properties": {}
                }
            }
        }

        sam_plugins_object_mock = Mock()
        sam_plugins_class_mock.return_value = sam_plugins_object_mock
        prepare_plugins_mock.return_value = sam_plugins_object_mock
        resource_from_dict_mock.return_value = SamSimpleTable("MyFunction")

        initial_plugins = [1, 2, 3]
        sam_parser = Parser()
        translator = Translator({}, sam_parser, plugins=initial_plugins)
        translator.translate(manifest, {})

        resource_from_dict_mock.assert_called_with(
            "MyTable",
            manifest["Resources"]["MyTable"],
            sam_plugins=sam_plugins_object_mock)
        prepare_plugins_mock.assert_called_once_with(initial_plugins, {
            "AWS::Region": "ap-southeast-1",
            "AWS::Partition": "aws"
        })
    def test_throws_when_resource_not_found(self):
        template = {"foo": "bar"}

        with self.assertRaises(InvalidDocumentException):
            sam_parser = Parser()
            translator = Translator({}, sam_parser)
            translator.translate(template, {})
    def test_transform_method_must_inject_plugins_when_creating_resources(self,
                                                                          prepare_plugins_mock,
                                                                          sam_plugins_class_mock,
                                                                          resource_from_dict_mock):
        manifest = {
            'Resources': {
                'MyTable': {
                    'Type': 'AWS::Serverless::SimpleTable',
                    'Properties': {
                    }
                }
            }
        }

        sam_plugins_object_mock = Mock()
        sam_plugins_class_mock.return_value = sam_plugins_object_mock
        prepare_plugins_mock.return_value = sam_plugins_object_mock
        resource_from_dict_mock.return_value = SamSimpleTable("MyFunction")

        initial_plugins = [1,2,3]
        sam_parser = Parser()
        translator = Translator({}, sam_parser, plugins=initial_plugins)
        translator.translate(manifest, {})

        resource_from_dict_mock.assert_called_with("MyTable",
                                                        manifest["Resources"]["MyTable"],
                                                        sam_plugins=sam_plugins_object_mock)
        prepare_plugins_mock.assert_called_once_with(initial_plugins, {"AWS::Region": "ap-southeast-1"})
    def test_throws_when_resource_is_not_dict(self):
        template = {"Resources": [1, 2, 3]}

        with self.assertRaises(InvalidDocumentException):
            sam_parser = Parser()
            translator = Translator({}, sam_parser)
            translator.translate(template, {})
Beispiel #5
0
    def is_valid(self):
        """
        Runs the SAM Translator to determine if the template provided is valid. This is similar to running a
        ChangeSet in CloudFormation for a SAM Template

        Raises
        -------
        InvalidSamDocumentException
             If the template is not valid, an InvalidSamDocumentException is raised
        """
        managed_policy_map = self.managed_policy_loader.load()

        sam_translator = Translator(managed_policy_map=managed_policy_map,
                                    sam_parser=self.sam_parser,
                                    plugins=[])

        self._replace_local_codeuri()

        try:
            template = sam_translator.translate(sam_template=self.sam_template,
                                                parameter_values={})
            LOG.debug("Translated template is:\n%s", yaml_dump(template))
        except InvalidDocumentException as e:
            raise InvalidSamDocumentException(
                functools.reduce(
                    lambda message, error: message + " " + str(error),
                    e.causes, str(e))) from e
    def test_throws_when_resources_not_all_dicts(self):
        template = {"Resources": {"notadict": None, "MyResource": {}}}

        with self.assertRaises(InvalidDocumentException):
            sam_parser = Parser()
            translator = Translator({}, sam_parser)
            translator.translate(template, {})
    def test_throws_when_resource_not_found(self):
        template = {
            "foo": "bar"
        }

        with self.assertRaises(InvalidDocumentException):
            sam_parser = Parser()
            translator = Translator({}, sam_parser)
            translator.translate(template, {})
Beispiel #8
0
    def transform_template(self):
        """
        Transform the Template using the Serverless Application Model.
        """
        matches = []

        try:
            # Output the SAM Translator version in debug mode
            LOGGER.debug('SAM Translator: %s', samtranslator.__version__)

            sam_translator = Translator(
                managed_policy_map=self._managed_policy_map,
                sam_parser=self._sam_parser)

            self._replace_local_codeuri()

            # Tell SAM to use the region we're linting in, this has to be controlled using the default AWS mechanisms, see also:
            # https://github.com/awslabs/serverless-application-model/blob/master/samtranslator/translator/arn_generator.py
            os.environ['AWS_DEFAULT_REGION'] = self._region

            # In the Paser class, within the SAM Translator, they log a warning for when the template
            # does not match the schema. The logger they use is the root logger instead of one scoped to
            # their module. Currently this does not cause templates to fail, so we will suppress this
            # by patching the logging.warning method that is used in that class.
            class WarningSuppressLogger(object):
                """ Patch the Logger in SAM """
                def __init__(self, obj_to_patch):
                    self.obj_to_patch = obj_to_patch

                def __enter__(self):
                    self.obj_to_patch.warning = self.warning

                def __exit__(self, exc_type, exc_val, exc_tb):
                    self.obj_to_patch.warning = self.obj_to_patch.warning

                def warning(self, message):
                    """ Ignore warnings from SAM """

            with WarningSuppressLogger(parser.logging):
                self._template = cfnlint.helpers.convert_dict(
                    sam_translator.translate(sam_template=self._template,
                                             parameter_values={}))
        except InvalidDocumentException as e:
            for cause in e.causes:
                matches.append(
                    cfnlint.Match(1, 1, 1, 1, self._filename,
                                  cfnlint.TransformError(), cause.message))
        except Exception as e:  # pylint: disable=W0703
            LOGGER.debug('Error transforming template: %s', str(e))
            LOGGER.debug('Stack trace: %s', e, exc_info=True)
            message = 'Error transforming template: {0}'
            matches.append(
                cfnlint.Match(1, 1, 1, 1, self._filename,
                              cfnlint.TransformError(),
                              message.format(str(e))))

        return matches
    def test_throws_when_resource_is_not_dict(self):
        template = {
            "Resources": [1,2,3]
        }

        with self.assertRaises(InvalidDocumentException):
            sam_parser = Parser()
            translator = Translator({}, sam_parser)
            translator.translate(template, {})
def transform(input_fragment, parameter_values, managed_policy_loader):
    """Translates the SAM manifest provided in the and returns the translation to CloudFormation.

    :param dict input_fragment: the SAM template to transform
    :param dict parameter_values: Parameter values provided by the user
    :returns: the transformed CloudFormation template
    :rtype: dict
    """

    sam_parser = Parser()
    translator = Translator(managed_policy_loader.load(), sam_parser)
    return translator.translate(input_fragment, parameter_values=parameter_values)
    def test_throws_when_resources_not_all_dicts(self):
        template = {
            "Resources": {
                "notadict": None,
                "MyResource": {}
            }
        }

        with self.assertRaises(InvalidDocumentException):
            sam_parser = Parser()
            translator = Translator({}, sam_parser)
            translator.translate(template, {})
Beispiel #12
0
    def test_add_default_parameter_values_must_ignore_invalid_template_parameters(
            self, template_parameters):
        parameter_values = {"Param1": "value1"}

        expected = {"Param1": "value1"}

        sam_template = {"Parameters": template_parameters}

        sam_parser = Parser()
        translator = Translator({}, sam_parser)
        result = translator._add_default_parameter_values(
            sam_template, parameter_values)
        self.assertEquals(expected, result)
Beispiel #13
0
    def __translate(self, parameter_values):
        """
        This method is unused and a Work In Progress
        """

        template_copy = self.template

        sam_parser = Parser()
        sam_translator = Translator(managed_policy_map=self.__managed_policy_map(),
                                    sam_parser=sam_parser,
                                    # Default plugins are already initialized within the Translator
                                    plugins=self.extra_plugins)

        return sam_translator.translate(sam_template=template_copy,
                                        parameter_values=parameter_values)
Beispiel #14
0
    def __translate(self, parameter_values):
        """
        This method is unused and a Work In Progress
        """

        template_copy = self.template

        sam_parser = Parser()
        sam_translator = Translator(managed_policy_map=self.__managed_policy_map(),
                                    sam_parser=sam_parser,
                                    # Default plugins are already initialized within the Translator
                                    plugins=self.extra_plugins)

        return sam_translator.translate(sam_template=template_copy,
                                        parameter_values=parameter_values)
Beispiel #15
0
    def transform_template(self):
        """
        Transform the Template using the Serverless Application Model.
        """
        matches = []

        try:
            # Output the SAM Translator version in debug mode
            LOGGER.info('SAM Translator: %s', samtranslator.__version__)

            sam_translator = Translator(
                managed_policy_map=self._managed_policy_map,
                sam_parser=self._sam_parser)

            self._replace_local_codeuri()

            # Tell SAM to use the region we're linting in, this has to be
            # controlled using the default AWS mechanisms, see also:
            # https://github.com/awslabs/serverless-application-model/blob/master/samtranslator/translator/arn_generator.py
            LOGGER.info('Setting AWS_DEFAULT_REGION to %s', self._region)
            os.environ['AWS_DEFAULT_REGION'] = self._region

            self._template = convert_dict(
                sam_translator.translate(sam_template=self._template,
                                         parameter_values=self._parameters))

            LOGGER.info('Transformed template: \n%s',
                        format_json_string(self._template))
        except InvalidDocumentException as e:
            message = 'Error transforming template: {0}'
            for cause in e.causes:
                matches.append(Match(
                    1, 1,
                    1, 1,
                    self._filename,
                    TransformError(), message.format(cause.message)))
        except Exception as e:  # pylint: disable=W0703
            LOGGER.debug('Error transforming template: %s', str(e))
            LOGGER.debug('Stack trace: %s', e, exc_info=True)
            message = 'Error transforming template: {0}'
            matches.append(Match(
                1, 1,
                1, 1,
                self._filename,
                TransformError(), message.format(str(e))))

        return matches
Beispiel #16
0
    def is_valid(self):
        """
        Runs the SAM Translator to determine if the template provided is valid. This is similar to running a
        ChangeSet in CloudFormation for a SAM Template

        Raises
        -------
        InvalidSamDocumentException
             If the template is not valid, an InvalidSamDocumentException is raised
        """
        managed_policy_map = self.managed_policy_loader.load()

        sam_translator = Translator(managed_policy_map=managed_policy_map,
                                    sam_parser=self.sam_parser,
                                    plugins=[])

        self._replace_local_codeuri()

        # In the Paser class, within the SAM Translator, they log a warning for when the template
        # does not match the schema. The logger they use is the root logger instead of one scoped to
        # their module. Currently this does not cause templates to fail, so we will suppress this
        # by patching the logging.warning method that is used in that class.
        class WarningSuppressLogger(object):
            def __init__(self, obj_to_patch):
                self.obj_to_patch = obj_to_patch

            def __enter__(self):
                self.obj_to_patch.warning = self.warning

            def __exit__(self, exc_type, exc_val, exc_tb):
                self.obj_to_patch.warning = self.obj_to_patch.warning

            def warning(self, message):
                pass

        try:
            with WarningSuppressLogger(parser.logging):
                template = sam_translator.translate(
                    sam_template=self.sam_template, parameter_values={})
                LOG.debug("Translated template is:\n%s", yaml_dump(template))
        except InvalidDocumentException as e:
            raise InvalidSamDocumentException(
                functools.reduce(
                    lambda message, error: message + ' ' + str(error),
                    e.causes, str(e)))
    def is_valid(self):
        """
        Runs the SAM Translator to determine if the template provided is valid. This is similar to running a
        ChangeSet in CloudFormation for a SAM Template

        Raises
        -------
        InvalidSamDocumentException
             If the template is not valid, an InvalidSamDocumentException is raised
        """
        managed_policy_map = self.managed_policy_loader.load()

        sam_translator = Translator(managed_policy_map=managed_policy_map,
                                    sam_parser=self.sam_parser,
                                    plugins=[])

        self._replace_local_codeuri()

        # In the Paser class, within the SAM Translator, they log a warning for when the template
        # does not match the schema. The logger they use is the root logger instead of one scoped to
        # their module. Currently this does not cause templates to fail, so we will suppress this
        # by patching the logging.warning method that is used in that class.
        class WarningSuppressLogger(object):

            def __init__(self, obj_to_patch):
                self.obj_to_patch = obj_to_patch

            def __enter__(self):
                self.obj_to_patch.warning = self.warning

            def __exit__(self, exc_type, exc_val, exc_tb):
                self.obj_to_patch.warning = self.obj_to_patch.warning

            def warning(self, message):
                pass

        try:
            with WarningSuppressLogger(parser.logging):
                template = sam_translator.translate(sam_template=self.sam_template,
                                                    parameter_values={})
                LOG.debug("Translated template is:\n%s", yaml_dump(template))
        except InvalidDocumentException as e:
            raise InvalidSamDocumentException(
                functools.reduce(lambda message, error: message + ' ' + str(error), e.causes, str(e)))
Beispiel #18
0
    def test_add_default_parameter_values_must_merge(self):
        parameter_values = {"Param1": "value1"}

        sam_template = {
            "Parameters": {
                "Param2": {
                    "Type": "String",
                    "Default": "template default"
                }
            }
        }

        expected = {"Param1": "value1", "Param2": "template default"}

        sam_parser = Parser()
        translator = Translator({}, sam_parser)
        result = translator._add_default_parameter_values(
            sam_template, parameter_values)
        self.assertEquals(expected, result)
Beispiel #19
0
    def transform_template(self):
        """
        Transform the Template using the Serverless Application Model.
        """
        matches = []

        try:
            sam_translator = Translator(
                managed_policy_map=self._managed_policy_map,
                sam_parser=self._sam_parser)

            self._replace_local_codeuri()

            # In the Paser class, within the SAM Translator, they log a warning for when the template
            # does not match the schema. The logger they use is the root logger instead of one scoped to
            # their module. Currently this does not cause templates to fail, so we will suppress this
            # by patching the logging.warning method that is used in that class.
            class WarningSuppressLogger(object):
                """ Patch the Logger in SAM """
                def __init__(self, obj_to_patch):
                    self.obj_to_patch = obj_to_patch

                def __enter__(self):
                    self.obj_to_patch.warning = self.warning

                def __exit__(self, exc_type, exc_val, exc_tb):
                    self.obj_to_patch.warning = self.obj_to_patch.warning

                def warning(self, message):
                    """ Ignore warnings from SAM """
                    pass

            with WarningSuppressLogger(parser.logging):
                sam_translator.translate(sam_template=self._template,
                                         parameter_values={})
        except InvalidDocumentException as e:
            for cause in e.causes:
                matches.append(
                    cfnlint.Match(1, 1, 1, 1, self._filename,
                                  cfnlint.TransformError(), cause.message))

        return matches
    def test_add_default_parameter_values_must_skip_params_without_defaults(
            self):
        parameter_values = {"Param1": "value1"}

        sam_template = {
            "Parameters": {
                "Param1": {
                    "Type": "String"
                },
                "Param2": {
                    "Type": "String"
                }
            }
        }

        expected = {"Param1": "value1"}

        sam_parser = Parser()
        translator = Translator({}, sam_parser)
        result = translator._add_default_parameter_values(
            sam_template, parameter_values)
        self.assertEqual(expected, result)