Skip to content

Commit aace39d

Browse files
authored
Allow Qualifier to be defined with Id in Serverless Connectors (#2768)
1 parent dda8497 commit aace39d

File tree

6 files changed

+247
-7
lines changed

6 files changed

+247
-7
lines changed

samtranslator/model/connector/connector.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -80,20 +80,22 @@ def get_event_source_mappings(event_source_id: str, function_id: str, resource_r
8080

8181
def _is_valid_resource_reference(obj: Dict[str, Any]) -> bool:
8282
id_provided = "Id" in obj
83-
non_id_provided = len([k for k in obj.keys() if k != "Id"]) > 0
84-
# Must provide either Id, or a combination of other properties, but not both
83+
non_id_provided = len([k for k in obj.keys() if k not in ["Id", "Qualifier"]]) > 0
84+
# Must provide Id (with optional Qualifier) or a supported combination of other properties.
8585
return id_provided != non_id_provided
8686

8787

8888
def get_resource_reference(
8989
obj: Dict[str, Any], resource_resolver: ResourceResolver, connecting_obj: Dict[str, Any]
9090
) -> ConnectorResourceReference:
9191
if not _is_valid_resource_reference(obj):
92-
raise ConnectorResourceError("Must provide either 'Id' or a combination of the other properties, not both.")
92+
raise ConnectorResourceError(
93+
"Must provide 'Id' (with optional 'Qualifier') or a supported combination of other properties."
94+
)
9395

9496
logical_id = obj.get("Id")
9597

96-
# Must either provide Id or a combination of the other properties (not both).
98+
# Must provide Id (with optional Qualifier) or a supported combination of other properties
9799
# If Id is not provided, all values must come from overrides.
98100
if not logical_id:
99101
resource_type = obj.get("Type")
@@ -136,7 +138,7 @@ def get_resource_reference(
136138

137139
name = _get_resource_name(logical_id, resource_type)
138140

139-
qualifier = _get_resource_qualifier(resource_type)
141+
qualifier = obj.get("Qualifier") if "Qualifier" in obj else _get_resource_qualifier(resource_type)
140142

141143
return ConnectorResourceReference(
142144
logical_id=logical_id,

tests/translator/input/connector_hardcoded_props.yaml

+22
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,28 @@ Resources:
7575
Permissions:
7676
- Write
7777

78+
ApiV1ToLambdaWithId:
79+
Type: AWS::Serverless::Connector
80+
Properties:
81+
Source:
82+
Id: MyApiV1
83+
Qualifier: Prod/GET/foobar
84+
Destination:
85+
Id: MyFunction
86+
Permissions:
87+
- Write
88+
89+
ApiV2ToLambdaWithId:
90+
Type: AWS::Serverless::Connector
91+
Properties:
92+
Source:
93+
Id: MyApiV2
94+
Qualifier: '*'
95+
Destination:
96+
Id: MyFunction
97+
Permissions:
98+
- Write
99+
78100
SfnToSfn:
79101
Type: AWS::Serverless::Connector
80102
Properties:

tests/translator/output/aws-cn/connector_hardcoded_props.json

+72
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,41 @@
11
{
22
"Resources": {
3+
"ApiV1ToLambdaWithIdWriteLambdaPermission": {
4+
"Metadata": {
5+
"aws:sam:connectors": {
6+
"ApiV1ToLambdaWithId": {
7+
"Destination": {
8+
"Type": "AWS::Lambda::Function"
9+
},
10+
"Source": {
11+
"Type": "AWS::ApiGateway::RestApi"
12+
}
13+
}
14+
}
15+
},
16+
"Properties": {
17+
"Action": "lambda:InvokeFunction",
18+
"FunctionName": {
19+
"Fn::GetAtt": [
20+
"MyFunction",
21+
"Arn"
22+
]
23+
},
24+
"Principal": "apigateway.amazonaws.com",
25+
"SourceArn": {
26+
"Fn::Sub": [
27+
"arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SourceResourceId}/${SourceQualifier}",
28+
{
29+
"SourceQualifier": "Prod/GET/foobar",
30+
"SourceResourceId": {
31+
"Ref": "MyApiV1"
32+
}
33+
}
34+
]
35+
}
36+
},
37+
"Type": "AWS::Lambda::Permission"
38+
},
339
"ApiV1ToLambdaWriteLambdaPermission": {
440
"Metadata": {
541
"aws:sam:connectors": {
@@ -36,6 +72,42 @@
3672
},
3773
"Type": "AWS::Lambda::Permission"
3874
},
75+
"ApiV2ToLambdaWithIdWriteLambdaPermission": {
76+
"Metadata": {
77+
"aws:sam:connectors": {
78+
"ApiV2ToLambdaWithId": {
79+
"Destination": {
80+
"Type": "AWS::Lambda::Function"
81+
},
82+
"Source": {
83+
"Type": "AWS::ApiGatewayV2::Api"
84+
}
85+
}
86+
}
87+
},
88+
"Properties": {
89+
"Action": "lambda:InvokeFunction",
90+
"FunctionName": {
91+
"Fn::GetAtt": [
92+
"MyFunction",
93+
"Arn"
94+
]
95+
},
96+
"Principal": "apigateway.amazonaws.com",
97+
"SourceArn": {
98+
"Fn::Sub": [
99+
"arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SourceResourceId}/${SourceQualifier}",
100+
{
101+
"SourceQualifier": "*",
102+
"SourceResourceId": {
103+
"Ref": "MyApiV2"
104+
}
105+
}
106+
]
107+
}
108+
},
109+
"Type": "AWS::Lambda::Permission"
110+
},
39111
"ApiV2ToLambdaWriteLambdaPermission": {
40112
"Metadata": {
41113
"aws:sam:connectors": {

tests/translator/output/aws-us-gov/connector_hardcoded_props.json

+72
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,41 @@
11
{
22
"Resources": {
3+
"ApiV1ToLambdaWithIdWriteLambdaPermission": {
4+
"Metadata": {
5+
"aws:sam:connectors": {
6+
"ApiV1ToLambdaWithId": {
7+
"Destination": {
8+
"Type": "AWS::Lambda::Function"
9+
},
10+
"Source": {
11+
"Type": "AWS::ApiGateway::RestApi"
12+
}
13+
}
14+
}
15+
},
16+
"Properties": {
17+
"Action": "lambda:InvokeFunction",
18+
"FunctionName": {
19+
"Fn::GetAtt": [
20+
"MyFunction",
21+
"Arn"
22+
]
23+
},
24+
"Principal": "apigateway.amazonaws.com",
25+
"SourceArn": {
26+
"Fn::Sub": [
27+
"arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SourceResourceId}/${SourceQualifier}",
28+
{
29+
"SourceQualifier": "Prod/GET/foobar",
30+
"SourceResourceId": {
31+
"Ref": "MyApiV1"
32+
}
33+
}
34+
]
35+
}
36+
},
37+
"Type": "AWS::Lambda::Permission"
38+
},
339
"ApiV1ToLambdaWriteLambdaPermission": {
440
"Metadata": {
541
"aws:sam:connectors": {
@@ -36,6 +72,42 @@
3672
},
3773
"Type": "AWS::Lambda::Permission"
3874
},
75+
"ApiV2ToLambdaWithIdWriteLambdaPermission": {
76+
"Metadata": {
77+
"aws:sam:connectors": {
78+
"ApiV2ToLambdaWithId": {
79+
"Destination": {
80+
"Type": "AWS::Lambda::Function"
81+
},
82+
"Source": {
83+
"Type": "AWS::ApiGatewayV2::Api"
84+
}
85+
}
86+
}
87+
},
88+
"Properties": {
89+
"Action": "lambda:InvokeFunction",
90+
"FunctionName": {
91+
"Fn::GetAtt": [
92+
"MyFunction",
93+
"Arn"
94+
]
95+
},
96+
"Principal": "apigateway.amazonaws.com",
97+
"SourceArn": {
98+
"Fn::Sub": [
99+
"arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SourceResourceId}/${SourceQualifier}",
100+
{
101+
"SourceQualifier": "*",
102+
"SourceResourceId": {
103+
"Ref": "MyApiV2"
104+
}
105+
}
106+
]
107+
}
108+
},
109+
"Type": "AWS::Lambda::Permission"
110+
},
39111
"ApiV2ToLambdaWriteLambdaPermission": {
40112
"Metadata": {
41113
"aws:sam:connectors": {

tests/translator/output/connector_hardcoded_props.json

+72
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,41 @@
11
{
22
"Resources": {
3+
"ApiV1ToLambdaWithIdWriteLambdaPermission": {
4+
"Metadata": {
5+
"aws:sam:connectors": {
6+
"ApiV1ToLambdaWithId": {
7+
"Destination": {
8+
"Type": "AWS::Lambda::Function"
9+
},
10+
"Source": {
11+
"Type": "AWS::ApiGateway::RestApi"
12+
}
13+
}
14+
}
15+
},
16+
"Properties": {
17+
"Action": "lambda:InvokeFunction",
18+
"FunctionName": {
19+
"Fn::GetAtt": [
20+
"MyFunction",
21+
"Arn"
22+
]
23+
},
24+
"Principal": "apigateway.amazonaws.com",
25+
"SourceArn": {
26+
"Fn::Sub": [
27+
"arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SourceResourceId}/${SourceQualifier}",
28+
{
29+
"SourceQualifier": "Prod/GET/foobar",
30+
"SourceResourceId": {
31+
"Ref": "MyApiV1"
32+
}
33+
}
34+
]
35+
}
36+
},
37+
"Type": "AWS::Lambda::Permission"
38+
},
339
"ApiV1ToLambdaWriteLambdaPermission": {
440
"Metadata": {
541
"aws:sam:connectors": {
@@ -36,6 +72,42 @@
3672
},
3773
"Type": "AWS::Lambda::Permission"
3874
},
75+
"ApiV2ToLambdaWithIdWriteLambdaPermission": {
76+
"Metadata": {
77+
"aws:sam:connectors": {
78+
"ApiV2ToLambdaWithId": {
79+
"Destination": {
80+
"Type": "AWS::Lambda::Function"
81+
},
82+
"Source": {
83+
"Type": "AWS::ApiGatewayV2::Api"
84+
}
85+
}
86+
}
87+
},
88+
"Properties": {
89+
"Action": "lambda:InvokeFunction",
90+
"FunctionName": {
91+
"Fn::GetAtt": [
92+
"MyFunction",
93+
"Arn"
94+
]
95+
},
96+
"Principal": "apigateway.amazonaws.com",
97+
"SourceArn": {
98+
"Fn::Sub": [
99+
"arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${SourceResourceId}/${SourceQualifier}",
100+
{
101+
"SourceQualifier": "*",
102+
"SourceResourceId": {
103+
"Ref": "MyApiV2"
104+
}
105+
}
106+
]
107+
}
108+
},
109+
"Type": "AWS::Lambda::Permission"
110+
},
39111
"ApiV2ToLambdaWriteLambdaPermission": {
40112
"Metadata": {
41113
"aws:sam:connectors": {

tests/translator/output/error_connector.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 16. Resource with id [BothIdAndOtherProps] is invalid. Must provide either 'Id' or a combination of the other properties, not both. Resource with id [EmptyListPermissionConnector] is invalid. 'Permissions' cannot be empty; valid values are: Read, Write. Resource with id [EmptyPermissionConnector] is invalid. Missing required property 'Permissions'. Resource with id [MissingLambdaFunctionArn] is invalid. Source.Arn is missing. Resource with id [MissingRole] is invalid. Unable to get IAM role name from 'Source' resource. Resource with id [MissingRoleDestination] is invalid. Unable to get IAM role name from 'Destination' resource. Resource with id [MissingSnsTopicArn] is invalid. Destination.Arn is missing. Resource with id [MissingSqsQueueUrl] is invalid. Destination.Arn is missing. Resource with id [NoIdMissingType] is invalid. 'Type' is missing or not a string. Resource with id [NoPermissionConnector] is invalid. Missing required property 'Permissions'. Resource with id [NonExistentLogicalId] is invalid. Unable to find resource with logical ID 'ThisDoesntExist'. Resource with id [NonStrId] is invalid. 'Id' is missing or not a string. Resource with id [ResourceWithoutType] is invalid. 'Type' is missing or not a string. Resource with id [UnsupportedAccessCategory] is invalid. Unsupported 'Permissions' provided; valid values are: Read, Write. Resource with id [UnsupportedAccessCategoryCombination] is invalid. Unsupported 'Permissions' provided; valid combinations are: Read + Write. Resource with id [UnsupportedType] is invalid. Unable to create connector from AWS::Fancy::CoolType to AWS::Lambda::Function; it's not supported or the template is invalid.",
2+
"errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 16. Resource with id [BothIdAndOtherProps] is invalid. Must provide 'Id' (with optional 'Qualifier') or a supported combination of other properties. Resource with id [EmptyListPermissionConnector] is invalid. 'Permissions' cannot be empty; valid values are: Read, Write. Resource with id [EmptyPermissionConnector] is invalid. Missing required property 'Permissions'. Resource with id [MissingLambdaFunctionArn] is invalid. Source.Arn is missing. Resource with id [MissingRole] is invalid. Unable to get IAM role name from 'Source' resource. Resource with id [MissingRoleDestination] is invalid. Unable to get IAM role name from 'Destination' resource. Resource with id [MissingSnsTopicArn] is invalid. Destination.Arn is missing. Resource with id [MissingSqsQueueUrl] is invalid. Destination.Arn is missing. Resource with id [NoIdMissingType] is invalid. 'Type' is missing or not a string. Resource with id [NoPermissionConnector] is invalid. Missing required property 'Permissions'. Resource with id [NonExistentLogicalId] is invalid. Unable to find resource with logical ID 'ThisDoesntExist'. Resource with id [NonStrId] is invalid. 'Id' is missing or not a string. Resource with id [ResourceWithoutType] is invalid. 'Type' is missing or not a string. Resource with id [UnsupportedAccessCategory] is invalid. Unsupported 'Permissions' provided; valid values are: Read, Write. Resource with id [UnsupportedAccessCategoryCombination] is invalid. Unsupported 'Permissions' provided; valid combinations are: Read + Write. Resource with id [UnsupportedType] is invalid. Unable to create connector from AWS::Fancy::CoolType to AWS::Lambda::Function; it's not supported or the template is invalid.",
33
"errors": [
44
{
55
"errorMessage": "Resource with id [NoIdMissingType] is invalid. 'Type' is missing or not a string."
@@ -38,7 +38,7 @@
3838
"errorMessage": "Resource with id [MissingSnsTopicArn] is invalid. Destination.Arn is missing."
3939
},
4040
{
41-
"errorMessage": "Resource with id [BothIdAndOtherProps] is invalid. Must provide either 'Id' or a combination of the other properties, not both."
41+
"errorMessage": "Resource with id [BothIdAndOtherProps] is invalid. Must provide 'Id' (with optional 'Qualifier') or a supported combination of other properties."
4242
},
4343
{
4444
"errorMessage": "Resource with id [NoPermissionConnector] is invalid. Missing required property 'Permissions'"

0 commit comments

Comments
 (0)