Пример #1
0
    def _add_api_to_swagger(self, event_id, event_properties, template):
        """
        Adds the API path/method from the given event to the Swagger JSON of Serverless::Api resource this event
        refers to.

        :param string event_id: LogicalId of the event
        :param dict event_properties: Properties of the event
        :param SamTemplate template: SAM Template to search for Serverless::Api resources
        """

        # "RestApiId" property of the event contains the logical Id to the AWS::Serverless::Api resource.
        # Need to grab the resource and update Swagger from it
        api_id = event_properties.get("RestApiId")
        if isinstance(api_id, dict) and "Ref" in api_id:
            api_id = api_id["Ref"]

        # RestApiId is not pointing to a valid  API resource
        if isinstance(api_id, dict) or not template.get(api_id):
            raise InvalidEventException(
                event_id,
                "RestApiId must be a valid reference to an 'AWS::Serverless::Api' resource "
                "in same template")

        # Make sure Swagger is valid
        resource = template.get(api_id)
        if not (resource and isinstance(resource.properties, dict)
                and SwaggerEditor.is_valid(
                    resource.properties.get("DefinitionBody"))):
            # This does not have an inline Swagger. Nothing can be done about it.
            return

        if not resource.properties.get("__MANAGE_SWAGGER"):
            # Do not add the api to Swagger, if the resource is not actively managed by SAM.
            # ie. Implicit API resources are created & managed by SAM on behalf of customers.
            # But for explicit API resources, customers write their own Swagger and manage it.
            # If a path is present in Events section but *not* present in the Explicit API Swagger, then it is
            # customer's responsibility to add to Swagger. We will not modify the Swagger here.
            #
            # In the future, we will might expose a flag that will allow SAM to manage explicit API Swagger as well.
            # Until then, we will not modify explicit explicit APIs.
            return

        swagger = resource.properties.get("DefinitionBody")

        path = event_properties["Path"]
        method = event_properties["Method"]
        editor = SwaggerEditor(swagger)
        editor.add_path(path, method)

        resource.properties["DefinitionBody"] = editor.swagger
        template.set(api_id, resource)
    def _add_api_to_swagger(self, event_id, event_properties, template):
        """
        Adds the API path/method from the given event to the Swagger JSON of Serverless::Api resource this event
        refers to.

        :param string event_id: LogicalId of the event
        :param dict event_properties: Properties of the event
        :param SamTemplate template: SAM Template to search for Serverless::Api resources
        """

        # "RestApiId" property of the event contains the logical Id to the AWS::Serverless::Api resource.
        # Need to grab the resource and update Swagger from it
        api_id = event_properties.get("RestApiId")
        if isinstance(api_id, dict) and "Ref" in api_id:
            api_id = api_id["Ref"]

        # RestApiId is not pointing to a valid  API resource
        if isinstance(api_id, dict) or not template.get(api_id):
            raise InvalidEventException(event_id,
                                        "RestApiId must be a valid reference to an 'AWS::Serverless::Api' resource "
                                        "in same template")

        # Make sure Swagger is valid
        resource = template.get(api_id)
        if not (resource and
                    isinstance(resource.properties, dict) and
                    SwaggerEditor.is_valid(resource.properties.get("DefinitionBody"))):
            # This does not have an inline Swagger. Nothing can be done about it.
            return

        if not resource.properties.get("__MANAGE_SWAGGER"):
            # Do not add the api to Swagger, if the resource is not actively managed by SAM.
            # ie. Implicit API resources are created & managed by SAM on behalf of customers.
            # But for explicit API resources, customers write their own Swagger and manage it.
            # If a path is present in Events section but *not* present in the Explicit API Swagger, then it is
            # customer's responsibility to add to Swagger. We will not modify the Swagger here.
            #
            # In the future, we will might expose a flag that will allow SAM to manage explicit API Swagger as well.
            # Until then, we will not modify explicit explicit APIs.
            return

        swagger = resource.properties.get("DefinitionBody")

        path = event_properties["Path"]
        method = event_properties["Method"]
        editor = SwaggerEditor(swagger)
        editor.add_path(path, method)

        resource.properties["DefinitionBody"] = editor.swagger
        template.set(api_id, resource)
    def __init__(self):
        swagger = SwaggerEditor.gen_skeleton()

        resource = {
            "Type": SamResourceType.Api.value,
            "Properties": {
                # Because we set the StageName to be constant value here, customers cannot override StageName with
                # Globals. This is because, if a property is specified in both Globals and the resource, the resource
                # one takes precedence.
                "StageName": "Prod",
                "DefinitionBody": swagger,
                # Internal property that means Event source code can add Events. Used only for implicit APIs, to
                # prevent back compatibility issues for explicit APIs
                "__MANAGE_SWAGGER": True,
            },
        }

        super(ImplicitApiResource, self).__init__(resource)
    def __init__(self):
        swagger = SwaggerEditor.gen_skeleton()

        resource = {
            "Type": SamResourceType.Api.value,
            "Properties": {

                # Because we set the StageName to be constant value here, customers cannot override StageName with
                # Globals. This is because, if a property is specified in both Globals and the resource, the resource
                # one takes precedence.
                "StageName": "Prod",

                "DefinitionBody": swagger,
                # Internal property that means Event source code can add Events. Used only for implicit APIs, to
                # prevent back compatibility issues for explicit APIs
                "__MANAGE_SWAGGER": True
            }
        }

        super(ImplicitApiResource, self).__init__(resource)
Пример #5
0
    def _maybe_add_conditions_to_implicit_api_paths(self, template):
        """
        Add conditions to implicit API paths if necessary.

        Implicit API resource methods are constructed from API events on individual serverless functions within the SAM
        template. Since serverless functions can have conditions on them, it's possible to have a case where all methods
        under a resource path have conditions on them. If all of these conditions evaluate to false, the entire resource
        path should not be defined either. This method checks all resource paths' methods and if all methods under a
        given path contain a condition, a composite condition is added to the overall template Conditions section and
        that composite condition is added to the resource path.
        """

        for api_id, api in template.iterate(SamResourceType.Api.value):
            if not api.properties.get('__MANAGE_SWAGGER'):
                continue

            swagger = api.properties.get("DefinitionBody")
            editor = SwaggerEditor(swagger)

            for path in editor.iter_on_path():
                all_method_conditions = set([
                    condition for method, condition in
                    self.api_conditions[api_id][path].items()
                ])
                at_least_one_method = len(all_method_conditions) > 0
                all_methods_contain_conditions = None not in all_method_conditions
                if at_least_one_method and all_methods_contain_conditions:
                    if len(all_method_conditions) == 1:
                        editor.make_path_conditional(
                            path, all_method_conditions.pop())
                    else:
                        path_condition_name = self._path_condition_name(
                            api_id, path)
                        self._add_combined_condition_to_template(
                            template.template_dict, path_condition_name,
                            all_method_conditions)
                        editor.make_path_conditional(path, path_condition_name)

            api.properties["DefinitionBody"] = editor.swagger
            template.set(api_id, api)
    def _maybe_add_conditions_to_implicit_api_paths(self, template):
        """
        Add conditions to implicit API paths if necessary.

        Implicit API resource methods are constructed from API events on individual serverless functions within the SAM
        template. Since serverless functions can have conditions on them, it's possible to have a case where all methods
        under a resource path have conditions on them. If all of these conditions evaluate to false, the entire resource
        path should not be defined either. This method checks all resource paths' methods and if all methods under a
        given path contain a condition, a composite condition is added to the overall template Conditions section and
        that composite condition is added to the resource path.
        """

        for api_id, api in template.iterate(SamResourceType.Api.value):
            if not api.properties.get('__MANAGE_SWAGGER'):
                continue

            swagger = api.properties.get("DefinitionBody")
            editor = SwaggerEditor(swagger)

            for path in editor.iter_on_path():
                all_method_conditions = set(
                    [condition for method, condition in self.api_conditions[api_id][path].items()]
                )
                at_least_one_method = len(all_method_conditions) > 0
                all_methods_contain_conditions = None not in all_method_conditions
                if at_least_one_method and all_methods_contain_conditions:
                    if len(all_method_conditions) == 1:
                        editor.make_path_conditional(path, all_method_conditions.pop())
                    else:
                        path_condition_name = self._path_condition_name(api_id, path)
                        self._add_combined_condition_to_template(
                            template.template_dict, path_condition_name, all_method_conditions)
                        editor.make_path_conditional(path, path_condition_name)

            api.properties["DefinitionBody"] = editor.swagger
            template.set(api_id, api)