Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions docs/globals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Currently, the following resources and properties are being supported:
AutoPublishAlias:
DeploymentPreference:
PermissionsBoundary:
ReservedConcurrentExecutions:

Api:
# Properties of AWS::Serverless::Api
Expand Down
3 changes: 2 additions & 1 deletion samtranslator/plugins/globals/globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ class Globals(object):
"AutoPublishAlias",
"Layers",
"DeploymentPreference",
"PermissionsBoundary"
"PermissionsBoundary",
"ReservedConcurrentExecutions"
],

# Everything except
Expand Down
3 changes: 3 additions & 0 deletions samtranslator/public/sdk/parameter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# flake8: noqa

from samtranslator.sdk.parameter import SamParameterValues
67 changes: 67 additions & 0 deletions samtranslator/sdk/parameter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import boto3
import copy


class SamParameterValues(object):
"""
Class representing SAM parameter values.
"""

def __init__(self, parameter_values):
"""
Initialize the object given the parameter values as a dictionary

:param dict parameter_values: Parameter value dictionary containing parameter name & value
"""

self.parameter_values = copy.deepcopy(parameter_values)

def add_default_parameter_values(self, sam_template):
"""
Method to read default values for template parameters and merge with user supplied values.

Example:
If the template contains the following parameters defined

Parameters:
Param1:
Type: String
Default: default_value
Param2:
Type: String
Default: default_value

And, the user explicitly provided the following parameter values:

{
Param2: "new value"
}

then, this method will grab default value for Param1 and return the following result:

{
Param1: "default_value",
Param2: "new value"
}


:param dict sam_template: SAM template
:param dict parameter_values: Dictionary of parameter values provided by the user
:return dict: Merged parameter values
"""

parameter_definition = sam_template.get("Parameters", None)
if not parameter_definition or not isinstance(parameter_definition, dict):
return self.parameter_values

for param_name, value in parameter_definition.items():
if param_name not in self.parameter_values and isinstance(value, dict) and "Default" in value:
self.parameter_values[param_name] = value["Default"]

def add_pseudo_parameter_values(self):
"""
Add pseudo parameter values
:return: parameter values that have pseudo parameter in it
"""
if 'AWS::Region' not in self.parameter_values:
self.parameter_values['AWS::Region'] = boto3.session.Session().region_name
64 changes: 5 additions & 59 deletions samtranslator/translator/translator.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import copy
import boto3

from samtranslator.model import ResourceTypeResolver, sam_resources
from samtranslator.translator.verify_logical_id import verify_unique_logical_id
Expand All @@ -15,6 +14,7 @@
from samtranslator.plugins.globals.globals_plugin import GlobalsPlugin
from samtranslator.plugins.policies.policy_templates_plugin import PolicyTemplatesForFunctionPlugin
from samtranslator.policy_template_processor.processor import PolicyTemplatesProcessor
from samtranslator.sdk.parameter import SamParameterValues


class Translator:
Expand Down Expand Up @@ -46,8 +46,10 @@ def translate(self, sam_template, parameter_values):
:returns: a copy of the template with SAM resources replaced with the corresponding CloudFormation, which may \
be dumped into a valid CloudFormation JSON or YAML template
"""
parameter_values = self._add_default_parameter_values(sam_template, parameter_values)
parameter_values = self._add_pseudo_parameter_values(parameter_values)
sam_parameter_values = SamParameterValues(parameter_values)
sam_parameter_values.add_default_parameter_values(sam_template)
sam_parameter_values.add_pseudo_parameter_values()
parameter_values = sam_parameter_values.parameter_values
# Create & Install plugins
sam_plugins = prepare_plugins(self.plugins, parameter_values)

Expand Down Expand Up @@ -157,62 +159,6 @@ def _get_resources_to_iterate(self, sam_template, macro_resolver):

return functions + apis + others

# Ideally this should belong to a separate class called "Parameters" or something that knows how to manage
# parameters. An instance of this class should be passed as input to the Translate class.
def _add_default_parameter_values(self, sam_template, parameter_values):
"""
Method to read default values for template parameters and merge with user supplied values.

Example:
If the template contains the following parameters defined

Parameters:
Param1:
Type: String
Default: default_value
Param2:
Type: String
Default: default_value

And, the user explicitly provided the following parameter values:

{
Param2: "new value"
}

then, this method will grab default value for Param1 and return the following result:

{
Param1: "default_value",
Param2: "new value"
}


:param dict sam_template: SAM template
:param dict parameter_values: Dictionary of parameter values provided by the user
:return dict: Merged parameter values
"""

parameter_definition = sam_template.get("Parameters", None)
if not parameter_definition or not isinstance(parameter_definition, dict):
return parameter_values

default_values = {}
for param_name, value in parameter_definition.items():
if isinstance(value, dict) and "Default" in value:
default_values[param_name] = value["Default"]

# Any explicitly provided value must override the default
default_values.update(parameter_values)

return default_values

def _add_pseudo_parameter_values(self, parameter_values):
updated_parameter_values = copy.deepcopy(parameter_values)
if 'AWS::Region' not in updated_parameter_values:
updated_parameter_values['AWS::Region'] = boto3.session.Session().region_name
return updated_parameter_values


def prepare_plugins(plugins, parameters={}):
"""
Expand Down
136 changes: 136 additions & 0 deletions tests/sdk/test_parameter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
from parameterized import parameterized, param

import pytest
from unittest import TestCase
from samtranslator.sdk.parameter import SamParameterValues
from mock import patch

class TestSAMParameterValues(TestCase):

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_parameter_values = SamParameterValues(parameter_values)
sam_parameter_values.add_default_parameter_values(sam_template)
self.assertEqual(expected, sam_parameter_values.parameter_values)

def test_add_default_parameter_values_must_override_user_specified_values(self):
parameter_values = {
"Param1": "value1"
}

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

expected = {
"Param1": "value1"
}

sam_parameter_values = SamParameterValues(parameter_values)
sam_parameter_values.add_default_parameter_values(sam_template)
self.assertEqual(expected, sam_parameter_values.parameter_values)

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_parameter_values = SamParameterValues(parameter_values)
sam_parameter_values.add_default_parameter_values(sam_template)
self.assertEqual(expected, sam_parameter_values.parameter_values)


@parameterized.expand([
# Array
param(["1", "2"]),

# String
param("something"),

# Some other non-parameter looking dictionary
param({"Param1": {"Foo": "Bar"}}),

param(None)
])
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_parameter_values = SamParameterValues(parameter_values)
sam_parameter_values.add_default_parameter_values(sam_template)
self.assertEqual(expected, sam_parameter_values.parameter_values)

@patch('boto3.session.Session.region_name', 'ap-southeast-1')
def test_add_pseudo_parameter_values_aws_region(self):
parameter_values = {
"Param1": "value1"
}

expected = {
"Param1": "value1",
"AWS::Region": "ap-southeast-1"
}

sam_parameter_values = SamParameterValues(parameter_values)
sam_parameter_values.add_pseudo_parameter_values()
self.assertEqual(expected, sam_parameter_values.parameter_values)

@patch('boto3.session.Session.region_name', 'ap-southeast-1')
def test_add_pseudo_parameter_values_aws_region_not_override(self):
parameter_values = {
"AWS::Region": "value1"
}

expected = {
"AWS::Region": "value1"
}

sam_parameter_values = SamParameterValues(parameter_values)
sam_parameter_values.add_pseudo_parameter_values()
self.assertEqual(expected, sam_parameter_values.parameter_values)
2 changes: 2 additions & 0 deletions tests/translator/input/globals_for_function.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Globals:
PermissionsBoundary: arn:aws:1234:iam:boundary/CustomerCreatedPermissionsBoundary
Layers:
- !Sub arn:${AWS:Partition}:lambda:${AWS:Region}:${AWS:AccountId}:layer:MyLayer:1
ReservedConcurrentExecutions: 50

Resources:
MinimalFunction:
Expand All @@ -45,4 +46,5 @@ Resources:
PermissionsBoundary: arn:aws:1234:iam:boundary/OverridePermissionsBoundary
Layers:
- !Sub arn:${AWS:Partition}:lambda:${AWS:Region}:${AWS:AccountId}:layer:MyLayer2:2
ReservedConcurrentExecutions: 100

2 changes: 2 additions & 0 deletions tests/translator/output/aws-cn/globals_for_function.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
}
],
"MemorySize": 512,
"ReservedConcurrentExecutions": 100,
"Environment": {
"Variables": {
"Var1": "value1",
Expand Down Expand Up @@ -146,6 +147,7 @@
}
],
"MemorySize": 1024,
"ReservedConcurrentExecutions": 50,
"Environment": {
"Variables": {
"Var1": "value1",
Expand Down
2 changes: 2 additions & 0 deletions tests/translator/output/aws-us-gov/globals_for_function.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
}
],
"MemorySize": 512,
"ReservedConcurrentExecutions": 100,
"Environment": {
"Variables": {
"Var1": "value1",
Expand Down Expand Up @@ -146,6 +147,7 @@
}
],
"MemorySize": 1024,
"ReservedConcurrentExecutions": 50,
"Environment": {
"Variables": {
"Var1": "value1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"errors": [
{
"errorMessage": "'Globals' section is invalid. 'SomeKey' is not a supported property of 'Function'. Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'Layers', 'DeploymentPreference', 'PermissionsBoundary']"
"errorMessage": "'Globals' section is invalid. 'SomeKey' is not a supported property of 'Function'. Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'Layers', 'DeploymentPreference', 'PermissionsBoundary', 'ReservedConcurrentExecutions']"
}
],
"errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. 'Globals' section is invalid. 'SomeKey' is not a supported property of 'Function'. Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'Layers', 'DeploymentPreference', 'PermissionsBoundary']"
"errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. 'Globals' section is invalid. 'SomeKey' is not a supported property of 'Function'. Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'Layers', 'DeploymentPreference', 'PermissionsBoundary', 'ReservedConcurrentExecutions']"
}
2 changes: 2 additions & 0 deletions tests/translator/output/globals_for_function.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
}
],
"MemorySize": 512,
"ReservedConcurrentExecutions": 100,
"Environment": {
"Variables": {
"Var1": "value1",
Expand Down Expand Up @@ -146,6 +147,7 @@
}
],
"MemorySize": 1024,
"ReservedConcurrentExecutions": 50,
"Environment": {
"Variables": {
"Var1": "value1",
Expand Down
Loading