Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions bin/sam-translate.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
from samtranslator.public.translator import ManagedPolicyLoader
from samtranslator.translator.transform import transform
from samtranslator.yaml_helper import yaml_parse
from samtranslator.model.exceptions import InvalidDocumentException


cli_options = docopt(__doc__)
iam_client = boto3.client('iam')
Expand All @@ -42,15 +44,21 @@ def main():
with open(input_file_path, 'r') as f:
sam_template = yaml_parse(f)

cloud_formation_template = transform(
sam_template, {}, ManagedPolicyLoader(iam_client))
cloud_formation_template_prettified = json.dumps(
cloud_formation_template, indent=2)

with open(output_file_path, 'w') as f:
f.write(cloud_formation_template_prettified)

print('Wrote transformed CloudFormation template to: ' + output_file_path)
try:
cloud_formation_template = transform(
sam_template, {}, ManagedPolicyLoader(iam_client))
cloud_formation_template_prettified = json.dumps(
cloud_formation_template, indent=2)

with open(output_file_path, 'w') as f:
f.write(cloud_formation_template_prettified)

print('Wrote transformed CloudFormation template to: ' + output_file_path)
except InvalidDocumentException as e:
errorMessage = reduce(lambda message, error: message + ' ' + error.message, e.causes, e.message)
print(errorMessage)
errors = map(lambda cause: {'errorMessage': cause.message}, e.causes)
print(errors)


if __name__ == '__main__':
Expand Down
3 changes: 0 additions & 3 deletions samtranslator/model/api/api_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,6 @@ def _construct_rest_api(self):
rest_api.BodyS3Location = self._construct_body_s3_dict()
elif self.definition_body:
rest_api.Body = self.definition_body
else:
raise InvalidResourceException(self.logical_id,
"Either 'DefinitionUri' or 'DefinitionBody' property is required")

if self.name:
rest_api.Name = self.name
Expand Down
37 changes: 37 additions & 0 deletions samtranslator/plugins/api/default_definition_body_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from samtranslator.plugins import BasePlugin
from samtranslator.swagger.swagger import SwaggerEditor
from samtranslator.public.sdk.resource import SamResourceType
from samtranslator.public.sdk.template import SamTemplate


class DefaultDefinitionBodyPlugin(BasePlugin):
"""
If the user does not provide a DefinitionBody or DefinitionUri
on an AWS::Serverless::Api resource, the Swagger constructed by
SAM is used. It accomplishes this by simply setting DefinitionBody
to a minimum Swagger definition and sets `__MANAGE_SWAGGER: true`.
"""

def __init__(self):
"""
Initialize the plugin.
"""

super(DefaultDefinitionBodyPlugin, self).__init__(DefaultDefinitionBodyPlugin.__name__)

def on_before_transform_template(self, template_dict):
"""
Hook method that gets called before the SAM template is processed.
The template has pass the validation and is guaranteed to contain a non-empty "Resources" section.
:param dict template_dict: Dictionary of the SAM template
:return: Nothing
"""
template = SamTemplate(template_dict)

for logicalId, api in template.iterate(SamResourceType.Api.value):
if api.properties.get('DefinitionBody') or api.properties.get('DefinitionUri'):
continue

api.properties['DefinitionBody'] = SwaggerEditor.gen_skeleton()
api.properties['__MANAGE_SWAGGER'] = True
2 changes: 2 additions & 0 deletions samtranslator/translator/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
InvalidEventException
from samtranslator.intrinsics.resolver import IntrinsicsResolver
from samtranslator.intrinsics.resource_refs import SupportedResourceReferences
from samtranslator.plugins.api.default_definition_body_plugin import DefaultDefinitionBodyPlugin
from samtranslator.plugins import SamPlugins
from samtranslator.plugins.globals.globals_plugin import GlobalsPlugin
from samtranslator.plugins.policies.policy_templates_plugin import PolicyTemplatesForFunctionPlugin
Expand Down Expand Up @@ -198,6 +199,7 @@ def prepare_plugins(plugins):
"""

required_plugins = [
DefaultDefinitionBodyPlugin(),
make_implicit_api_plugin(),
GlobalsPlugin(),
make_policy_template_for_function_plugin(),
Expand Down
51 changes: 51 additions & 0 deletions tests/plugins/api/test_default_definition_body_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from unittest import TestCase
from mock import Mock, patch

from samtranslator.plugins.api.default_definition_body_plugin import DefaultDefinitionBodyPlugin
from samtranslator.public.plugins import BasePlugin

IMPLICIT_API_LOGICAL_ID = "ServerlessRestApi"


class TestDefaultDefinitionBodyPlugin_init(TestCase):

def setUp(self):
self.plugin = DefaultDefinitionBodyPlugin()

def test_plugin_must_setup_correct_name(self):
# Name is the class name
expected_name = "DefaultDefinitionBodyPlugin"

self.assertEquals(self.plugin.name, expected_name)

def test_plugin_must_be_instance_of_base_plugin_class(self):
self.assertTrue(isinstance(self.plugin, BasePlugin))


class TestDefaultDefinitionBodyPlugin_on_before_transform_template(TestCase):

def setUp(self):
self.plugin = DefaultDefinitionBodyPlugin()

@patch("samtranslator.plugins.api.default_definition_body_plugin.SamTemplate")
def test_must_process_functions(self, SamTemplateMock):

template_dict = {"a": "b"}
api_resources = [("id1", ApiResource()), ("id2", ApiResource()), ("id3", ApiResource())]

sam_template = Mock()
SamTemplateMock.return_value = sam_template
sam_template.iterate = Mock()
sam_template.iterate.return_value = api_resources

self.plugin.on_before_transform_template(template_dict)

SamTemplateMock.assert_called_with(template_dict)

# Make sure this is called only for Apis
sam_template.iterate.assert_called_with("AWS::Serverless::Api")


class ApiResource(object):
def __init__(self):
self.properties = {}
34 changes: 34 additions & 0 deletions tests/translator/input/api_with_cors_no_definitionbody.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Globals:
Api:
# If we skip AllowMethods, then SAM will auto generate a list of methods scoped to each path
Cors: "origins"

Resources:
ImplicitApiFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: s3://sam-demo-bucket/member_portal.zip
Handler: index.gethtml
Runtime: nodejs4.3
Events:
GetHtml:
Type: Api
Properties:
RestApiId: !Ref ExplicitApi
Path: /
Method: get

PostHtml:
Type: Api
Properties:
RestApiId: !Ref ExplicitApi
Path: /
Method: post


ExplicitApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Loading