def __enter__(self): self._template_dict = get_template_data(self._template_file) self._function_provider = SamFunctionProvider( self._template_dict, self._parameter_overrides) self._layer_provider = SamLayerProvider(self._template_dict, self._parameter_overrides) if not self._base_dir: # Base directory, if not provided, is the directory containing the template self._base_dir = str( pathlib.Path(self._template_file).resolve().parent) self._build_dir = self._setup_build_dir(self._build_dir, self._clean) if self._cached: cache_path = pathlib.Path(self._cache_dir) cache_path.mkdir(mode=self._BUILD_DIR_PERMISSIONS, parents=True, exist_ok=True) self._cache_dir = str(cache_path.resolve()) if self._use_container: self._container_manager = ContainerManager( docker_network_id=self._docker_network, skip_pull_image=self._skip_pull_image) return self
def test_must_return_function_value(self): provider = SamFunctionProvider({}) provider.functions = { "func1": "value" } # Cheat a bit here by setting the value of this property directly self.assertEqual("value", provider.get("func1"))
def __enter__(self): """ Performs some basic checks and returns itself when everything is ready to invoke a Lambda function. :returns InvokeContext: Returns this object """ # Grab template from file and create a provider self._template_dict = self._get_template_data(self._template_file) self._function_provider = SamFunctionProvider(self._template_dict, self.parameter_overrides) self._env_vars_value = self._get_env_vars_value(self._env_vars_file) self._log_file_handle = self._setup_log_file(self._log_file) self._debug_context = self._get_debug_context(self._debug_ports, self._debug_args, self._debugger_path) self._container_manager = self._get_container_manager( self._docker_network, self._skip_pull_image) if not self._container_manager.is_docker_reachable: raise InvokeContextException( "Running AWS SAM projects locally requires Docker. Have you got it installed?" ) return self
def test_must_return_function_value(self): provider = SamFunctionProvider([]) # Cheat a bit here by setting the value of this property directly function = Function( name="not-value", functionname="value", runtime=None, handler=None, codeuri=None, memory=None, timeout=None, environment=None, rolearn=None, layers=[], events=None, metadata=None, inlinecode=None, imageuri=None, imageconfig=None, packagetype=None, codesign_config_arn=None, stack_path=STACK_PATH, ) provider.functions = {"func1": function} self.assertEqual(function, provider.get("value"))
def auth_per_resource(stacks: List[Stack]): """ Check if authentication has been set for the function resources defined in the template that have `Api` Event type. Parameters ---------- stacks: List[Stack] The list of stacks where resources are looked for Returns ------- List of tuples per function resource that have the `Api` or `HttpApi` event types, that describes the resource name and if authorization is required per resource. """ _auth_per_resource: List[Tuple[str, bool]] = [] sam_function_provider = SamFunctionProvider( stacks, ignore_code_extraction_warnings=True) for sam_function in sam_function_provider.get_all(): # Only check for auth if there are function events defined. if sam_function.events: _auth_resource_event(sam_function_provider, sam_function, _auth_per_resource) return _auth_per_resource
def auth_per_resource(parameter_overrides, template_dict): """ Check if authentication has been set for the function resources defined in the template that have `Api` Event type. Parameters ---------- parameter_overrides: dict list of parameter overrides for the parameters defined in the template template_dict: dict Raw dictionary of the defined SAM template Returns ------- List of tuples per function resource that have the `Api` or `HttpApi` event types, that describes the resource name and if authorization is required per resource. """ _auth_per_resource = [] sam_functions = SamFunctionProvider( template_dict=template_dict, parameter_overrides=parameter_overrides, ignore_code_extraction_warnings=True) for sam_function in sam_functions.get_all(): # Only check for auth if there are function events defined. if sam_function.events: _auth_resource_event(sam_functions, sam_function, _auth_per_resource) return _auth_per_resource
def setUp(self): self.parameter_overrides = {} root_stack = Stack("", "", "template.yaml", self.parameter_overrides, self.TEMPLATE) child_stack = Stack("", "ChildStack", "./child/template.yaml", None, self.CHILD_TEMPLATE) with patch("samcli.lib.providers.sam_stack_provider.get_template_data") as get_template_data_mock: get_template_data_mock.side_effect = lambda t: { "template.yaml": self.TEMPLATE, "./child/template.yaml": self.CHILD_TEMPLATE, } self.provider = SamFunctionProvider([root_stack, child_stack])
def __enter__(self): """ Performs some basic checks and returns itself when everything is ready to invoke a Lambda function. :returns InvokeContext: Returns this object """ # Grab template from file and create a provider self._template_dict = self._get_template_data(self._template_file) self._function_provider = SamFunctionProvider(self._template_dict, self.parameter_overrides) self._env_vars_value = self._get_env_vars_value(self._env_vars_file) self._container_env_vars_value = self._get_env_vars_value( self._container_env_vars_file) self._log_file_handle = self._setup_log_file(self._log_file) # in case of warm containers && debugging is enabled && if debug-function property is not provided, so # if the provided template only contains one lambda function, so debug-function will be set to this function # if the template contains multiple functions, a warning message "that the debugging option will be ignored" # will be printed if self._containers_mode == ContainersMode.WARM and self._debug_ports and not self._debug_function: if len(self._function_provider.functions) == 1: self._debug_function = list( self._function_provider.functions.keys())[0] else: LOG.info( "Warning: you supplied debugging options but you did not specify the --debug-function option." " To specify which function you want to debug, please use the --debug-function <function-name>" ) # skipp the debugging self._debug_ports = None self._debug_context = self._get_debug_context( self._debug_ports, self._debug_args, self._debugger_path, self._container_env_vars_value, self._debug_function, ) self._container_manager = self._get_container_manager( self._docker_network, self._skip_pull_image, self._shutdown) if not self._container_manager.is_docker_reachable: raise InvokeContextException( "Running AWS SAM projects locally requires Docker. Have you got it installed and running?" ) # initialize all lambda function containers upfront if self._containers_initializing_mode == ContainersInitializationMode.EAGER: self._initialize_all_functions_containers() return self
def test_must_handle_code_s3_uri(self): name = "myname" properties = {"CodeUri": "s3://bucket/key"} result = SamFunctionProvider._convert_sam_function_resource(name, properties, []) self.assertEqual(result.codeuri, ".") # Default value
def test_must_use_inlinecode(self): name = "myname" properties = { "InlineCode": "testcode", "Runtime": "myruntime", "MemorySize": "mymemorysize", "Timeout": "30", "Handler": "index.handler", } expected = Function( name="myname", functionname="myname", runtime="myruntime", memory="mymemorysize", timeout="30", handler="index.handler", codeuri=None, environment=None, rolearn=None, layers=[], events=None, metadata=None, inlinecode="testcode", imageuri=None, imageconfig=None, packagetype=ZIP, codesign_config_arn=None, stack_path=STACK_PATH, ) result = SamFunctionProvider._convert_sam_function_resource(STACK, name, properties, []) self.assertEqual(expected, result)
def test_must_work_for_multiple_functions_with_name_but_in_different_stacks( self, convert_mock, ): function_root = Mock() function_root.name = "Func1" function_root.full_path = "Func1" function_child = Mock() function_child.name = "Func1" function_child.full_path = "C/Func1" stack_root = Mock() stack_root.resources = { "Func1": {"Type": "AWS::Lambda::Function", "Properties": {"a": "b"}}, "C": {"Type": "AWS::Serverless::Application", "Properties": {"Location": "./child.yaml"}}, } stack_child = Mock() stack_child.resources = { "Func1": {"Type": "AWS::Lambda::Function", "Properties": {"a": "b"}}, } convert_mock.side_effect = [function_root, function_child] expected = {"Func1": function_root, "C/Func1": function_child} result = SamFunctionProvider._extract_functions([stack_root, stack_child]) self.assertEqual(expected, result) convert_mock.assert_has_calls( [ call(stack_root, "Func1", {"a": "b"}, [], False), call(stack_child, "Func1", {"a": "b"}, [], False), ] )
def test_must_skip_unknown_resource(self, resources_mock): resources_mock.return_value = {"Func1": {"Type": "AWS::SomeOther::Function", "Properties": {"a": "b"}}} expected = {} result = SamFunctionProvider._extract_functions([make_root_stack(None)]) self.assertEqual(expected, result)
def test_must_skip_non_existent_properties(self): name = "myname" properties = {"Code": {"Bucket": "bucket"}} expected = Function( name="myname", functionname="myname", runtime=None, memory=None, timeout=None, handler=None, codeuri=".", environment=None, rolearn=None, layers=[], events=None, metadata=None, codesign_config_arn=None, ) result = SamFunctionProvider._convert_lambda_function_resource( name, properties, []) self.assertEqual(expected, result)
def test_layers_created_from_template_resources(self): resources = { "Layer": {"Type": "AWS::Lambda::LayerVersion", "Properties": {"Content": {"Bucket": "bucket"}}}, "ServerlessLayer": {"Type": "AWS::Serverless::LayerVersion", "Properties": {"ContentUri": "/somepath"}}, } list_of_layers = [ {"Ref": "Layer"}, {"Ref": "ServerlessLayer"}, "arn:aws:lambda:region:account-id:layer:layer-name:1", {"NonRef": "Something"}, ] actual = SamFunctionProvider._parse_layer_info( Mock(stack_path=STACK_PATH, location="template.yaml", resources=resources), list_of_layers ) for (actual_layer, expected_layer) in zip( actual, [ LayerVersion("Layer", ".", stack_path=STACK_PATH), LayerVersion("ServerlessLayer", "/somepath", stack_path=STACK_PATH), LayerVersion("arn:aws:lambda:region:account-id:layer:layer-name:1", None, stack_path=STACK_PATH), ], ): self.assertEqual(actual_layer, expected_layer)
def test_must_convert(self): name = "myname" properties = { "CodeUri": "/usr/local", "Runtime": "myruntime", "MemorySize": "mymemorysize", "Timeout": "30", "Handler": "myhandler", "Environment": "myenvironment", "Role": "myrole", "Layers": ["Layer1", "Layer2"], } expected = Function( name="myname", functionname="myname", runtime="myruntime", memory="mymemorysize", timeout="30", handler="myhandler", codeuri="/usr/local", environment="myenvironment", rolearn="myrole", layers=["Layer1", "Layer2"], events=None, metadata=None, codesign_config_arn=None, ) result = SamFunctionProvider._convert_sam_function_resource( name, properties, ["Layer1", "Layer2"]) self.assertEqual(expected, result)
def test_must_skip_non_existent_properties(self): name = "myname" properties = {"CodeUri": "/usr/local"} expected = Function( name="myname", functionname="myname", runtime=None, memory=None, timeout=None, handler=None, codeuri="/usr/local", environment=None, rolearn=None, layers=[], events=None, metadata=None, imageuri=None, imageconfig=None, packagetype=ZIP, codesign_config_arn=None, ) result = SamFunctionProvider._convert_sam_function_resource( name, properties, []) self.assertEqual(expected, result)
def test_must_default_missing_code_uri(self): name = "myname" properties = {"Runtime": "myruntime"} result = SamFunctionProvider._convert_sam_function_resource(name, properties, []) self.assertEqual(result.codeuri, ".") # Default value
def test_must_convert(self): name = "myname" properties = { "Code": { "Bucket": "bucket" }, "Runtime": "myruntime", "MemorySize": "mymemorysize", "Timeout": "30", "Handler": "myhandler", "Environment": "myenvironment", "Role": "myrole", "Layers": ["Layer1", "Layer2"], } expected = Function( name="myname", functionname="myname", runtime="myruntime", memory="mymemorysize", timeout="30", handler="myhandler", codeuri=".", environment="myenvironment", rolearn="myrole", layers=["Layer1", "Layer2"], events=None, ) result = SamFunctionProvider._convert_lambda_function_resource( name, properties, ["Layer1", "Layer2"]) self.assertEqual(expected, result)
def test_must_skip_unknown_resource(self): resources = {"Func1": {"Type": "AWS::SomeOther::Function", "Properties": {"a": "b"}}} expected = {} result = SamFunctionProvider._extract_functions(resources) self.assertEqual(expected, result)
def test_return_empty_list_on_no_layers(self): resources = {"Function": {"Type": "AWS::Serverless::Function", "Properties": {}}} actual = SamFunctionProvider._parse_layer_info( Mock(stack_path=STACK_PATH, location="template.yaml", resources=resources), [] ) self.assertEqual(actual, [])
def test_must_return_function_value(self): provider = SamFunctionProvider({}) # Cheat a bit here by setting the value of this property directly function = Function( name="not-value", functionname="value", runtime=None, handler=None, codeuri=None, memory=None, timeout=None, environment=None, rolearn=None, layers=[], ) provider.functions = {"func1": function} self.assertEqual(function, provider.get("value"))
def __enter__(self): self._template_dict = get_template_data(self._template_file) self._function_provider = SamFunctionProvider( self._template_dict, self._parameter_overrides) if not self._base_dir: # Base directory, if not provided, is the directory containing the template self._base_dir = str( pathlib.Path(self._template_file).resolve().parent) self._build_dir = self._setup_build_dir(self._build_dir, self._clean) if self._use_container: self._container_manager = ContainerManager( docker_network_id=self._docker_network, skip_pull_image=self._skip_pull_image) return self
def test_must_default_to_empty_resources(self, extract_mock, get_template_mock): extract_result = {"foo": "bar"} extract_mock.return_value = extract_result template = {"a": "b"} # Template does *not* have 'Resources' key get_template_mock.return_value = template provider = SamFunctionProvider(template, parameter_overrides=self.parameter_overrides) extract_mock.assert_called_with({}, False) # Empty Resources value must be passed self.assertEqual(provider.functions, extract_result) self.assertEqual(provider.resources, {})
def test_must_extract_functions(self, extract_mock, get_template_mock): extract_result = {"foo": "bar"} extract_mock.return_value = extract_result template = {"Resources": {"a": "b"}} get_template_mock.return_value = template provider = SamFunctionProvider(template, parameter_overrides=self.parameter_overrides) extract_mock.assert_called_with({"a": "b"}, False) get_template_mock.assert_called_with(template, self.parameter_overrides) self.assertEqual(provider.functions, extract_result)
def test_must_work_for_lambda_function(self, convert_mock): convertion_result = "some result" convert_mock.return_value = convertion_result resources = {"Func1": {"Type": "AWS::Lambda::Function", "Properties": {"a": "b"}}} expected = {"Func1": "some result"} result = SamFunctionProvider._extract_functions(resources) self.assertEqual(expected, result) convert_mock.assert_called_with("Func1", {"a": "b"}, [])
def test_return_empty_list_on_no_layers(self): resources = { "Function": { "Type": "AWS::Serverless::Function", "Properties": {} } } actual = SamFunctionProvider._parse_layer_info([], resources) self.assertEqual(actual, [])
def test_must_work_for_sam_function(self, convert_mock): convertion_result = "some result" convert_mock.return_value = convertion_result resources = {"Func1": {"Type": "AWS::Serverless::Function", "Properties": {"a": "b"}}} expected = {"Func1": "some result"} result = SamFunctionProvider._extract_functions(resources) self.assertEqual(expected, result) convert_mock.assert_called_with("Func1", {"a": "b"}, [], ignore_code_extraction_warnings=False)
def test_must_handle_code_dict(self): name = "myname" properties = { "CodeUri": { # CodeUri is some dictionary "a": "b" } } result = SamFunctionProvider._convert_sam_function_resource(name, properties, []) self.assertEqual(result.codeuri, ".") # Default value
def test_must_work_for_sam_function(self, convert_mock, resources_mock): convertion_result = Mock() convertion_result.full_path = "A/B/C/Func1" convert_mock.return_value = convertion_result resources_mock.return_value = {"Func1": {"Type": "AWS::Serverless::Function", "Properties": {"a": "b"}}} expected = {"A/B/C/Func1": convertion_result} stack = make_root_stack(None) result = SamFunctionProvider._extract_functions([stack]) self.assertEqual(expected, result) convert_mock.assert_called_with(stack, "Func1", {"a": "b"}, [], False, ignore_code_extraction_warnings=False)
def transform_template(parameter_overrides, template_dict): """ :param parameter_overrides: Dictionary of parameter overrides for the SAM template. :param template_dict: Dictionary representation of the SAM template. :return: """ sam_functions = SamFunctionProvider( template_dict=template_dict, parameter_overrides=parameter_overrides, ignore_code_extraction_warnings=True ) return sam_functions