Skip to content
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

feat: allow user to provide role for schedule #3363

Merged
merged 8 commits into from
Oct 5, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class ScheduleEventProperties(BaseModel):
Schedule: Optional[PassThroughProp] = scheduleeventproperties("Schedule")
State: Optional[PassThroughProp] = scheduleeventproperties("State")
Target: Optional[ScheduleTarget] = scheduleeventproperties("Target")
Role: Optional[PassThroughProp] # TODO: add doc


class ScheduleEvent(BaseModel):
Expand Down
31 changes: 22 additions & 9 deletions samtranslator/model/stepfunctions/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class Schedule(EventSource):
"DeadLetterConfig": PropertyType(False, IS_DICT),
"RetryPolicy": PropertyType(False, IS_DICT),
"Target": Property(False, IS_DICT),
"Role": Property(False, IS_STR),
}

Schedule: PassThrough
Expand All @@ -104,6 +105,7 @@ class Schedule(EventSource):
DeadLetterConfig: Optional[Dict[str, Any]]
RetryPolicy: Optional[PassThrough]
Target: Optional[PassThrough]
Role: Optional[PassThrough]

@cw_timer(prefix=SFN_EVETSOURCE_METRIC_PREFIX)
def to_cloudformation(self, resource, **kwargs): # type: ignore[no-untyped-def]
Expand Down Expand Up @@ -135,8 +137,10 @@ def to_cloudformation(self, resource, **kwargs): # type: ignore[no-untyped-def]
events_rule.Name = self.Name
events_rule.Description = self.Description

role = self._construct_role(resource, permissions_boundary) # type: ignore[no-untyped-call]
resources.append(role)
role = None
if self.Role is None:
role = self._construct_role(resource, permissions_boundary) # type: ignore[no-untyped-call]
sidhujus marked this conversation as resolved.
Show resolved Hide resolved
resources.append(role)

source_arn = events_rule.get_runtime_attr("arn")
dlq_queue_arn = None
Expand All @@ -146,11 +150,11 @@ def to_cloudformation(self, resource, **kwargs): # type: ignore[no-untyped-def]
self, source_arn, passthrough_resource_attributes
)
resources.extend(dlq_resources)
events_rule.Targets = [self._construct_target(resource, role, dlq_queue_arn)] # type: ignore[no-untyped-call]
events_rule.Targets = [self._construct_target(resource, role, self.Role, dlq_queue_arn)] # type: ignore[no-untyped-call]

return resources

def _construct_target(self, resource, role, dead_letter_queue_arn=None): # type: ignore[no-untyped-def]
def _construct_target(self, resource, role, provided_role=None, dead_letter_queue_arn=None): # type: ignore[no-untyped-def]
sidhujus marked this conversation as resolved.
Show resolved Hide resolved
sidhujus marked this conversation as resolved.
Show resolved Hide resolved
"""Constructs the Target property for the EventBridge Rule.

sidhujus marked this conversation as resolved.
Show resolved Hide resolved
:returns: the Target property
Expand All @@ -161,11 +165,20 @@ def _construct_target(self, resource, role, dead_letter_queue_arn=None): # type
if self.Target and "Id" in self.Target
else generate_valid_target_id(self.logical_id, EVENT_RULE_SFN_TARGET_SUFFIX)
)
target = {
"Arn": resource.get_runtime_attr("arn"),
"Id": target_id,
"RoleArn": role.get_runtime_attr("arn"),
}

if provided_role:
role_arn = fnSub("arn:aws:iam::${AWS::AccountId}:role/${Role}", {"Role": provided_role})
sidhujus marked this conversation as resolved.
Show resolved Hide resolved
target = {
"Arn": resource.get_runtime_attr("arn"),
"Id": target_id,
"RoleArn": role_arn,
}
else:
target = {
"Arn": resource.get_runtime_attr("arn"),
"Id": target_id,
"RoleArn": role.get_runtime_attr("arn"),
}
if self.Input is not None:
target["Input"] = self.Input

Expand Down
3 changes: 3 additions & 0 deletions samtranslator/schema/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -251046,6 +251046,9 @@
"markdownDescription": "A `RetryPolicy` object that includes information about the retry policy settings\\. For more information, see [Event retry policy and using dead\\-letter queues](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html) in the *Amazon EventBridge User Guide*\\. \n*Type*: [RetryPolicy](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-target.html#cfn-events-rule-target-retrypolicy) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`RetryPolicy`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-target.html#cfn-events-rule-target-retrypolicy) property of the `AWS::Events::Rule` `Target` data type\\.",
"title": "RetryPolicy"
},
"Role": {
"$ref": "#/definitions/PassThroughProp"
},
"Schedule": {
"allOf": [
{
Expand Down
3 changes: 3 additions & 0 deletions schema_source/sam.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3013,6 +3013,9 @@
"markdownDescription": "A `RetryPolicy` object that includes information about the retry policy settings\\. For more information, see [Event retry policy and using dead\\-letter queues](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html) in the *Amazon EventBridge User Guide*\\. \n*Type*: [RetryPolicy](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-target.html#cfn-events-rule-target-retrypolicy) \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`RetryPolicy`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-target.html#cfn-events-rule-target-retrypolicy) property of the `AWS::Events::Rule` `Target` data type\\.",
"title": "RetryPolicy"
},
"Role": {
"$ref": "#/definitions/PassThroughProp"
},
"Schedule": {
"allOf": [
{
Expand Down
10 changes: 10 additions & 0 deletions tests/model/stepfunctions/test_schedule_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from parameterized import parameterized
from samtranslator.model.exceptions import InvalidEventException
from samtranslator.model.intrinsics import fnSub
from samtranslator.model.stepfunctions.events import Schedule


Expand Down Expand Up @@ -153,6 +154,15 @@ def test_to_cloudformation_with_dlq_generated_with_intrinsic_function_custom_log
with self.assertRaises(InvalidEventException):
self.schedule_event_source.to_cloudformation(resource=self.state_machine)

def test_to_cloudformation_with_role_arn_provided(self):
role = "ScheduleRole"
self.schedule_event_source.Role = role
resources = self.schedule_event_source.to_cloudformation(resource=self.state_machine)
event_rule = resources[0]
self.assertEqual(
event_rule.Targets[0]["RoleArn"], fnSub("arn:aws:iam::${AWS::AccountId}:role/${Role}", {"Role": role})
)

@parameterized.expand(
[
(True, "Enabled"),
Expand Down
32 changes: 32 additions & 0 deletions tests/translator/input/state_machine_with_schedule_role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Resources:

MyStateMachine:
Type: AWS::Serverless::StateMachine
Properties:
Definition:
Comment: A Hello World example of the Amazon States Language using Pass states
StartAt: Hello
States:
Hello:
Type: Pass
Result: Hello
Next: World
World:
Type: Pass
Result: World
End: true
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Deny
Action: '*'
Resource: '*'
sidhujus marked this conversation as resolved.
Show resolved Hide resolved

Events:
sidhujus marked this conversation as resolved.
Show resolved Hide resolved
CWSchedule:
Type: Schedule
Properties:
Schedule: rate(1 minute)
Description: test schedule
Enabled: false
Role: with-role-MyStateMachineCWScheduleRole-RI4SGRI1ORL9
111 changes: 111 additions & 0 deletions tests/translator/output/aws-cn/state_machine_with_schedule_role.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
{
"Resources": {
"MyStateMachine": {
"Properties": {
"DefinitionString": {
"Fn::Join": [
"\n",
[
"{",
" \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",",
" \"StartAt\": \"Hello\",",
" \"States\": {",
" \"Hello\": {",
" \"Next\": \"World\",",
" \"Result\": \"Hello\",",
" \"Type\": \"Pass\"",
" },",
" \"World\": {",
" \"End\": true,",
" \"Result\": \"World\",",
" \"Type\": \"Pass\"",
" }",
" }",
"}"
]
]
},
"RoleArn": {
"Fn::GetAtt": [
"MyStateMachineRole",
"Arn"
]
},
"Tags": [
{
"Key": "stateMachine:createdBy",
"Value": "SAM"
}
]
},
"Type": "AWS::StepFunctions::StateMachine"
},
"MyStateMachineCWSchedule": {
"Properties": {
"Description": "test schedule",
"ScheduleExpression": "rate(1 minute)",
"State": "DISABLED",
"Targets": [
{
"Arn": {
"Ref": "MyStateMachine"
},
"Id": "MyStateMachineCWScheduleStepFunctionsTarget",
"RoleArn": {
"Fn::Sub": [
"arn:aws:iam::${AWS::AccountId}:role/${Role}",
{
"Role": "with-role-MyStateMachineCWScheduleRole-RI4SGRI1ORL9"
}
]
}
}
]
},
"Type": "AWS::Events::Rule"
},
"MyStateMachineRole": {
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Effect": "Allow",
"Principal": {
"Service": [
"states.amazonaws.com"
]
}
}
],
"Version": "2012-10-17"
},
"ManagedPolicyArns": [],
"Policies": [
{
"PolicyDocument": {
"Statement": [
{
"Action": "*",
"Effect": "Deny",
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"PolicyName": "MyStateMachineRolePolicy0"
}
],
"Tags": [
{
"Key": "stateMachine:createdBy",
"Value": "SAM"
}
]
},
"Type": "AWS::IAM::Role"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
{
"Resources": {
"MyStateMachine": {
"Properties": {
"DefinitionString": {
"Fn::Join": [
"\n",
[
"{",
" \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",",
" \"StartAt\": \"Hello\",",
" \"States\": {",
" \"Hello\": {",
" \"Next\": \"World\",",
" \"Result\": \"Hello\",",
" \"Type\": \"Pass\"",
" },",
" \"World\": {",
" \"End\": true,",
" \"Result\": \"World\",",
" \"Type\": \"Pass\"",
" }",
" }",
"}"
]
]
},
"RoleArn": {
"Fn::GetAtt": [
"MyStateMachineRole",
"Arn"
]
},
"Tags": [
{
"Key": "stateMachine:createdBy",
"Value": "SAM"
}
]
},
"Type": "AWS::StepFunctions::StateMachine"
},
"MyStateMachineCWSchedule": {
"Properties": {
"Description": "test schedule",
"ScheduleExpression": "rate(1 minute)",
"State": "DISABLED",
"Targets": [
{
"Arn": {
"Ref": "MyStateMachine"
},
"Id": "MyStateMachineCWScheduleStepFunctionsTarget",
"RoleArn": {
"Fn::Sub": [
"arn:aws:iam::${AWS::AccountId}:role/${Role}",
{
"Role": "with-role-MyStateMachineCWScheduleRole-RI4SGRI1ORL9"
}
]
}
}
]
},
"Type": "AWS::Events::Rule"
},
"MyStateMachineRole": {
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Effect": "Allow",
"Principal": {
"Service": [
"states.amazonaws.com"
]
}
}
],
"Version": "2012-10-17"
},
"ManagedPolicyArns": [],
"Policies": [
{
"PolicyDocument": {
"Statement": [
{
"Action": "*",
"Effect": "Deny",
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"PolicyName": "MyStateMachineRolePolicy0"
}
],
"Tags": [
{
"Key": "stateMachine:createdBy",
"Value": "SAM"
}
]
},
"Type": "AWS::IAM::Role"
}
}
}
Loading