-
Notifications
You must be signed in to change notification settings - Fork 2.5k
feat: support conditional AWS::NoValue in SAM Function's IAM Role #3842
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
samtranslator/model/sam_resources.py
Outdated
| lambda_function.Role = execution_role.get_runtime_attr("arn") | ||
|
|
||
| if is_intrinsic_if(lambda_role): | ||
| resources.append(execution_role) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not exactly correct here. In theory we need to create this role only if one of the values is AWS::NoValue.
If the Role field has an If with two different roles, then we shouldn't create the new one. (so, move this resources.append to inside a new condition "if 1 or 2 are intrinsic_no_value"
|
|
||
| cfn_resources = self.function.to_cloudformation(**self.kwargs) | ||
| generated_roles = [x for x in cfn_resources if isinstance(x, IAMRole)] | ||
| lambda_function = next(r for r in cfn_resources if r.resource_type == "AWS::Lambda::Function") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can do the same than for the roles with the functions: generated_functions = [x for x in cfnResources if isinstance(x, LambdaFunction)]
and then you can also confirm that there's only one created.
But it's not a big deal. We can probably change it in the future if needed.
tests/model/test_sam_resources.py
Outdated
| template = {"Conditions": {"Condition": True}} | ||
| kwargs = dict(self.kwargs) | ||
| kwargs["conditions"] = template.get("Conditions", {}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't use the variable template anywhere else, so you could just remove it and define the conditions below. (same in other tests)
| template = {"Conditions": {"Condition": True}} | |
| kwargs = dict(self.kwargs) | |
| kwargs["conditions"] = template.get("Conditions", {}) | |
| kwargs = dict(self.kwargs) | |
| kwargs["conditions"] = {"Condition": True} |
tests/model/test_sam_resources.py
Outdated
| self.function.CodeUri = "s3://foobar/foo.zip" | ||
| self.function.Runtime = "foo" | ||
| self.function.Handler = "bar" | ||
| self.template = {"Conditions": {}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need this self.template variable since it's not being used. Right below you use it to get Conditions from here, but it will be just {}, so you can just do that ("conditions": {})
samtranslator/model/sam_resources.py
Outdated
| if lambda_role is None: | ||
| resources.append(execution_role) | ||
| lambda_function.Role = execution_role.get_runtime_attr("arn") | ||
|
|
||
| elif is_intrinsic_if(lambda_role): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can avoid a indentation by early return
| if lambda_role is None: | |
| resources.append(execution_role) | |
| lambda_function.Role = execution_role.get_runtime_attr("arn") | |
| elif is_intrinsic_if(lambda_role): | |
| if lambda_role is None: | |
| resources.append(execution_role) | |
| lambda_function.Role = execution_role.get_runtime_attr("arn") | |
| return | |
| if not is_intrinsic_if(lambda_role): | |
| return |
|
|
||
| def _make_lambda_role( | ||
| self, | ||
| lambda_function: LambdaFunction, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this implementation has some unnecessary change IMO, we can keep the if lambda_function.Role is None part as is, then _make_lambda_role can return the created role, so we don't need to pass in lambda_function in this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One other concern is we are modifying values for lambda_function, execution_role, resources, conditions ( which are the function's input) inside this function which returns None, but all these values might have changed after running this function. This might make this part of the code harder to review in the future. If we need to change all these variable's value in place, I would perfer to implement this directly in to_cloudformation instead of this subfunction. If you really prefer to have this subfunction. Maybe we can return the new value instead of modifying them inplace. So future reviewers could easily understand these variables are modified in this subfunction.
| if role_changes["should_append_role"]: | ||
| resources.append(execution_role) | ||
|
|
||
| if role_changes["lambda_role_value"] is not None: | ||
| lambda_function.Role = role_changes["lambda_role_value"] | ||
|
|
||
| if role_changes["execution_role_condition"] is not None: | ||
| execution_role.set_resource_attribute("Condition", role_changes["execution_role_condition"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can change this a little bit so you return a role_changes["execution_role_resource"] that it's either execution_role or None. And you set the Condition attribute inside the function not here outside.
so then you have
if role_changes["execution_role_resource"] is not None:
resources.append(role_changes["execution_role_resource"])
and that role comes ready to be added, you can change its resource_attribute("Condition, inside the function instead of here.
samtranslator/model/sam_resources.py
Outdated
| result = { | ||
| "should_append_role": False, | ||
| "lambda_role_value": None, | ||
| "execution_role_condition": None, | ||
| "new_condition": None, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another recommendation. Work with the simple variables first. And them to the result only at the very end for returning. Using the result variable for all the following manipulations makes the code look so much worse.
Issue #, if available
#3736
Description of changes
Support
AWS::NoValueconditional for Role property inAWS::Serverless::FunctionRole is an optional string value for
AWS::Serverless::Function. An execution role is auto generated code when the value is None. This change adds support forAWS::NoValue.Use cases :
AWS::NoValuecreates an execution role for both true and false case and replacesAWS::NoValueAWS::NoValuecreates an execution role and replacesAWS::NoValueFn::GetAttgets passed through as is.Description of how you validated changes
sam-translate.pywith templates and verified translated templatesChecklist
Examples?
Please reach out in the comments if you want to add an example. Examples will be
added to
sam initthrough aws/aws-sam-cli-app-templates.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.