From 13f948e7f1cbce761eee60e96ab63085d7c0a783 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 11:30:25 -0700 Subject: [PATCH 1/6] chore(schema): update (#3352) Co-authored-by: github-actions --- samtranslator/schema/schema.json | 165 +++++++++++++++++++++++ schema_source/cloudformation.schema.json | 165 +++++++++++++++++++++++ 2 files changed, 330 insertions(+) diff --git a/samtranslator/schema/schema.json b/samtranslator/schema/schema.json index f15cb6e32..a62d08e7d 100644 --- a/samtranslator/schema/schema.json +++ b/samtranslator/schema/schema.json @@ -46343,6 +46343,102 @@ ], "type": "object" }, + "AWS::Connect::SecurityProfile": { + "additionalProperties": false, + "properties": { + "Condition": { + "type": "string" + }, + "DeletionPolicy": { + "enum": [ + "Delete", + "Retain", + "Snapshot" + ], + "type": "string" + }, + "DependsOn": { + "anyOf": [ + { + "pattern": "^[a-zA-Z0-9]+$", + "type": "string" + }, + { + "items": { + "pattern": "^[a-zA-Z0-9]+$", + "type": "string" + }, + "type": "array" + } + ] + }, + "Metadata": { + "type": "object" + }, + "Properties": { + "additionalProperties": false, + "properties": { + "AllowedAccessControlTags": { + "items": { + "$ref": "#/definitions/Tag" + }, + "type": "array" + }, + "Description": { + "type": "string" + }, + "InstanceArn": { + "type": "string" + }, + "Permissions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "SecurityProfileName": { + "type": "string" + }, + "TagRestrictedResources": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Tags": { + "items": { + "$ref": "#/definitions/Tag" + }, + "type": "array" + } + }, + "required": [ + "InstanceArn", + "SecurityProfileName" + ], + "type": "object" + }, + "Type": { + "enum": [ + "AWS::Connect::SecurityProfile" + ], + "type": "string" + }, + "UpdateReplacePolicy": { + "enum": [ + "Delete", + "Retain", + "Snapshot" + ], + "type": "string" + } + }, + "required": [ + "Type", + "Properties" + ], + "type": "object" + }, "AWS::Connect::TaskTemplate": { "additionalProperties": false, "properties": { @@ -66158,6 +66254,9 @@ "title": "DestinationIpv6CidrBlock", "type": "string" }, + "DestinationPrefixListId": { + "type": "string" + }, "EgressOnlyInternetGatewayId": { "markdownDescription": "[IPv6 traffic only] The ID of an egress-only internet gateway.", "title": "EgressOnlyInternetGatewayId", @@ -74995,6 +75094,9 @@ "title": "ProvisionedThroughputInMibps", "type": "number" }, + "ReplicationConfiguration": { + "$ref": "#/definitions/AWS::EFS::FileSystem.ReplicationConfiguration" + }, "ThroughputMode": { "markdownDescription": "Specifies the throughput mode for the file system. The mode can be `bursting` , `provisioned` , or `elastic` . If you set `ThroughputMode` to `provisioned` , you must also set a value for `ProvisionedThroughputInMibps` . After you create the file system, you can decrease your file system's throughput in Provisioned Throughput mode or change between the throughput modes, with certain time restrictions. For more information, see [Specifying throughput with provisioned mode](https://docs.aws.amazon.com/efs/latest/ug/performance.html#provisioned-throughput) in the *Amazon EFS User Guide* .\n\nDefault is `elastic` .", "title": "ThroughputMode", @@ -75073,6 +75175,36 @@ }, "type": "object" }, + "AWS::EFS::FileSystem.ReplicationConfiguration": { + "additionalProperties": false, + "properties": { + "Destinations": { + "items": { + "$ref": "#/definitions/AWS::EFS::FileSystem.ReplicationDestination" + }, + "type": "array" + } + }, + "type": "object" + }, + "AWS::EFS::FileSystem.ReplicationDestination": { + "additionalProperties": false, + "properties": { + "AvailabilityZoneName": { + "type": "string" + }, + "FileSystemId": { + "type": "string" + }, + "KmsKeyId": { + "type": "string" + }, + "Region": { + "type": "string" + } + }, + "type": "object" + }, "AWS::EFS::MountTarget": { "additionalProperties": false, "properties": { @@ -131260,6 +131392,9 @@ "title": "Power", "type": "string" }, + "PrivateRegistryAccess": { + "$ref": "#/definitions/AWS::Lightsail::Container.PrivateRegistryAccess" + }, "PublicDomainNames": { "items": { "$ref": "#/definitions/AWS::Lightsail::Container.PublicDomainName" @@ -131374,6 +131509,18 @@ }, "type": "object" }, + "AWS::Lightsail::Container.EcrImagePullerRole": { + "additionalProperties": false, + "properties": { + "IsActive": { + "type": "boolean" + }, + "PrincipalArn": { + "type": "string" + } + }, + "type": "object" + }, "AWS::Lightsail::Container.EnvironmentVariable": { "additionalProperties": false, "properties": { @@ -131442,6 +131589,15 @@ }, "type": "object" }, + "AWS::Lightsail::Container.PrivateRegistryAccess": { + "additionalProperties": false, + "properties": { + "EcrImagePullerRole": { + "$ref": "#/definitions/AWS::Lightsail::Container.EcrImagePullerRole" + } + }, + "type": "object" + }, "AWS::Lightsail::Container.PublicDomainName": { "additionalProperties": false, "properties": { @@ -136844,6 +137000,12 @@ "markdownDescription": "The regular expression ( *regex* ) that defines the text pattern to match. The expression can contain 1-512 characters.", "title": "Regex", "type": "string" + }, + "Tags": { + "items": { + "$ref": "#/definitions/Tag" + }, + "type": "array" } }, "required": [ @@ -256147,6 +256309,9 @@ { "$ref": "#/definitions/AWS::Connect::SecurityKey" }, + { + "$ref": "#/definitions/AWS::Connect::SecurityProfile" + }, { "$ref": "#/definitions/AWS::Connect::TaskTemplate" }, diff --git a/schema_source/cloudformation.schema.json b/schema_source/cloudformation.schema.json index 76ae70091..d85fcfe90 100644 --- a/schema_source/cloudformation.schema.json +++ b/schema_source/cloudformation.schema.json @@ -46315,6 +46315,102 @@ ], "type": "object" }, + "AWS::Connect::SecurityProfile": { + "additionalProperties": false, + "properties": { + "Condition": { + "type": "string" + }, + "DeletionPolicy": { + "enum": [ + "Delete", + "Retain", + "Snapshot" + ], + "type": "string" + }, + "DependsOn": { + "anyOf": [ + { + "pattern": "^[a-zA-Z0-9]+$", + "type": "string" + }, + { + "items": { + "pattern": "^[a-zA-Z0-9]+$", + "type": "string" + }, + "type": "array" + } + ] + }, + "Metadata": { + "type": "object" + }, + "Properties": { + "additionalProperties": false, + "properties": { + "AllowedAccessControlTags": { + "items": { + "$ref": "#/definitions/Tag" + }, + "type": "array" + }, + "Description": { + "type": "string" + }, + "InstanceArn": { + "type": "string" + }, + "Permissions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "SecurityProfileName": { + "type": "string" + }, + "TagRestrictedResources": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Tags": { + "items": { + "$ref": "#/definitions/Tag" + }, + "type": "array" + } + }, + "required": [ + "InstanceArn", + "SecurityProfileName" + ], + "type": "object" + }, + "Type": { + "enum": [ + "AWS::Connect::SecurityProfile" + ], + "type": "string" + }, + "UpdateReplacePolicy": { + "enum": [ + "Delete", + "Retain", + "Snapshot" + ], + "type": "string" + } + }, + "required": [ + "Type", + "Properties" + ], + "type": "object" + }, "AWS::Connect::TaskTemplate": { "additionalProperties": false, "properties": { @@ -66123,6 +66219,9 @@ "title": "DestinationIpv6CidrBlock", "type": "string" }, + "DestinationPrefixListId": { + "type": "string" + }, "EgressOnlyInternetGatewayId": { "markdownDescription": "[IPv6 traffic only] The ID of an egress-only internet gateway.", "title": "EgressOnlyInternetGatewayId", @@ -74960,6 +75059,9 @@ "title": "ProvisionedThroughputInMibps", "type": "number" }, + "ReplicationConfiguration": { + "$ref": "#/definitions/AWS::EFS::FileSystem.ReplicationConfiguration" + }, "ThroughputMode": { "markdownDescription": "Specifies the throughput mode for the file system. The mode can be `bursting` , `provisioned` , or `elastic` . If you set `ThroughputMode` to `provisioned` , you must also set a value for `ProvisionedThroughputInMibps` . After you create the file system, you can decrease your file system's throughput in Provisioned Throughput mode or change between the throughput modes, with certain time restrictions. For more information, see [Specifying throughput with provisioned mode](https://docs.aws.amazon.com/efs/latest/ug/performance.html#provisioned-throughput) in the *Amazon EFS User Guide* .\n\nDefault is `elastic` .", "title": "ThroughputMode", @@ -75038,6 +75140,36 @@ }, "type": "object" }, + "AWS::EFS::FileSystem.ReplicationConfiguration": { + "additionalProperties": false, + "properties": { + "Destinations": { + "items": { + "$ref": "#/definitions/AWS::EFS::FileSystem.ReplicationDestination" + }, + "type": "array" + } + }, + "type": "object" + }, + "AWS::EFS::FileSystem.ReplicationDestination": { + "additionalProperties": false, + "properties": { + "AvailabilityZoneName": { + "type": "string" + }, + "FileSystemId": { + "type": "string" + }, + "KmsKeyId": { + "type": "string" + }, + "Region": { + "type": "string" + } + }, + "type": "object" + }, "AWS::EFS::MountTarget": { "additionalProperties": false, "properties": { @@ -131211,6 +131343,9 @@ "title": "Power", "type": "string" }, + "PrivateRegistryAccess": { + "$ref": "#/definitions/AWS::Lightsail::Container.PrivateRegistryAccess" + }, "PublicDomainNames": { "items": { "$ref": "#/definitions/AWS::Lightsail::Container.PublicDomainName" @@ -131325,6 +131460,18 @@ }, "type": "object" }, + "AWS::Lightsail::Container.EcrImagePullerRole": { + "additionalProperties": false, + "properties": { + "IsActive": { + "type": "boolean" + }, + "PrincipalArn": { + "type": "string" + } + }, + "type": "object" + }, "AWS::Lightsail::Container.EnvironmentVariable": { "additionalProperties": false, "properties": { @@ -131393,6 +131540,15 @@ }, "type": "object" }, + "AWS::Lightsail::Container.PrivateRegistryAccess": { + "additionalProperties": false, + "properties": { + "EcrImagePullerRole": { + "$ref": "#/definitions/AWS::Lightsail::Container.EcrImagePullerRole" + } + }, + "type": "object" + }, "AWS::Lightsail::Container.PublicDomainName": { "additionalProperties": false, "properties": { @@ -136795,6 +136951,12 @@ "markdownDescription": "The regular expression ( *regex* ) that defines the text pattern to match. The expression can contain 1-512 characters.", "title": "Regex", "type": "string" + }, + "Tags": { + "items": { + "$ref": "#/definitions/Tag" + }, + "type": "array" } }, "required": [ @@ -248680,6 +248842,9 @@ { "$ref": "#/definitions/AWS::Connect::SecurityKey" }, + { + "$ref": "#/definitions/AWS::Connect::SecurityProfile" + }, { "$ref": "#/definitions/AWS::Connect::TaskTemplate" }, From f4648d038b40c146047327ce92464eedcc2936af Mon Sep 17 00:00:00 2001 From: GZ Date: Tue, 26 Sep 2023 12:39:55 -0700 Subject: [PATCH 2/6] fix: Catch network interface deletion failure (#3353) --- integration/conftest.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/integration/conftest.py b/integration/conftest.py index 2912f5b35..cdf42763a 100644 --- a/integration/conftest.py +++ b/integration/conftest.py @@ -75,7 +75,10 @@ def _delete_unused_network_interface_by_subnet(ec2_client, subnet_id): network_interface_ids += [ni["NetworkInterfaceId"] for ni in page["NetworkInterfaces"]] for ni_id in network_interface_ids: - ec2_client.delete_network_interface(NetworkInterfaceId=ni_id) + try: + ec2_client.delete_network_interface(NetworkInterfaceId=ni_id) + except ClientError as e: + LOG.error("Unable to delete network interface %s", ni_id, exc_info=e) time.sleep(0.5) LOG.info("Deleted %s unused network interfaces under subnet %s", len(network_interface_ids), subnet_id) From ecffa7cd713954a8de04665ce0ce3dec5ee861cc Mon Sep 17 00:00:00 2001 From: GZ Date: Thu, 28 Sep 2023 13:18:08 -0700 Subject: [PATCH 3/6] fix: Support creating a FIFO queue if using FIFO SNS event (#3357) --- samtranslator/model/eventsources/push.py | 39 ++++- samtranslator/model/sam_resources.py | 5 +- samtranslator/model/sqs.py | 8 +- .../eventsources/test_sns_event_source.py | 14 +- .../input/function_with_fifo_topic_event.yaml | 36 +++++ .../function_with_fifo_topic_event.json | 142 ++++++++++++++++++ .../function_with_fifo_topic_event.json | 142 ++++++++++++++++++ .../function_with_fifo_topic_event.json | 142 ++++++++++++++++++ 8 files changed, 516 insertions(+), 12 deletions(-) create mode 100644 tests/translator/input/function_with_fifo_topic_event.yaml create mode 100644 tests/translator/output/aws-cn/function_with_fifo_topic_event.json create mode 100644 tests/translator/output/aws-us-gov/function_with_fifo_topic_event.json create mode 100644 tests/translator/output/function_with_fifo_topic_event.json diff --git a/samtranslator/model/eventsources/push.py b/samtranslator/model/eventsources/push.py index 0cea74e13..a296edbc6 100644 --- a/samtranslator/model/eventsources/push.py +++ b/samtranslator/model/eventsources/push.py @@ -12,7 +12,15 @@ from samtranslator.model.eventsources import FUNCTION_EVETSOURCE_METRIC_PREFIX from samtranslator.model.eventsources.pull import SQS from samtranslator.model.exceptions import InvalidDocumentException, InvalidEventException, InvalidResourceException -from samtranslator.model.intrinsics import fnGetAtt, fnSub, is_intrinsic, make_conditional, make_shorthand, ref +from samtranslator.model.intrinsics import ( + fnGetAtt, + fnSub, + get_logical_id_from_intrinsic, + is_intrinsic, + make_conditional, + make_shorthand, + ref, +) from samtranslator.model.iot import IotTopicRule from samtranslator.model.lambda_ import LambdaPermission from samtranslator.model.s3 import S3Bucket @@ -517,6 +525,8 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] if not function: raise TypeError("Missing required keyword argument: function") + intrinsics_resolver: IntrinsicsResolver = kwargs["intrinsics_resolver"] + # SNS -> Lambda if not self.SqsSubscription: subscription = self._inject_subscription( @@ -534,7 +544,11 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] # SNS -> SQS(Create New) -> Lambda if isinstance(self.SqsSubscription, bool): resources = [] # type: ignore[var-annotated] - queue = self._inject_sqs_queue(function) # type: ignore[no-untyped-call] + + fifo_topic = self._check_fifo_topic( + get_logical_id_from_intrinsic(self.Topic), kwargs.get("original_template"), intrinsics_resolver + ) + queue = self._inject_sqs_queue(function, fifo_topic) # type: ignore[no-untyped-call] queue_arn = queue.get_runtime_attr("arn") queue_url = queue.get_runtime_attr("queue_url") @@ -591,6 +605,19 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] resources.append(subscription) return resources + def _check_fifo_topic( + self, + topic_id: Optional[str], + template: Optional[Dict[str, Any]], + intrinsics_resolver: IntrinsicsResolver, + ) -> bool: + if not topic_id or not template: + return False + + resources = template.get("Resources", {}) + properties = resources.get(topic_id, {}).get("Properties", {}) + return intrinsics_resolver.resolve_parameter_refs(properties.get("FifoTopic", False)) # type: ignore[no-any-return] + def _inject_subscription( # noqa: PLR0913 self, protocol: str, @@ -621,8 +648,12 @@ def _inject_subscription( # noqa: PLR0913 return subscription - def _inject_sqs_queue(self, function): # type: ignore[no-untyped-def] - return SQSQueue(self.logical_id + "Queue", attributes=function.get_passthrough_resource_attributes()) + def _inject_sqs_queue(self, function, fifo_topic=False): # type: ignore[no-untyped-def] + queue = SQSQueue(self.logical_id + "Queue", attributes=function.get_passthrough_resource_attributes()) + + if fifo_topic: + queue.FifoQueue = fifo_topic + return queue def _inject_sqs_event_source_mapping(self, function, role, queue_arn, batch_size=None, enabled=None): # type: ignore[no-untyped-def] event_source = SQS( diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index 86f297ebd..68d9a9e4d 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -351,6 +351,7 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] # noqa: P kwargs["event_resources"], intrinsics_resolver, lambda_alias=lambda_alias, + original_template=kwargs.get("original_template"), ) except InvalidEventException as e: raise InvalidResourceException(self.logical_id, e.message) from e @@ -775,13 +776,14 @@ def order_events(event: Tuple[str, Any]) -> Any: return logical_id return event_dict.get("Properties", {}).get("Path", logical_id) - def _generate_event_resources( + def _generate_event_resources( # noqa: PLR0913 self, lambda_function: LambdaFunction, execution_role: Optional[IAMRole], event_resources: Any, intrinsics_resolver: IntrinsicsResolver, lambda_alias: Optional[LambdaAlias] = None, + original_template: Optional[Dict[str, Any]] = None, ) -> List[Any]: """Generates and returns the resources associated with this function's events. @@ -811,6 +813,7 @@ def _generate_event_resources( "function": lambda_alias or lambda_function, "role": execution_role, "intrinsics_resolver": intrinsics_resolver, + "original_template": original_template, } for name, resource in event_resources[logical_id].items(): diff --git a/samtranslator/model/sqs.py b/samtranslator/model/sqs.py index 8e2002b64..d829b4362 100644 --- a/samtranslator/model/sqs.py +++ b/samtranslator/model/sqs.py @@ -2,16 +2,22 @@ from samtranslator.model import GeneratedProperty, PropertyType, Resource from samtranslator.model.intrinsics import fnGetAtt, ref +from samtranslator.model.types import PassThrough class SQSQueue(Resource): resource_type = "AWS::SQS::Queue" - property_types: Dict[str, PropertyType] = {"Tags": GeneratedProperty()} + property_types: Dict[str, PropertyType] = { + "FifoQueue": GeneratedProperty(), + "Tags": GeneratedProperty(), + } runtime_attrs = { "queue_url": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn"), } + FifoQueue: PassThrough + class SQSQueuePolicy(Resource): resource_type = "AWS::SQS::QueuePolicy" diff --git a/tests/model/eventsources/test_sns_event_source.py b/tests/model/eventsources/test_sns_event_source.py index b2f17660b..71dfa4805 100644 --- a/tests/model/eventsources/test_sns_event_source.py +++ b/tests/model/eventsources/test_sns_event_source.py @@ -18,8 +18,10 @@ def setUp(self): self.function.get_passthrough_resource_attributes = Mock() self.function.get_passthrough_resource_attributes.return_value = {} + self.kwargs = {"function": self.function, "intrinsics_resolver": Mock()} + def test_to_cloudformation_returns_permission_and_subscription_resources(self): - resources = self.sns_event_source.to_cloudformation(function=self.function) + resources = self.sns_event_source.to_cloudformation(**self.kwargs) self.assertEqual(len(resources), 2) self.assertEqual(resources[0].resource_type, "AWS::Lambda::Permission") self.assertEqual(resources[1].resource_type, "AWS::SNS::Subscription") @@ -37,7 +39,7 @@ def test_to_cloudformation_passes_the_region(self): region = "us-west-2" self.sns_event_source.Region = region - resources = self.sns_event_source.to_cloudformation(function=self.function) + resources = self.sns_event_source.to_cloudformation(**self.kwargs) self.assertEqual(len(resources), 2) self.assertEqual(resources[1].resource_type, "AWS::SNS::Subscription") subscription = resources[1] @@ -51,7 +53,7 @@ def test_to_cloudformation_passes_the_filter_policy(self): } self.sns_event_source.FilterPolicy = filterPolicy - resources = self.sns_event_source.to_cloudformation(function=self.function) + resources = self.sns_event_source.to_cloudformation(**self.kwargs) self.assertEqual(len(resources), 2) self.assertEqual(resources[1].resource_type, "AWS::SNS::Subscription") subscription = resources[1] @@ -61,7 +63,7 @@ def test_to_cloudformation_passes_the_filter_policy_scope(self): filterPolicyScope = "MessageAttributes" self.sns_event_source.FilterPolicyScope = filterPolicyScope - resources = self.sns_event_source.to_cloudformation(function=self.function) + resources = self.sns_event_source.to_cloudformation(**self.kwargs) self.assertEqual(len(resources), 2) self.assertEqual(resources[1].resource_type, "AWS::SNS::Subscription") subscription = resources[1] @@ -71,7 +73,7 @@ def test_to_cloudformation_passes_the_redrive_policy(self): redrive_policy = {"deadLetterTargetArn": "arn:aws:sqs:us-east-2:123456789012:MyDeadLetterQueue"} self.sns_event_source.RedrivePolicy = redrive_policy - resources = self.sns_event_source.to_cloudformation(function=self.function) + resources = self.sns_event_source.to_cloudformation(**self.kwargs) self.assertEqual(len(resources), 2) self.assertEqual(resources[1].resource_type, "AWS::SNS::Subscription") subscription = resources[1] @@ -89,7 +91,7 @@ def test_to_cloudformation_when_sqs_subscription_disable(self): sqsSubscription = False self.sns_event_source.SqsSubscription = sqsSubscription - resources = self.sns_event_source.to_cloudformation(function=self.function) + resources = self.sns_event_source.to_cloudformation(**self.kwargs) self.assertEqual(len(resources), 2) self.assertEqual(resources[0].resource_type, "AWS::Lambda::Permission") self.assertEqual(resources[1].resource_type, "AWS::SNS::Subscription") diff --git a/tests/translator/input/function_with_fifo_topic_event.yaml b/tests/translator/input/function_with_fifo_topic_event.yaml new file mode 100644 index 000000000..ded1cdbc1 --- /dev/null +++ b/tests/translator/input/function_with_fifo_topic_event.yaml @@ -0,0 +1,36 @@ +Transform: AWS::Serverless-2016-10-31 +Description: SNS Fifo +Globals: + Function: + Timeout: 3 + +Resources: + MyFifoTopic: + Type: AWS::SNS::Topic + Properties: + ContentBasedDeduplication: true + FifoTopic: true + TopicName: myFifoTopic.fifo + + HelloWorldFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = async (event, context, callback) => { + return { + statusCode: 200, + body: 'Success' + } + } + Handler: index.handler + Runtime: nodejs16.x + Events: + FifoTrigger: + Type: SNS + Properties: + SqsSubscription: true + Topic: !Ref MyFifoTopic + Metadata: + DockerTag: nodejs12.x-v1 + DockerContext: ./hello-world + Dockerfile: Dockerfile diff --git a/tests/translator/output/aws-cn/function_with_fifo_topic_event.json b/tests/translator/output/aws-cn/function_with_fifo_topic_event.json new file mode 100644 index 000000000..c6a4d0881 --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_fifo_topic_event.json @@ -0,0 +1,142 @@ +{ + "Description": "SNS Fifo", + "Resources": { + "HelloWorldFunction": { + "Metadata": { + "DockerContext": "./hello-world", + "DockerTag": "nodejs12.x-v1", + "Dockerfile": "Dockerfile" + }, + "Properties": { + "Code": { + "ZipFile": "exports.handler = async (event, context, callback) => {\n return {\n statusCode: 200,\n body: 'Success'\n }\n}\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "HelloWorldFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs16.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "Timeout": 3 + }, + "Type": "AWS::Lambda::Function" + }, + "HelloWorldFunctionFifoTrigger": { + "Properties": { + "Endpoint": { + "Fn::GetAtt": [ + "HelloWorldFunctionFifoTriggerQueue", + "Arn" + ] + }, + "Protocol": "sqs", + "TopicArn": { + "Ref": "MyFifoTopic" + } + }, + "Type": "AWS::SNS::Subscription" + }, + "HelloWorldFunctionFifoTriggerEventSourceMapping": { + "Properties": { + "BatchSize": 10, + "Enabled": true, + "EventSourceArn": { + "Fn::GetAtt": [ + "HelloWorldFunctionFifoTriggerQueue", + "Arn" + ] + }, + "FunctionName": { + "Ref": "HelloWorldFunction" + } + }, + "Type": "AWS::Lambda::EventSourceMapping" + }, + "HelloWorldFunctionFifoTriggerQueue": { + "Properties": { + "FifoQueue": true + }, + "Type": "AWS::SQS::Queue" + }, + "HelloWorldFunctionFifoTriggerQueuePolicy": { + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sqs:SendMessage", + "Condition": { + "ArnEquals": { + "aws:SourceArn": { + "Ref": "MyFifoTopic" + } + } + }, + "Effect": "Allow", + "Principal": "*", + "Resource": { + "Fn::GetAtt": [ + "HelloWorldFunctionFifoTriggerQueue", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Queues": [ + { + "Ref": "HelloWorldFunctionFifoTriggerQueue" + } + ] + }, + "Type": "AWS::SQS::QueuePolicy" + }, + "HelloWorldFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "MyFifoTopic": { + "Properties": { + "ContentBasedDeduplication": true, + "FifoTopic": true, + "TopicName": "myFifoTopic.fifo" + }, + "Type": "AWS::SNS::Topic" + } + } +} diff --git a/tests/translator/output/aws-us-gov/function_with_fifo_topic_event.json b/tests/translator/output/aws-us-gov/function_with_fifo_topic_event.json new file mode 100644 index 000000000..c8fc24958 --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_fifo_topic_event.json @@ -0,0 +1,142 @@ +{ + "Description": "SNS Fifo", + "Resources": { + "HelloWorldFunction": { + "Metadata": { + "DockerContext": "./hello-world", + "DockerTag": "nodejs12.x-v1", + "Dockerfile": "Dockerfile" + }, + "Properties": { + "Code": { + "ZipFile": "exports.handler = async (event, context, callback) => {\n return {\n statusCode: 200,\n body: 'Success'\n }\n}\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "HelloWorldFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs16.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "Timeout": 3 + }, + "Type": "AWS::Lambda::Function" + }, + "HelloWorldFunctionFifoTrigger": { + "Properties": { + "Endpoint": { + "Fn::GetAtt": [ + "HelloWorldFunctionFifoTriggerQueue", + "Arn" + ] + }, + "Protocol": "sqs", + "TopicArn": { + "Ref": "MyFifoTopic" + } + }, + "Type": "AWS::SNS::Subscription" + }, + "HelloWorldFunctionFifoTriggerEventSourceMapping": { + "Properties": { + "BatchSize": 10, + "Enabled": true, + "EventSourceArn": { + "Fn::GetAtt": [ + "HelloWorldFunctionFifoTriggerQueue", + "Arn" + ] + }, + "FunctionName": { + "Ref": "HelloWorldFunction" + } + }, + "Type": "AWS::Lambda::EventSourceMapping" + }, + "HelloWorldFunctionFifoTriggerQueue": { + "Properties": { + "FifoQueue": true + }, + "Type": "AWS::SQS::Queue" + }, + "HelloWorldFunctionFifoTriggerQueuePolicy": { + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sqs:SendMessage", + "Condition": { + "ArnEquals": { + "aws:SourceArn": { + "Ref": "MyFifoTopic" + } + } + }, + "Effect": "Allow", + "Principal": "*", + "Resource": { + "Fn::GetAtt": [ + "HelloWorldFunctionFifoTriggerQueue", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Queues": [ + { + "Ref": "HelloWorldFunctionFifoTriggerQueue" + } + ] + }, + "Type": "AWS::SQS::QueuePolicy" + }, + "HelloWorldFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "MyFifoTopic": { + "Properties": { + "ContentBasedDeduplication": true, + "FifoTopic": true, + "TopicName": "myFifoTopic.fifo" + }, + "Type": "AWS::SNS::Topic" + } + } +} diff --git a/tests/translator/output/function_with_fifo_topic_event.json b/tests/translator/output/function_with_fifo_topic_event.json new file mode 100644 index 000000000..29fc72cf3 --- /dev/null +++ b/tests/translator/output/function_with_fifo_topic_event.json @@ -0,0 +1,142 @@ +{ + "Description": "SNS Fifo", + "Resources": { + "HelloWorldFunction": { + "Metadata": { + "DockerContext": "./hello-world", + "DockerTag": "nodejs12.x-v1", + "Dockerfile": "Dockerfile" + }, + "Properties": { + "Code": { + "ZipFile": "exports.handler = async (event, context, callback) => {\n return {\n statusCode: 200,\n body: 'Success'\n }\n}\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "HelloWorldFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs16.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ], + "Timeout": 3 + }, + "Type": "AWS::Lambda::Function" + }, + "HelloWorldFunctionFifoTrigger": { + "Properties": { + "Endpoint": { + "Fn::GetAtt": [ + "HelloWorldFunctionFifoTriggerQueue", + "Arn" + ] + }, + "Protocol": "sqs", + "TopicArn": { + "Ref": "MyFifoTopic" + } + }, + "Type": "AWS::SNS::Subscription" + }, + "HelloWorldFunctionFifoTriggerEventSourceMapping": { + "Properties": { + "BatchSize": 10, + "Enabled": true, + "EventSourceArn": { + "Fn::GetAtt": [ + "HelloWorldFunctionFifoTriggerQueue", + "Arn" + ] + }, + "FunctionName": { + "Ref": "HelloWorldFunction" + } + }, + "Type": "AWS::Lambda::EventSourceMapping" + }, + "HelloWorldFunctionFifoTriggerQueue": { + "Properties": { + "FifoQueue": true + }, + "Type": "AWS::SQS::Queue" + }, + "HelloWorldFunctionFifoTriggerQueuePolicy": { + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sqs:SendMessage", + "Condition": { + "ArnEquals": { + "aws:SourceArn": { + "Ref": "MyFifoTopic" + } + } + }, + "Effect": "Allow", + "Principal": "*", + "Resource": { + "Fn::GetAtt": [ + "HelloWorldFunctionFifoTriggerQueue", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Queues": [ + { + "Ref": "HelloWorldFunctionFifoTriggerQueue" + } + ] + }, + "Type": "AWS::SQS::QueuePolicy" + }, + "HelloWorldFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "MyFifoTopic": { + "Properties": { + "ContentBasedDeduplication": true, + "FifoTopic": true, + "TopicName": "myFifoTopic.fifo" + }, + "Type": "AWS::SNS::Topic" + } + } +} From 9c59fc769da648351f098af21cd17d3664d02675 Mon Sep 17 00:00:00 2001 From: GZ Date: Tue, 3 Oct 2023 13:49:04 -0700 Subject: [PATCH 4/6] fix: Give a more appropriate warning with Availability Dip (#3362) --- .../plugins/application/serverless_app_plugin.py | 9 +++++++++ .../input/error_sar_with_dynamic_reference.yaml | 7 +++++++ .../output/error_sar_with_dynamic_reference.json | 14 ++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 tests/translator/input/error_sar_with_dynamic_reference.yaml create mode 100644 tests/translator/output/error_sar_with_dynamic_reference.json diff --git a/samtranslator/plugins/application/serverless_app_plugin.py b/samtranslator/plugins/application/serverless_app_plugin.py index c8759d998..02d70d9f7 100644 --- a/samtranslator/plugins/application/serverless_app_plugin.py +++ b/samtranslator/plugins/application/serverless_app_plugin.py @@ -1,6 +1,7 @@ import copy import json import logging +import re from time import sleep from typing import Any, Callable, Dict, List, Optional, Tuple @@ -150,6 +151,14 @@ def on_before_transform_template(self, template_dict): # type: ignore[no-untype raise InvalidResourceException( logical_id, "Serverless Application Repository is not available in this region." ) + # SSM Pattern found here https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html + ssm_pattern = r"{{resolve:ssm:[a-zA-Z0-9_.\-/]+(:\d+)?}}" + if re.search(ssm_pattern, app_id): + raise InvalidResourceException( + logical_id, + "Serverless Application Repostiory does not support dynamic reference in 'ApplicationId' property.", + ) + self._make_service_call_with_retry(service_call, app_id, semver, key, logical_id) # type: ignore[no-untyped-call] except InvalidResourceException as e: # Catch all InvalidResourceExceptions, raise those in the before_resource_transform target. diff --git a/tests/translator/input/error_sar_with_dynamic_reference.yaml b/tests/translator/input/error_sar_with_dynamic_reference.yaml new file mode 100644 index 000000000..efefd3cca --- /dev/null +++ b/tests/translator/input/error_sar_with_dynamic_reference.yaml @@ -0,0 +1,7 @@ +Resources: + CLOUDDELIVERY: + Type: AWS::Serverless::Application + Properties: + Location: + ApplicationId: '{{resolve:ssm:/elw/test/sar-app}}' + SemanticVersion: 5.2.17 diff --git a/tests/translator/output/error_sar_with_dynamic_reference.json b/tests/translator/output/error_sar_with_dynamic_reference.json new file mode 100644 index 000000000..5d35d5703 --- /dev/null +++ b/tests/translator/output/error_sar_with_dynamic_reference.json @@ -0,0 +1,14 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [CLOUDDELIVERY] is invalid. ", + "Serverless Application Repostiory does not support dynamic reference in 'ApplicationId' property." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [CLOUDDELIVERY] is invalid. Serverless Application Repostiory does not support dynamic reference in 'ApplicationId' property.", + "errors": [ + { + "errorMessage": "Resource with id [CLOUDDELIVERY] is invalid. Serverless Application Repostiory does not support dynamic reference in 'ApplicationId' property." + } + ] +} From cf8418baca89b0b261c203120d50591f886dc2a2 Mon Sep 17 00:00:00 2001 From: sidhujus <105385029+sidhujus@users.noreply.github.com> Date: Thu, 5 Oct 2023 09:19:18 -0700 Subject: [PATCH 5/6] feat: allow user to provide role for schedule (#3363) --- .../aws_serverless_statemachine.py | 1 + samtranslator/model/stepfunctions/events.py | 67 ++++++--- samtranslator/schema/schema.json | 3 + schema_source/sam.schema.json | 3 + .../stepfunctions/test_schedule_event.py | 7 + .../state_machine_with_schedule_role.yaml | 21 +++ .../state_machine_with_schedule_role.json | 129 ++++++++++++++++++ .../state_machine_with_schedule_role.json | 129 ++++++++++++++++++ .../state_machine_with_schedule_role.json | 129 ++++++++++++++++++ 9 files changed, 473 insertions(+), 16 deletions(-) create mode 100644 tests/translator/input/state_machine_with_schedule_role.yaml create mode 100644 tests/translator/output/aws-cn/state_machine_with_schedule_role.json create mode 100644 tests/translator/output/aws-us-gov/state_machine_with_schedule_role.json create mode 100644 tests/translator/output/state_machine_with_schedule_role.json diff --git a/samtranslator/internal/schema_source/aws_serverless_statemachine.py b/samtranslator/internal/schema_source/aws_serverless_statemachine.py index 2d286243c..041392b93 100644 --- a/samtranslator/internal/schema_source/aws_serverless_statemachine.py +++ b/samtranslator/internal/schema_source/aws_serverless_statemachine.py @@ -49,6 +49,7 @@ class ScheduleEventProperties(BaseModel): Schedule: Optional[PassThroughProp] = scheduleeventproperties("Schedule") State: Optional[PassThroughProp] = scheduleeventproperties("State") Target: Optional[ScheduleTarget] = scheduleeventproperties("Target") + RoleArn: Optional[PassThroughProp] # TODO: add doc class ScheduleEvent(BaseModel): diff --git a/samtranslator/model/stepfunctions/events.py b/samtranslator/model/stepfunctions/events.py index b8a248d3d..d2f8500b4 100644 --- a/samtranslator/model/stepfunctions/events.py +++ b/samtranslator/model/stepfunctions/events.py @@ -1,6 +1,6 @@ import json from abc import ABCMeta -from typing import Any, Dict, Optional, cast +from typing import Any, Dict, List, Optional, Union, cast from samtranslator.metrics.method_decorator import cw_timer from samtranslator.model import Property, PropertyType, Resource, ResourceMacro @@ -10,6 +10,7 @@ from samtranslator.model.exceptions import InvalidEventException from samtranslator.model.iam import IAMRole, IAMRolePolicies from samtranslator.model.intrinsics import fnSub +from samtranslator.model.stepfunctions.resources import StepFunctionsStateMachine from samtranslator.model.types import IS_BOOL, IS_DICT, IS_STR, PassThrough from samtranslator.swagger.swagger import SwaggerEditor from samtranslator.translator import logical_id_generator @@ -50,7 +51,13 @@ def _generate_logical_id(self, prefix, suffix, resource_type): # type: ignore[n generator = logical_id_generator.LogicalIdGenerator(prefix + resource_type, suffix) return generator.gen() - def _construct_role(self, resource, permissions_boundary=None, prefix=None, suffix=""): # type: ignore[no-untyped-def] + def _construct_role( + self, + resource: StepFunctionsStateMachine, + permissions_boundary: Optional[str], + prefix: Optional[str], + suffix: str = "", + ) -> IAMRole: """Constructs the IAM Role resource allowing the event service to invoke the StartExecution API of the state machine resource it is associated with. @@ -93,6 +100,7 @@ class Schedule(EventSource): "DeadLetterConfig": PropertyType(False, IS_DICT), "RetryPolicy": PropertyType(False, IS_DICT), "Target": Property(False, IS_DICT), + "RoleArn": Property(False, IS_STR), } Schedule: PassThrough @@ -104,6 +112,7 @@ class Schedule(EventSource): DeadLetterConfig: Optional[Dict[str, Any]] RetryPolicy: Optional[PassThrough] Target: Optional[PassThrough] + RoleArn: Optional[PassThrough] @cw_timer(prefix=SFN_EVETSOURCE_METRIC_PREFIX) def to_cloudformation(self, resource, **kwargs): # type: ignore[no-untyped-def] @@ -113,7 +122,7 @@ def to_cloudformation(self, resource, **kwargs): # type: ignore[no-untyped-def] :returns: a list of vanilla CloudFormation Resources, to which this Schedule event expands :rtype: list """ - resources = [] + resources: List[Any] = [] permissions_boundary = kwargs.get("permissions_boundary") @@ -135,8 +144,12 @@ 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: Union[IAMRole, str, Dict[str, Any]] + if self.RoleArn is None: + role = self._construct_role(resource, permissions_boundary, prefix=None) + resources.append(role) + else: + role = self.RoleArn source_arn = events_rule.get_runtime_attr("arn") dlq_queue_arn = None @@ -146,26 +159,44 @@ 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, dlq_queue_arn)] return resources - def _construct_target(self, resource, role, dead_letter_queue_arn=None): # type: ignore[no-untyped-def] - """Constructs the Target property for the EventBridge Rule. - - :returns: the Target property - :rtype: dict + def _construct_target( + self, + resource: StepFunctionsStateMachine, + role: Union[IAMRole, str, Dict[str, Any]], + dead_letter_queue_arn: Optional[str], + ) -> Dict[str, Any]: + """_summary_ + + Parameters + ---------- + resource + StepFunctionsState machine resource to be generated + role + The role to be used by the Schedule event resource either generated or user provides arn + dead_letter_queue_arn + Dead letter queue associated with the resource + + Returns + ------- + The Target property """ target_id = ( self.Target["Id"] 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"), } + + target["RoleArn"] = role.get_runtime_attr("arn") if isinstance(role, IAMRole) else role + if self.Input is not None: target["Input"] = self.Input @@ -216,7 +247,7 @@ def to_cloudformation(self, resource, **kwargs): # type: ignore[no-untyped-def] :returns: a list of vanilla CloudFormation Resources, to which this CloudWatch Events/EventBridge event expands :rtype: list """ - resources = [] + resources: List[Any] = [] permissions_boundary = kwargs.get("permissions_boundary") @@ -231,7 +262,11 @@ def to_cloudformation(self, resource, **kwargs): # type: ignore[no-untyped-def] resources.append(events_rule) - role = self._construct_role(resource, permissions_boundary) # type: ignore[no-untyped-call] + role = self._construct_role( + resource, + permissions_boundary, + prefix=None, + ) resources.append(role) source_arn = events_rule.get_runtime_attr("arn") @@ -331,7 +366,7 @@ def to_cloudformation(self, resource, **kwargs): # type: ignore[no-untyped-def] :returns: a list of vanilla CloudFormation Resources, to which this Api event expands :rtype: list """ - resources = [] + resources: List[Any] = [] intrinsics_resolver = kwargs.get("intrinsics_resolver") permissions_boundary = kwargs.get("permissions_boundary") @@ -340,7 +375,7 @@ def to_cloudformation(self, resource, **kwargs): # type: ignore[no-untyped-def] # Convert to lower case so that user can specify either GET or get self.Method = self.Method.lower() - role = self._construct_role(resource, permissions_boundary) # type: ignore[no-untyped-call] + role = self._construct_role(resource, permissions_boundary, prefix=None) resources.append(role) explicit_api = kwargs["explicit_api"] diff --git a/samtranslator/schema/schema.json b/samtranslator/schema/schema.json index a62d08e7d..0856c655b 100644 --- a/samtranslator/schema/schema.json +++ b/samtranslator/schema/schema.json @@ -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" }, + "RoleArn": { + "$ref": "#/definitions/PassThroughProp" + }, "Schedule": { "allOf": [ { diff --git a/schema_source/sam.schema.json b/schema_source/sam.schema.json index b87915663..b5e1ccbd6 100644 --- a/schema_source/sam.schema.json +++ b/schema_source/sam.schema.json @@ -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" }, + "RoleArn": { + "$ref": "#/definitions/PassThroughProp" + }, "Schedule": { "allOf": [ { diff --git a/tests/model/stepfunctions/test_schedule_event.py b/tests/model/stepfunctions/test_schedule_event.py index c8db1849e..1f98a8aa7 100644 --- a/tests/model/stepfunctions/test_schedule_event.py +++ b/tests/model/stepfunctions/test_schedule_event.py @@ -153,6 +153,13 @@ 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 = "not a real arn" + self.schedule_event_source.RoleArn = role + resources = self.schedule_event_source.to_cloudformation(resource=self.state_machine) + event_rule = resources[0] + self.assertEqual(event_rule.Targets[0]["RoleArn"], "not a real arn") + @parameterized.expand( [ (True, "Enabled"), diff --git a/tests/translator/input/state_machine_with_schedule_role.yaml b/tests/translator/input/state_machine_with_schedule_role.yaml new file mode 100644 index 000000000..7525f8593 --- /dev/null +++ b/tests/translator/input/state_machine_with_schedule_role.yaml @@ -0,0 +1,21 @@ +Resources: + + MyStateMachine: + Type: AWS::Serverless::StateMachine + + Properties: + DefinitionUri: s3://sam-demo-bucket/my_state_machine.asl.json + Events: + CWSchedule: + Type: Schedule + Properties: + Schedule: rate(1 minute) + Description: test schedule + Enabled: false + RoleArn: arn:0000000000:iam::role/yoyo + CWScheduleCreateRole: + Type: Schedule + Properties: + Schedule: rate(1 minute) + Description: test schedule + Enabled: false diff --git a/tests/translator/output/aws-cn/state_machine_with_schedule_role.json b/tests/translator/output/aws-cn/state_machine_with_schedule_role.json new file mode 100644 index 000000000..463a32738 --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_schedule_role.json @@ -0,0 +1,129 @@ +{ + "Resources": { + "MyStateMachine": { + "Properties": { + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my_state_machine.asl.json" + }, + "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": "arn:0000000000:iam::role/yoyo" + } + ] + }, + "Type": "AWS::Events::Rule" + }, + "MyStateMachineCWScheduleCreateRole": { + "Properties": { + "Description": "test schedule", + "ScheduleExpression": "rate(1 minute)", + "State": "DISABLED", + "Targets": [ + { + "Arn": { + "Ref": "MyStateMachine" + }, + "Id": "MyStateMachineCWScheduleCreateRoleStepFunctionsTarget", + "RoleArn": { + "Fn::GetAtt": [ + "MyStateMachineCWScheduleCreateRoleRole", + "Arn" + ] + } + } + ] + }, + "Type": "AWS::Events::Rule" + }, + "MyStateMachineCWScheduleCreateRoleRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "events.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Effect": "Allow", + "Resource": { + "Ref": "MyStateMachine" + } + } + ] + }, + "PolicyName": "MyStateMachineCWScheduleCreateRoleRoleStartExecutionPolicy" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "MyStateMachineRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [], + "Tags": [ + { + "Key": "stateMachine:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-us-gov/state_machine_with_schedule_role.json b/tests/translator/output/aws-us-gov/state_machine_with_schedule_role.json new file mode 100644 index 000000000..463a32738 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_schedule_role.json @@ -0,0 +1,129 @@ +{ + "Resources": { + "MyStateMachine": { + "Properties": { + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my_state_machine.asl.json" + }, + "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": "arn:0000000000:iam::role/yoyo" + } + ] + }, + "Type": "AWS::Events::Rule" + }, + "MyStateMachineCWScheduleCreateRole": { + "Properties": { + "Description": "test schedule", + "ScheduleExpression": "rate(1 minute)", + "State": "DISABLED", + "Targets": [ + { + "Arn": { + "Ref": "MyStateMachine" + }, + "Id": "MyStateMachineCWScheduleCreateRoleStepFunctionsTarget", + "RoleArn": { + "Fn::GetAtt": [ + "MyStateMachineCWScheduleCreateRoleRole", + "Arn" + ] + } + } + ] + }, + "Type": "AWS::Events::Rule" + }, + "MyStateMachineCWScheduleCreateRoleRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "events.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Effect": "Allow", + "Resource": { + "Ref": "MyStateMachine" + } + } + ] + }, + "PolicyName": "MyStateMachineCWScheduleCreateRoleRoleStartExecutionPolicy" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "MyStateMachineRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [], + "Tags": [ + { + "Key": "stateMachine:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/state_machine_with_schedule_role.json b/tests/translator/output/state_machine_with_schedule_role.json new file mode 100644 index 000000000..463a32738 --- /dev/null +++ b/tests/translator/output/state_machine_with_schedule_role.json @@ -0,0 +1,129 @@ +{ + "Resources": { + "MyStateMachine": { + "Properties": { + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my_state_machine.asl.json" + }, + "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": "arn:0000000000:iam::role/yoyo" + } + ] + }, + "Type": "AWS::Events::Rule" + }, + "MyStateMachineCWScheduleCreateRole": { + "Properties": { + "Description": "test schedule", + "ScheduleExpression": "rate(1 minute)", + "State": "DISABLED", + "Targets": [ + { + "Arn": { + "Ref": "MyStateMachine" + }, + "Id": "MyStateMachineCWScheduleCreateRoleStepFunctionsTarget", + "RoleArn": { + "Fn::GetAtt": [ + "MyStateMachineCWScheduleCreateRoleRole", + "Arn" + ] + } + } + ] + }, + "Type": "AWS::Events::Rule" + }, + "MyStateMachineCWScheduleCreateRoleRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "events.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Effect": "Allow", + "Resource": { + "Ref": "MyStateMachine" + } + } + ] + }, + "PolicyName": "MyStateMachineCWScheduleCreateRoleRoleStartExecutionPolicy" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "MyStateMachineRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [], + "Tags": [ + { + "Key": "stateMachine:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} From 416e76b1b0a631959b643954d4442e78affe63da Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 5 Oct 2023 19:53:52 +0000 Subject: [PATCH 6/6] chore(schema): update (#3367) Co-authored-by: github-actions --- samtranslator/schema/schema.json | 317 +++++++++++++++++++---- schema_source/cloudformation.schema.json | 317 +++++++++++++++++++---- 2 files changed, 534 insertions(+), 100 deletions(-) diff --git a/samtranslator/schema/schema.json b/samtranslator/schema/schema.json index 0856c655b..f4e0c1e5d 100644 --- a/samtranslator/schema/schema.json +++ b/samtranslator/schema/schema.json @@ -10390,6 +10390,9 @@ "AWS::AppFlow::ConnectorProfile.ServiceNowConnectorProfileCredentials": { "additionalProperties": false, "properties": { + "OAuth2Credentials": { + "$ref": "#/definitions/AWS::AppFlow::ConnectorProfile.OAuth2Credentials" + }, "Password": { "markdownDescription": "The password that corresponds to the user name.", "title": "Password", @@ -10401,10 +10404,6 @@ "type": "string" } }, - "required": [ - "Password", - "Username" - ], "type": "object" }, "AWS::AppFlow::ConnectorProfile.ServiceNowConnectorProfileProperties": { @@ -15990,6 +15989,9 @@ "$ref": "#/definitions/AWS::AppRunner::Service.SourceCodeVersion", "markdownDescription": "The version that should be used within the source code repository.", "title": "SourceCodeVersion" + }, + "SourceDirectory": { + "type": "string" } }, "required": [ @@ -41863,7 +41865,13 @@ "additionalProperties": false, "properties": { "ClientMetadata": { + "additionalProperties": true, "markdownDescription": "A map of custom key-value pairs that you can provide as input for the custom workflow that is invoked by the *pre sign-up* trigger.\n\nYou create custom workflows by assigning AWS Lambda functions to user pool triggers. When you create a `UserPoolUser` resource and include the `ClientMetadata` property, Amazon Cognito invokes the function that is assigned to the *pre sign-up* trigger. When Amazon Cognito invokes this function, it passes a JSON payload, which the function receives as input. This payload contains a `clientMetadata` attribute, which provides the data that you assigned to the ClientMetadata property. In your function code in AWS Lambda , you can process the `clientMetadata` value to enhance your workflow for your specific needs.\n\nFor more information, see [Customizing User Pool Workflows with Lambda Triggers](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html) in the *Amazon Cognito Developer Guide* .\n\n> Take the following limitations into consideration when you use the ClientMetadata parameter:\n> \n> - Amazon Cognito does not store the ClientMetadata value. This data is available only to AWS Lambda triggers that are assigned to a user pool to support custom workflows. If your user pool configuration does not include triggers, the ClientMetadata parameter serves no purpose.\n> - Amazon Cognito does not validate the ClientMetadata value.\n> - Amazon Cognito does not encrypt the the ClientMetadata value, so don't use it to provide sensitive information.", + "patternProperties": { + "^[a-zA-Z0-9]+$": { + "type": "string" + } + }, "title": "ClientMetadata", "type": "object" }, @@ -60925,16 +60933,6 @@ "Properties": { "additionalProperties": false, "properties": { - "DefaultResourceDiscoveryAssociationId": { - "markdownDescription": "The IPAM's default resource discovery association ID.", - "title": "DefaultResourceDiscoveryAssociationId", - "type": "string" - }, - "DefaultResourceDiscoveryId": { - "markdownDescription": "The IPAM's default resource discovery ID.", - "title": "DefaultResourceDiscoveryId", - "type": "string" - }, "Description": { "markdownDescription": "The description for the IPAM.", "title": "Description", @@ -85235,6 +85233,12 @@ "title": "Sql", "type": "string" }, + "Sqls": { + "items": { + "type": "string" + }, + "type": "array" + }, "StatementName": { "markdownDescription": "The name of the SQL statement. You can name the SQL statement when you create it to identify the query.", "title": "StatementName", @@ -85247,7 +85251,8 @@ } }, "required": [ - "Database" + "Database", + "Sql" ], "type": "object" }, @@ -85355,22 +85360,6 @@ ], "type": "object" }, - "AWS::Events::Rule.Tag": { - "additionalProperties": false, - "properties": { - "Key": { - "markdownDescription": "A string you can use to assign a value. The combination of tag keys and values can help you organize and categorize your resources.", - "title": "Key", - "type": "string" - }, - "Value": { - "markdownDescription": "The value for the specified tag key.", - "title": "Value", - "type": "string" - } - }, - "type": "object" - }, "AWS::Events::Rule.Target": { "additionalProperties": false, "properties": { @@ -100351,6 +100340,79 @@ ], "type": "object" }, + "AWS::HealthImaging::Datastore": { + "additionalProperties": false, + "properties": { + "Condition": { + "type": "string" + }, + "DeletionPolicy": { + "enum": [ + "Delete", + "Retain", + "Snapshot" + ], + "type": "string" + }, + "DependsOn": { + "anyOf": [ + { + "pattern": "^[a-zA-Z0-9]+$", + "type": "string" + }, + { + "items": { + "pattern": "^[a-zA-Z0-9]+$", + "type": "string" + }, + "type": "array" + } + ] + }, + "Metadata": { + "type": "object" + }, + "Properties": { + "additionalProperties": false, + "properties": { + "DatastoreName": { + "type": "string" + }, + "KmsKeyArn": { + "type": "string" + }, + "Tags": { + "additionalProperties": true, + "patternProperties": { + "^[a-zA-Z0-9]+$": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Type": { + "enum": [ + "AWS::HealthImaging::Datastore" + ], + "type": "string" + }, + "UpdateReplacePolicy": { + "enum": [ + "Delete", + "Retain", + "Snapshot" + ], + "type": "string" + } + }, + "required": [ + "Type" + ], + "type": "object" + }, "AWS::HealthLake::FHIRDatastore": { "additionalProperties": false, "properties": { @@ -119012,6 +119074,9 @@ "title": "IndexId", "type": "string" }, + "LanguageCode": { + "type": "string" + }, "Name": { "markdownDescription": "The name of the data source.", "title": "Name", @@ -123587,6 +123652,9 @@ "markdownDescription": "When a Kinesis stream is used as the source for the delivery stream, a [KinesisStreamSourceConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-kinesisstreamsourceconfiguration.html) containing the Kinesis stream ARN and the role ARN for the source stream.", "title": "KinesisStreamSourceConfiguration" }, + "MSKSourceConfiguration": { + "$ref": "#/definitions/AWS::KinesisFirehose::DeliveryStream.MSKSourceConfiguration" + }, "RedshiftDestinationConfiguration": { "$ref": "#/definitions/AWS::KinesisFirehose::DeliveryStream.RedshiftDestinationConfiguration", "markdownDescription": "An Amazon Redshift destination for the delivery stream.\n\nConditional. You must specify only one destination configuration.\n\nIf you change the delivery stream destination from an Amazon Redshift destination to an Amazon ES destination, update requires [some interruptions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-some-interrupt) .", @@ -123829,6 +123897,22 @@ }, "type": "object" }, + "AWS::KinesisFirehose::DeliveryStream.AuthenticationConfiguration": { + "additionalProperties": false, + "properties": { + "Connectivity": { + "type": "string" + }, + "RoleARN": { + "type": "string" + } + }, + "required": [ + "Connectivity", + "RoleARN" + ], + "type": "object" + }, "AWS::KinesisFirehose::DeliveryStream.BufferingHints": { "additionalProperties": false, "properties": { @@ -124357,6 +124441,26 @@ ], "type": "object" }, + "AWS::KinesisFirehose::DeliveryStream.MSKSourceConfiguration": { + "additionalProperties": false, + "properties": { + "AuthenticationConfiguration": { + "$ref": "#/definitions/AWS::KinesisFirehose::DeliveryStream.AuthenticationConfiguration" + }, + "MSKClusterARN": { + "type": "string" + }, + "TopicName": { + "type": "string" + } + }, + "required": [ + "AuthenticationConfiguration", + "MSKClusterARN", + "TopicName" + ], + "type": "object" + }, "AWS::KinesisFirehose::DeliveryStream.OpenXJsonSerDe": { "additionalProperties": false, "properties": { @@ -136256,6 +136360,9 @@ "title": "KafkaVersionsList", "type": "array" }, + "LatestRevision": { + "$ref": "#/definitions/AWS::MSK::Configuration.LatestRevision" + }, "Name": { "markdownDescription": "The name of the configuration. Configuration names are strings that match the regex \"^[0-9A-Za-z][0-9A-Za-z-]{0,}$\".", "title": "Name", @@ -136294,6 +136401,21 @@ ], "type": "object" }, + "AWS::MSK::Configuration.LatestRevision": { + "additionalProperties": false, + "properties": { + "CreationTime": { + "type": "string" + }, + "Description": { + "type": "string" + }, + "Revision": { + "type": "number" + } + }, + "type": "object" + }, "AWS::MSK::ServerlessCluster": { "additionalProperties": false, "properties": { @@ -178894,6 +179016,9 @@ "title": "DateTimeFormat", "type": "string" }, + "InfoIconLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions" + }, "TitleOptions": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.LabelOptions", "markdownDescription": "The options to configure the title visibility, name, and font size.", @@ -179221,6 +179346,9 @@ "AWS::QuickSight::Dashboard.DropDownControlDisplayOptions": { "additionalProperties": false, "properties": { + "InfoIconLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions" + }, "SelectAllOptions": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.ListControlSelectAllOptions", "markdownDescription": "The configuration of the `Select all` options in a dropdown control.", @@ -180043,6 +180171,9 @@ "AWS::QuickSight::Dashboard.FilterScopeConfiguration": { "additionalProperties": false, "properties": { + "AllSheets": { + "type": "object" + }, "SelectedSheets": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.SelectedSheetsFilterScopeConfiguration", "markdownDescription": "The configuration for applying a filter to specific sheets.", @@ -180299,8 +180430,7 @@ } }, "required": [ - "ComputationId", - "Time" + "ComputationId" ], "type": "object" }, @@ -181316,8 +181446,7 @@ } }, "required": [ - "ComputationId", - "Time" + "ComputationId" ], "type": "object" }, @@ -182473,6 +182602,9 @@ "AWS::QuickSight::Dashboard.ListControlDisplayOptions": { "additionalProperties": false, "properties": { + "InfoIconLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions" + }, "SearchOptions": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.ListControlSearchOptions", "markdownDescription": "The configuration of the search options in a list control.", @@ -182616,7 +182748,6 @@ }, "required": [ "ComputationId", - "Time", "Type" ], "type": "object" @@ -182677,10 +182808,7 @@ } }, "required": [ - "ComputationId", - "FromValue", - "TargetValue", - "Time" + "ComputationId" ], "type": "object" }, @@ -183597,8 +183725,7 @@ } }, "required": [ - "ComputationId", - "Time" + "ComputationId" ], "type": "object" }, @@ -183632,8 +183759,7 @@ } }, "required": [ - "ComputationId", - "Time" + "ComputationId" ], "type": "object" }, @@ -184132,6 +184258,9 @@ "title": "ColumnNamesVisibility", "type": "string" }, + "DefaultCellWidth": { + "type": "string" + }, "MetricPlacement": { "markdownDescription": "The metric placement (row, column) options.", "title": "MetricPlacement", @@ -184152,6 +184281,12 @@ "markdownDescription": "The table cell style of the row headers.", "title": "RowHeaderStyle" }, + "RowsLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.PivotTableRowsLabelOptions" + }, + "RowsLayout": { + "type": "string" + }, "SingleMetricVisibility": { "markdownDescription": "The visibility of the single metric options.", "title": "SingleMetricVisibility", @@ -184181,6 +184316,18 @@ }, "type": "object" }, + "AWS::QuickSight::Dashboard.PivotTableRowsLabelOptions": { + "additionalProperties": false, + "properties": { + "CustomLabel": { + "type": "string" + }, + "Visibility": { + "type": "string" + } + }, + "type": "object" + }, "AWS::QuickSight::Dashboard.PivotTableSortBy": { "additionalProperties": false, "properties": { @@ -184778,6 +184925,9 @@ "title": "DateTimeFormat", "type": "string" }, + "InfoIconLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions" + }, "TitleOptions": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.LabelOptions", "markdownDescription": "The options to configure the title visibility, name, and font size.", @@ -184912,6 +185062,9 @@ "markdownDescription": "Determines the widget status.", "title": "Status", "type": "string" + }, + "UsePrimaryBackgroundColor": { + "type": "string" } }, "type": "object" @@ -185494,6 +185647,18 @@ }, "type": "object" }, + "AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions": { + "additionalProperties": false, + "properties": { + "InfoIconText": { + "type": "string" + }, + "Visibility": { + "type": "string" + } + }, + "type": "object" + }, "AWS::QuickSight::Dashboard.SheetControlLayout": { "additionalProperties": false, "properties": { @@ -185731,6 +185896,9 @@ "AWS::QuickSight::Dashboard.SliderControlDisplayOptions": { "additionalProperties": false, "properties": { + "InfoIconLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions" + }, "TitleOptions": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.LabelOptions", "markdownDescription": "The options to configure the title visibility, name, and font size.", @@ -185739,6 +185907,18 @@ }, "type": "object" }, + "AWS::QuickSight::Dashboard.SmallMultiplesAxisProperties": { + "additionalProperties": false, + "properties": { + "Placement": { + "type": "string" + }, + "Scale": { + "type": "string" + } + }, + "type": "object" + }, "AWS::QuickSight::Dashboard.SmallMultiplesOptions": { "additionalProperties": false, "properties": { @@ -185756,6 +185936,12 @@ "$ref": "#/definitions/AWS::QuickSight::Dashboard.PanelConfiguration", "markdownDescription": "Configures the display options for each small multiples panel.", "title": "PanelConfiguration" + }, + "XAxis": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SmallMultiplesAxisProperties" + }, + "YAxis": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SmallMultiplesAxisProperties" } }, "type": "object" @@ -185924,6 +186110,12 @@ "markdownDescription": "The cell styling options for the subtotals of header cells.", "title": "MetricHeaderCellStyle" }, + "StyleTargets": { + "items": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.TableStyleTarget" + }, + "type": "array" + }, "TotalCellStyle": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.TableCellStyle", "markdownDescription": "The cell styling options for the subtotal cells.", @@ -186424,6 +186616,18 @@ }, "type": "object" }, + "AWS::QuickSight::Dashboard.TableStyleTarget": { + "additionalProperties": false, + "properties": { + "CellType": { + "type": "string" + } + }, + "required": [ + "CellType" + ], + "type": "object" + }, "AWS::QuickSight::Dashboard.TableUnaggregatedFieldWells": { "additionalProperties": false, "properties": { @@ -186483,6 +186687,9 @@ "AWS::QuickSight::Dashboard.TextAreaControlDisplayOptions": { "additionalProperties": false, "properties": { + "InfoIconLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions" + }, "PlaceholderOptions": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.TextControlPlaceholderOptions", "markdownDescription": "The configuration of the placeholder options in a text area control.", @@ -186531,6 +186738,9 @@ "AWS::QuickSight::Dashboard.TextFieldControlDisplayOptions": { "additionalProperties": false, "properties": { + "InfoIconLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions" + }, "PlaceholderOptions": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.TextControlPlaceholderOptions", "markdownDescription": "The configuration of the placeholder options in a text field control.", @@ -186866,9 +187076,7 @@ } }, "required": [ - "Category", "ComputationId", - "Time", "Type" ], "type": "object" @@ -186908,7 +187116,6 @@ } }, "required": [ - "Category", "ComputationId", "Type" ], @@ -186934,8 +187141,7 @@ } }, "required": [ - "ComputationId", - "Value" + "ComputationId" ], "type": "object" }, @@ -187182,7 +187388,6 @@ } }, "required": [ - "Category", "ComputationId" ], "type": "object" @@ -219757,7 +219962,13 @@ "type": "string" }, "Tags": { + "additionalProperties": true, "markdownDescription": "Optional metadata that you assign to a resource in the form of an arbitrary set of tags (key-value pairs). Tags enable you to categorize a resource in different ways, such as by purpose, owner, or environment. For example, you might want to tag a Systems Manager parameter to identify the type of resource to which it applies, the environment, or the type of configuration data referenced by the parameter.", + "patternProperties": { + "^[a-zA-Z0-9]+$": { + "type": "string" + } + }, "title": "Tags", "type": "object" }, @@ -227081,6 +227292,9 @@ "title": "SamplePayloadUrl", "type": "string" }, + "SkipModelValidation": { + "type": "string" + }, "SourceAlgorithmSpecification": { "$ref": "#/definitions/AWS::SageMaker::ModelPackage.SourceAlgorithmSpecification", "markdownDescription": "A list of algorithms that were used to create a model package.", @@ -257206,6 +257420,9 @@ { "$ref": "#/definitions/AWS::GuardDuty::ThreatIntelSet" }, + { + "$ref": "#/definitions/AWS::HealthImaging::Datastore" + }, { "$ref": "#/definitions/AWS::HealthLake::FHIRDatastore" }, diff --git a/schema_source/cloudformation.schema.json b/schema_source/cloudformation.schema.json index d85fcfe90..9da4c54f4 100644 --- a/schema_source/cloudformation.schema.json +++ b/schema_source/cloudformation.schema.json @@ -10376,6 +10376,9 @@ "AWS::AppFlow::ConnectorProfile.ServiceNowConnectorProfileCredentials": { "additionalProperties": false, "properties": { + "OAuth2Credentials": { + "$ref": "#/definitions/AWS::AppFlow::ConnectorProfile.OAuth2Credentials" + }, "Password": { "markdownDescription": "The password that corresponds to the user name.", "title": "Password", @@ -10387,10 +10390,6 @@ "type": "string" } }, - "required": [ - "Password", - "Username" - ], "type": "object" }, "AWS::AppFlow::ConnectorProfile.ServiceNowConnectorProfileProperties": { @@ -15976,6 +15975,9 @@ "$ref": "#/definitions/AWS::AppRunner::Service.SourceCodeVersion", "markdownDescription": "The version that should be used within the source code repository.", "title": "SourceCodeVersion" + }, + "SourceDirectory": { + "type": "string" } }, "required": [ @@ -41835,7 +41837,13 @@ "additionalProperties": false, "properties": { "ClientMetadata": { + "additionalProperties": true, "markdownDescription": "A map of custom key-value pairs that you can provide as input for the custom workflow that is invoked by the *pre sign-up* trigger.\n\nYou create custom workflows by assigning AWS Lambda functions to user pool triggers. When you create a `UserPoolUser` resource and include the `ClientMetadata` property, Amazon Cognito invokes the function that is assigned to the *pre sign-up* trigger. When Amazon Cognito invokes this function, it passes a JSON payload, which the function receives as input. This payload contains a `clientMetadata` attribute, which provides the data that you assigned to the ClientMetadata property. In your function code in AWS Lambda , you can process the `clientMetadata` value to enhance your workflow for your specific needs.\n\nFor more information, see [Customizing User Pool Workflows with Lambda Triggers](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html) in the *Amazon Cognito Developer Guide* .\n\n> Take the following limitations into consideration when you use the ClientMetadata parameter:\n> \n> - Amazon Cognito does not store the ClientMetadata value. This data is available only to AWS Lambda triggers that are assigned to a user pool to support custom workflows. If your user pool configuration does not include triggers, the ClientMetadata parameter serves no purpose.\n> - Amazon Cognito does not validate the ClientMetadata value.\n> - Amazon Cognito does not encrypt the the ClientMetadata value, so don't use it to provide sensitive information.", + "patternProperties": { + "^[a-zA-Z0-9]+$": { + "type": "string" + } + }, "title": "ClientMetadata", "type": "object" }, @@ -60890,16 +60898,6 @@ "Properties": { "additionalProperties": false, "properties": { - "DefaultResourceDiscoveryAssociationId": { - "markdownDescription": "The IPAM's default resource discovery association ID.", - "title": "DefaultResourceDiscoveryAssociationId", - "type": "string" - }, - "DefaultResourceDiscoveryId": { - "markdownDescription": "The IPAM's default resource discovery ID.", - "title": "DefaultResourceDiscoveryId", - "type": "string" - }, "Description": { "markdownDescription": "The description for the IPAM.", "title": "Description", @@ -85193,6 +85191,12 @@ "title": "Sql", "type": "string" }, + "Sqls": { + "items": { + "type": "string" + }, + "type": "array" + }, "StatementName": { "markdownDescription": "The name of the SQL statement. You can name the SQL statement when you create it to identify the query.", "title": "StatementName", @@ -85205,7 +85209,8 @@ } }, "required": [ - "Database" + "Database", + "Sql" ], "type": "object" }, @@ -85313,22 +85318,6 @@ ], "type": "object" }, - "AWS::Events::Rule.Tag": { - "additionalProperties": false, - "properties": { - "Key": { - "markdownDescription": "A string you can use to assign a value. The combination of tag keys and values can help you organize and categorize your resources.", - "title": "Key", - "type": "string" - }, - "Value": { - "markdownDescription": "The value for the specified tag key.", - "title": "Value", - "type": "string" - } - }, - "type": "object" - }, "AWS::Events::Rule.Target": { "additionalProperties": false, "properties": { @@ -100309,6 +100298,79 @@ ], "type": "object" }, + "AWS::HealthImaging::Datastore": { + "additionalProperties": false, + "properties": { + "Condition": { + "type": "string" + }, + "DeletionPolicy": { + "enum": [ + "Delete", + "Retain", + "Snapshot" + ], + "type": "string" + }, + "DependsOn": { + "anyOf": [ + { + "pattern": "^[a-zA-Z0-9]+$", + "type": "string" + }, + { + "items": { + "pattern": "^[a-zA-Z0-9]+$", + "type": "string" + }, + "type": "array" + } + ] + }, + "Metadata": { + "type": "object" + }, + "Properties": { + "additionalProperties": false, + "properties": { + "DatastoreName": { + "type": "string" + }, + "KmsKeyArn": { + "type": "string" + }, + "Tags": { + "additionalProperties": true, + "patternProperties": { + "^[a-zA-Z0-9]+$": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Type": { + "enum": [ + "AWS::HealthImaging::Datastore" + ], + "type": "string" + }, + "UpdateReplacePolicy": { + "enum": [ + "Delete", + "Retain", + "Snapshot" + ], + "type": "string" + } + }, + "required": [ + "Type" + ], + "type": "object" + }, "AWS::HealthLake::FHIRDatastore": { "additionalProperties": false, "properties": { @@ -118970,6 +119032,9 @@ "title": "IndexId", "type": "string" }, + "LanguageCode": { + "type": "string" + }, "Name": { "markdownDescription": "The name of the data source.", "title": "Name", @@ -123545,6 +123610,9 @@ "markdownDescription": "When a Kinesis stream is used as the source for the delivery stream, a [KinesisStreamSourceConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesisfirehose-deliverystream-kinesisstreamsourceconfiguration.html) containing the Kinesis stream ARN and the role ARN for the source stream.", "title": "KinesisStreamSourceConfiguration" }, + "MSKSourceConfiguration": { + "$ref": "#/definitions/AWS::KinesisFirehose::DeliveryStream.MSKSourceConfiguration" + }, "RedshiftDestinationConfiguration": { "$ref": "#/definitions/AWS::KinesisFirehose::DeliveryStream.RedshiftDestinationConfiguration", "markdownDescription": "An Amazon Redshift destination for the delivery stream.\n\nConditional. You must specify only one destination configuration.\n\nIf you change the delivery stream destination from an Amazon Redshift destination to an Amazon ES destination, update requires [some interruptions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-some-interrupt) .", @@ -123787,6 +123855,22 @@ }, "type": "object" }, + "AWS::KinesisFirehose::DeliveryStream.AuthenticationConfiguration": { + "additionalProperties": false, + "properties": { + "Connectivity": { + "type": "string" + }, + "RoleARN": { + "type": "string" + } + }, + "required": [ + "Connectivity", + "RoleARN" + ], + "type": "object" + }, "AWS::KinesisFirehose::DeliveryStream.BufferingHints": { "additionalProperties": false, "properties": { @@ -124315,6 +124399,26 @@ ], "type": "object" }, + "AWS::KinesisFirehose::DeliveryStream.MSKSourceConfiguration": { + "additionalProperties": false, + "properties": { + "AuthenticationConfiguration": { + "$ref": "#/definitions/AWS::KinesisFirehose::DeliveryStream.AuthenticationConfiguration" + }, + "MSKClusterARN": { + "type": "string" + }, + "TopicName": { + "type": "string" + } + }, + "required": [ + "AuthenticationConfiguration", + "MSKClusterARN", + "TopicName" + ], + "type": "object" + }, "AWS::KinesisFirehose::DeliveryStream.OpenXJsonSerDe": { "additionalProperties": false, "properties": { @@ -136207,6 +136311,9 @@ "title": "KafkaVersionsList", "type": "array" }, + "LatestRevision": { + "$ref": "#/definitions/AWS::MSK::Configuration.LatestRevision" + }, "Name": { "markdownDescription": "The name of the configuration. Configuration names are strings that match the regex \"^[0-9A-Za-z][0-9A-Za-z-]{0,}$\".", "title": "Name", @@ -136245,6 +136352,21 @@ ], "type": "object" }, + "AWS::MSK::Configuration.LatestRevision": { + "additionalProperties": false, + "properties": { + "CreationTime": { + "type": "string" + }, + "Description": { + "type": "string" + }, + "Revision": { + "type": "number" + } + }, + "type": "object" + }, "AWS::MSK::ServerlessCluster": { "additionalProperties": false, "properties": { @@ -178845,6 +178967,9 @@ "title": "DateTimeFormat", "type": "string" }, + "InfoIconLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions" + }, "TitleOptions": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.LabelOptions", "markdownDescription": "The options to configure the title visibility, name, and font size.", @@ -179172,6 +179297,9 @@ "AWS::QuickSight::Dashboard.DropDownControlDisplayOptions": { "additionalProperties": false, "properties": { + "InfoIconLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions" + }, "SelectAllOptions": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.ListControlSelectAllOptions", "markdownDescription": "The configuration of the `Select all` options in a dropdown control.", @@ -179994,6 +180122,9 @@ "AWS::QuickSight::Dashboard.FilterScopeConfiguration": { "additionalProperties": false, "properties": { + "AllSheets": { + "type": "object" + }, "SelectedSheets": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.SelectedSheetsFilterScopeConfiguration", "markdownDescription": "The configuration for applying a filter to specific sheets.", @@ -180250,8 +180381,7 @@ } }, "required": [ - "ComputationId", - "Time" + "ComputationId" ], "type": "object" }, @@ -181267,8 +181397,7 @@ } }, "required": [ - "ComputationId", - "Time" + "ComputationId" ], "type": "object" }, @@ -182424,6 +182553,9 @@ "AWS::QuickSight::Dashboard.ListControlDisplayOptions": { "additionalProperties": false, "properties": { + "InfoIconLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions" + }, "SearchOptions": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.ListControlSearchOptions", "markdownDescription": "The configuration of the search options in a list control.", @@ -182567,7 +182699,6 @@ }, "required": [ "ComputationId", - "Time", "Type" ], "type": "object" @@ -182628,10 +182759,7 @@ } }, "required": [ - "ComputationId", - "FromValue", - "TargetValue", - "Time" + "ComputationId" ], "type": "object" }, @@ -183548,8 +183676,7 @@ } }, "required": [ - "ComputationId", - "Time" + "ComputationId" ], "type": "object" }, @@ -183583,8 +183710,7 @@ } }, "required": [ - "ComputationId", - "Time" + "ComputationId" ], "type": "object" }, @@ -184083,6 +184209,9 @@ "title": "ColumnNamesVisibility", "type": "string" }, + "DefaultCellWidth": { + "type": "string" + }, "MetricPlacement": { "markdownDescription": "The metric placement (row, column) options.", "title": "MetricPlacement", @@ -184103,6 +184232,12 @@ "markdownDescription": "The table cell style of the row headers.", "title": "RowHeaderStyle" }, + "RowsLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.PivotTableRowsLabelOptions" + }, + "RowsLayout": { + "type": "string" + }, "SingleMetricVisibility": { "markdownDescription": "The visibility of the single metric options.", "title": "SingleMetricVisibility", @@ -184132,6 +184267,18 @@ }, "type": "object" }, + "AWS::QuickSight::Dashboard.PivotTableRowsLabelOptions": { + "additionalProperties": false, + "properties": { + "CustomLabel": { + "type": "string" + }, + "Visibility": { + "type": "string" + } + }, + "type": "object" + }, "AWS::QuickSight::Dashboard.PivotTableSortBy": { "additionalProperties": false, "properties": { @@ -184729,6 +184876,9 @@ "title": "DateTimeFormat", "type": "string" }, + "InfoIconLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions" + }, "TitleOptions": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.LabelOptions", "markdownDescription": "The options to configure the title visibility, name, and font size.", @@ -184863,6 +185013,9 @@ "markdownDescription": "Determines the widget status.", "title": "Status", "type": "string" + }, + "UsePrimaryBackgroundColor": { + "type": "string" } }, "type": "object" @@ -185445,6 +185598,18 @@ }, "type": "object" }, + "AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions": { + "additionalProperties": false, + "properties": { + "InfoIconText": { + "type": "string" + }, + "Visibility": { + "type": "string" + } + }, + "type": "object" + }, "AWS::QuickSight::Dashboard.SheetControlLayout": { "additionalProperties": false, "properties": { @@ -185682,6 +185847,9 @@ "AWS::QuickSight::Dashboard.SliderControlDisplayOptions": { "additionalProperties": false, "properties": { + "InfoIconLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions" + }, "TitleOptions": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.LabelOptions", "markdownDescription": "The options to configure the title visibility, name, and font size.", @@ -185690,6 +185858,18 @@ }, "type": "object" }, + "AWS::QuickSight::Dashboard.SmallMultiplesAxisProperties": { + "additionalProperties": false, + "properties": { + "Placement": { + "type": "string" + }, + "Scale": { + "type": "string" + } + }, + "type": "object" + }, "AWS::QuickSight::Dashboard.SmallMultiplesOptions": { "additionalProperties": false, "properties": { @@ -185707,6 +185887,12 @@ "$ref": "#/definitions/AWS::QuickSight::Dashboard.PanelConfiguration", "markdownDescription": "Configures the display options for each small multiples panel.", "title": "PanelConfiguration" + }, + "XAxis": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SmallMultiplesAxisProperties" + }, + "YAxis": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SmallMultiplesAxisProperties" } }, "type": "object" @@ -185875,6 +186061,12 @@ "markdownDescription": "The cell styling options for the subtotals of header cells.", "title": "MetricHeaderCellStyle" }, + "StyleTargets": { + "items": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.TableStyleTarget" + }, + "type": "array" + }, "TotalCellStyle": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.TableCellStyle", "markdownDescription": "The cell styling options for the subtotal cells.", @@ -186375,6 +186567,18 @@ }, "type": "object" }, + "AWS::QuickSight::Dashboard.TableStyleTarget": { + "additionalProperties": false, + "properties": { + "CellType": { + "type": "string" + } + }, + "required": [ + "CellType" + ], + "type": "object" + }, "AWS::QuickSight::Dashboard.TableUnaggregatedFieldWells": { "additionalProperties": false, "properties": { @@ -186434,6 +186638,9 @@ "AWS::QuickSight::Dashboard.TextAreaControlDisplayOptions": { "additionalProperties": false, "properties": { + "InfoIconLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions" + }, "PlaceholderOptions": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.TextControlPlaceholderOptions", "markdownDescription": "The configuration of the placeholder options in a text area control.", @@ -186482,6 +186689,9 @@ "AWS::QuickSight::Dashboard.TextFieldControlDisplayOptions": { "additionalProperties": false, "properties": { + "InfoIconLabelOptions": { + "$ref": "#/definitions/AWS::QuickSight::Dashboard.SheetControlInfoIconLabelOptions" + }, "PlaceholderOptions": { "$ref": "#/definitions/AWS::QuickSight::Dashboard.TextControlPlaceholderOptions", "markdownDescription": "The configuration of the placeholder options in a text field control.", @@ -186817,9 +187027,7 @@ } }, "required": [ - "Category", "ComputationId", - "Time", "Type" ], "type": "object" @@ -186859,7 +187067,6 @@ } }, "required": [ - "Category", "ComputationId", "Type" ], @@ -186885,8 +187092,7 @@ } }, "required": [ - "ComputationId", - "Value" + "ComputationId" ], "type": "object" }, @@ -187133,7 +187339,6 @@ } }, "required": [ - "Category", "ComputationId" ], "type": "object" @@ -219687,7 +219892,13 @@ "type": "string" }, "Tags": { + "additionalProperties": true, "markdownDescription": "Optional metadata that you assign to a resource in the form of an arbitrary set of tags (key-value pairs). Tags enable you to categorize a resource in different ways, such as by purpose, owner, or environment. For example, you might want to tag a Systems Manager parameter to identify the type of resource to which it applies, the environment, or the type of configuration data referenced by the parameter.", + "patternProperties": { + "^[a-zA-Z0-9]+$": { + "type": "string" + } + }, "title": "Tags", "type": "object" }, @@ -227011,6 +227222,9 @@ "title": "SamplePayloadUrl", "type": "string" }, + "SkipModelValidation": { + "type": "string" + }, "SourceAlgorithmSpecification": { "$ref": "#/definitions/AWS::SageMaker::ModelPackage.SourceAlgorithmSpecification", "markdownDescription": "A list of algorithms that were used to create a model package.", @@ -249736,6 +249950,9 @@ { "$ref": "#/definitions/AWS::GuardDuty::ThreatIntelSet" }, + { + "$ref": "#/definitions/AWS::HealthImaging::Datastore" + }, { "$ref": "#/definitions/AWS::HealthLake::FHIRDatastore" },