Repository: cloudtools/troposphere
Pull request #2018 (2022-03-11 13:05:10)

Updates from spec version 60.0.0
Autogenerated by maintenance action

If tests are stuck on https://github.com/peter-evans/create-pull-request/issues/48:
["Manually close pull requests and immediately reopen them. This will enable `on: pull_request` workflows to run and be added as checks."](https://github.com/peter-evans/create-pull-request/blob/master/docs/concepts-guidelines.md#triggering-further-workflow-runs)

markpeek: @PatMyron do the EC2 removals look odd to you for this spec version? And doesn't match with the current docs that still have those properties in place.

Patch:
diff --git a/resources_aws.md b/resources_aws.md
index 1ccb1ef8..d6462ae1 100644
--- a/resources_aws.md
+++ b/resources_aws.md
@@ -108,6 +108,7 @@
 - [AWS::KinesisAnalytics](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_KinesisAnalytics.html)
 - [AWS::KinesisAnalyticsV2](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_KinesisAnalyticsV2.html)
 - [AWS::KinesisFirehose](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_KinesisFirehose.html)
+- [AWS::KinesisVideo](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_KinesisVideo.html)
 - [AWS::LakeFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_LakeFormation.html)
 - [AWS::Lambda](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Lambda.html)
 - [AWS::Lex](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Lex.html)
@@ -136,6 +137,7 @@
 - [AWS::OpsWorks](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_OpsWorks.html)
 - [AWS::OpsWorksCM](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_OpsWorksCM.html)
 - [AWS::Panorama](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Panorama.html)
+- [AWS::Personalize](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Personalize.html)
 - [AWS::Pinpoint](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Pinpoint.html)
 - [AWS::PinpointEmail](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_PinpointEmail.html)
 - [AWS::QLDB](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_QLDB.html)
diff --git a/troposphere/__init__.py b/troposphere/__init__.py
index 0116d495..64151393 100644
--- a/troposphere/__init__.py
+++ b/troposphere/__init__.py
@@ -397,7 +397,7 @@ class BaseAWSObject:
     def _validate_props(self) -> None:
         for k, (_, required) in self.props.items():
             if required and k not in self.properties:
-                rtype = getattr(self, "resource_type", "<unknown type>")
+                rtype = getattr(self, "resource_type", type(self))
                 title = getattr(self, "title")
                 msg = "Resource %s required in type %s" % (k, rtype)
                 if title:
diff --git a/troposphere/appflow.py b/troposphere/appflow.py
index 5c9bf914..8111077a 100644
--- a/troposphere/appflow.py
+++ b/troposphere/appflow.py
@@ -461,6 +461,17 @@ class LookoutMetricsDestinationProperties(AWSProperty):
     }
 
 
+class MarketoDestinationProperties(AWSProperty):
+    """
+    `MarketoDestinationProperties <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-marketodestinationproperties.html>`__
+    """
+
+    props: PropsDictType = {
+        "ErrorHandlingConfig": (ErrorHandlingConfig, False),
+        "Object": (str, True),
+    }
+
+
 class RedshiftDestinationProperties(AWSProperty):
     """
     `RedshiftDestinationProperties <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appflow-flow-redshiftdestinationproperties.html>`__
@@ -615,6 +626,7 @@ class DestinationConnectorProperties(AWSProperty):
     props: PropsDictType = {
         "EventBridge": (EventBridgeDestinationProperties, False),
         "LookoutMetrics": (LookoutMetricsDestinationProperties, False),
+        "Marketo": (MarketoDestinationProperties, False),
         "Redshift": (RedshiftDestinationProperties, False),
         "S3": (S3DestinationProperties, False),
         "SAPOData": (SAPODataDestinationProperties, False),
diff --git a/troposphere/autoscaling.py b/troposphere/autoscaling.py
index e5df87c6..eb50a32f 100644
--- a/troposphere/autoscaling.py
+++ b/troposphere/autoscaling.py
@@ -383,6 +383,85 @@ class LifecycleHook(AWSObject):
     }
 
 
+class MetricDimension(AWSProperty):
+    """
+    `MetricDimension <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricdimension.html>`__
+    """
+
+    props: PropsDictType = {
+        "Name": (str, True),
+        "Value": (str, True),
+    }
+
+
+class Metric(AWSProperty):
+    """
+    `Metric <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metric.html>`__
+    """
+
+    props: PropsDictType = {
+        "Dimensions": ([MetricDimension], False),
+        "MetricName": (str, True),
+        "Namespace": (str, True),
+    }
+
+
+class MetricStat(AWSProperty):
+    """
+    `MetricStat <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricstat.html>`__
+    """
+
+    props: PropsDictType = {
+        "Metric": (Metric, True),
+        "Stat": (str, True),
+        "Unit": (str, False),
+    }
+
+
+class MetricDataQuery(AWSProperty):
+    """
+    `MetricDataQuery <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricdataquery.html>`__
+    """
+
+    props: PropsDictType = {
+        "Expression": (str, False),
+        "Id": (str, True),
+        "Label": (str, False),
+        "MetricStat": (MetricStat, False),
+        "ReturnData": (boolean, False),
+    }
+
+
+class PredictiveScalingCustomizedCapacityMetric(AWSProperty):
+    """
+    `PredictiveScalingCustomizedCapacityMetric <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingcustomizedcapacitymetric.html>`__
+    """
+
+    props: PropsDictType = {
+        "MetricDataQueries": ([MetricDataQuery], True),
+    }
+
+
+class PredictiveScalingCustomizedLoadMetric(AWSProperty):
+    """
+    `PredictiveScalingCustomizedLoadMetric <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingcustomizedloadmetric.html>`__
+    """
+
+    props: PropsDictType = {
+        "MetricDataQueries": ([MetricDataQuery], True),
+    }
+
+
+class PredictiveScalingCustomizedScalingMetric(AWSProperty):
+    """
+    `PredictiveScalingCustomizedScalingMetric <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingcustomizedscalingmetric.html>`__
+    """
+
+    props: PropsDictType = {
+        "MetricDataQueries": ([MetricDataQuery], True),
+    }
+
+
 class PredictiveScalingPredefinedLoadMetric(AWSProperty):
     """
     `PredictiveScalingPredefinedLoadMetric <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-predictivescalingpredefinedloadmetric.html>`__
@@ -422,6 +501,18 @@ class PredictiveScalingMetricSpecification(AWSProperty):
     """
 
     props: PropsDictType = {
+        "CustomizedCapacityMetricSpecification": (
+            PredictiveScalingCustomizedCapacityMetric,
+            False,
+        ),
+        "CustomizedLoadMetricSpecification": (
+            PredictiveScalingCustomizedLoadMetric,
+            False,
+        ),
+        "CustomizedScalingMetricSpecification": (
+            PredictiveScalingCustomizedScalingMetric,
+            False,
+        ),
         "PredefinedLoadMetricSpecification": (
             PredictiveScalingPredefinedLoadMetric,
             False,
@@ -464,17 +555,6 @@ class StepAdjustments(AWSProperty):
     }
 
 
-class MetricDimension(AWSProperty):
-    """
-    `MetricDimension <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-metricdimension.html>`__
-    """
-
-    props: PropsDictType = {
-        "Name": (str, True),
-        "Value": (str, True),
-    }
-
-
 class CustomizedMetricSpecification(AWSProperty):
     """
     `CustomizedMetricSpecification <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-scalingpolicy-customizedmetricspecification.html>`__
diff --git a/troposphere/ec2.py b/troposphere/ec2.py
index 59c8cfd9..23a122ec 100644
--- a/troposphere/ec2.py
+++ b/troposphere/ec2.py
@@ -2008,18 +2008,6 @@ class SpotFleet(AWSObject):
     }
 
 
-class PrivateDnsNameOptionsOnLaunch(AWSProperty):
-    """
-    `PrivateDnsNameOptionsOnLaunch <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-subnet-privatednsnameoptionsonlaunch.html>`__
-    """
-
-    props: PropsDictType = {
-        "EnableResourceNameDnsAAAARecord": (boolean, False),
-        "EnableResourceNameDnsARecord": (boolean, False),
-        "HostnameType": (str, False),
-    }
-
-
 class Subnet(AWSObject):
     """
     `Subnet <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html>`__
@@ -2030,14 +2018,10 @@ class Subnet(AWSObject):
     props: PropsDictType = {
         "AssignIpv6AddressOnCreation": (boolean, False),
         "AvailabilityZone": (str, False),
-        "AvailabilityZoneId": (str, False),
         "CidrBlock": (str, True),
-        "EnableDns64": (boolean, False),
         "Ipv6CidrBlock": (str, False),
-        "Ipv6Native": (boolean, False),
         "MapPublicIpOnLaunch": (boolean, False),
         "OutpostArn": (str, False),
-        "PrivateDnsNameOptionsOnLaunch": (PrivateDnsNameOptionsOnLaunch, False),
         "Tags": (validate_tags_or_list, False),
         "VpcId": (str, True),
     }
@@ -2283,16 +2267,6 @@ class TransitGatewayMulticastGroupSource(AWSObject):
     }
 
 
-class TransitGatewayPeeringAttachmentOptions(AWSProperty):
-    """
-    `TransitGatewayPeeringAttachmentOptions <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-transitgatewaypeeringattachment-transitgatewaypeeringattachmentoptions.html>`__
-    """
-
-    props: PropsDictType = {
-        "DynamicRouting": (str, False),
-    }
-
-
 class TransitGatewayPeeringAttachment(AWSObject):
     """
     `TransitGatewayPeeringAttachment <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-transitgatewaypeeringattachment.html>`__
@@ -2301,7 +2275,6 @@ class TransitGatewayPeeringAttachment(AWSObject):
     resource_type = "AWS::EC2::TransitGatewayPeeringAttachment"
 
     props: PropsDictType = {
-        "Options": (TransitGatewayPeeringAttachmentOptions, False),
         "PeerAccountId": (str, True),
         "PeerRegion": (str, True),
         "PeerTransitGatewayId": (str, True),
diff --git a/troposphere/fis.py b/troposphere/fis.py
index 4f2af9c7..6692f1eb 100644
--- a/troposphere/fis.py
+++ b/troposphere/fis.py
@@ -7,6 +7,7 @@
 
 
 from . import AWSObject, AWSProperty, PropsDictType
+from .validators import integer
 
 
 class ExperimentTemplateAction(AWSProperty):
@@ -23,6 +24,18 @@ class ExperimentTemplateAction(AWSProperty):
     }
 
 
+class ExperimentTemplateLogConfiguration(AWSProperty):
+    """
+    `ExperimentTemplateLogConfiguration <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatelogconfiguration.html>`__
+    """
+
+    props: PropsDictType = {
+        "CloudWatchLogsConfiguration": (dict, False),
+        "LogSchemaVersion": (integer, True),
+        "S3Configuration": (dict, False),
+    }
+
+
 class ExperimentTemplateStopCondition(AWSProperty):
     """
     `ExperimentTemplateStopCondition <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fis-experimenttemplate-experimenttemplatestopcondition.html>`__
@@ -52,6 +65,7 @@ class ExperimentTemplateTarget(AWSProperty):
 
     props: PropsDictType = {
         "Filters": ([ExperimentTemplateTargetFilter], False),
+        "Parameters": (dict, False),
         "ResourceArns": ([str], False),
         "ResourceTags": (dict, False),
         "ResourceType": (str, True),
@@ -69,6 +83,7 @@ class ExperimentTemplate(AWSObject):
     props: PropsDictType = {
         "Actions": (dict, False),
         "Description": (str, True),
+        "LogConfiguration": (ExperimentTemplateLogConfiguration, False),
         "RoleArn": (str, True),
         "StopConditions": ([ExperimentTemplateStopCondition], True),
         "Tags": (dict, True),
diff --git a/troposphere/kinesisvideo.py b/troposphere/kinesisvideo.py
new file mode 100644
index 00000000..5c6bcf09
--- /dev/null
+++ b/troposphere/kinesisvideo.py
@@ -0,0 +1,42 @@
+# Copyright (c) 2012-2022, Mark Peek <mark@peek.org>
+# All rights reserved.
+#
+# See LICENSE file for full license.
+#
+# *** Do not modify - this file is autogenerated ***
+
+
+from . import AWSObject, PropsDictType, Tags
+from .validators import integer
+
+
+class SignalingChannel(AWSObject):
+    """
+    `SignalingChannel <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kinesisvideo-signalingchannel.html>`__
+    """
+
+    resource_type = "AWS::KinesisVideo::SignalingChannel"
+
+    props: PropsDictType = {
+        "MessageTtlSeconds": (integer, False),
+        "Name": (str, False),
+        "Tags": (Tags, False),
+        "Type": (str, False),
+    }
+
+
+class Stream(AWSObject):
+    """
+    `Stream <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kinesisvideo-stream.html>`__
+    """
+
+    resource_type = "AWS::KinesisVideo::Stream"
+
+    props: PropsDictType = {
+        "DataRetentionInHours": (integer, False),
+        "DeviceName": (str, False),
+        "KmsKeyId": (str, False),
+        "MediaType": (str, False),
+        "Name": (str, False),
+        "Tags": (Tags, False),
+    }
diff --git a/troposphere/lex.py b/troposphere/lex.py
index f950eba5..20b661ac 100644
--- a/troposphere/lex.py
+++ b/troposphere/lex.py
@@ -589,7 +589,7 @@ class AudioLogDestination(AWSProperty):
     """
 
     props: PropsDictType = {
-        "S3Bucket": (S3BucketLogDestination, False),
+        "S3Bucket": (S3BucketLogDestination, True),
     }
 
 
@@ -621,7 +621,7 @@ class TextLogDestination(AWSProperty):
     """
 
     props: PropsDictType = {
-        "CloudWatch": (CloudWatchLogGroupLogDestination, False),
+        "CloudWatch": (CloudWatchLogGroupLogDestination, True),
     }
 
 
@@ -631,8 +631,8 @@ class TextLogSetting(AWSProperty):
     """
 
     props: PropsDictType = {
-        "Destination": (TextLogDestination, False),
-        "Enabled": (boolean, False),
+        "Destination": (TextLogDestination, True),
+        "Enabled": (boolean, True),
     }
 
 
diff --git a/troposphere/personalize.py b/troposphere/personalize.py
new file mode 100644
index 00000000..6a11fb52
--- /dev/null
+++ b/troposphere/personalize.py
@@ -0,0 +1,101 @@
+# Copyright (c) 2012-2022, Mark Peek <mark@peek.org>
+# All rights reserved.
+#
+# See LICENSE file for full license.
+#
+# *** Do not modify - this file is autogenerated ***
+
+
+from . import AWSObject, AWSProperty, PropsDictType
+from .validators import boolean
+
+
+class DatasetImportJob(AWSProperty):
+    """
+    `DatasetImportJob <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-personalize-dataset-datasetimportjob.html>`__
+    """
+
+    props: PropsDictType = {
+        "DataSource": (dict, False),
+        "DatasetArn": (str, False),
+        "DatasetImportJobArn": (str, False),
+        "JobName": (str, False),
+        "RoleArn": (str, False),
+    }
+
+
+class Dataset(AWSObject):
+    """
+    `Dataset <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-dataset.html>`__
+    """
+
+    resource_type = "AWS::Personalize::Dataset"
+
+    props: PropsDictType = {
+        "DatasetGroupArn": (str, True),
+        "DatasetImportJob": (DatasetImportJob, False),
+        "DatasetType": (str, True),
+        "Name": (str, True),
+        "SchemaArn": (str, True),
+    }
+
+
+class DatasetGroup(AWSObject):
+    """
+    `DatasetGroup <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-datasetgroup.html>`__
+    """
+
+    resource_type = "AWS::Personalize::DatasetGroup"
+
+    props: PropsDictType = {
+        "Domain": (str, False),
+        "KmsKeyArn": (str, False),
+        "Name": (str, True),
+        "RoleArn": (str, False),
+    }
+
+
+class Schema(AWSObject):
+    """
+    `Schema <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-schema.html>`__
+    """
+
+    resource_type = "AWS::Personalize::Schema"
+
+    props: PropsDictType = {
+        "Domain": (str, False),
+        "Name": (str, True),
+        "Schema": (str, True),
+    }
+
+
+class SolutionConfig(AWSProperty):
+    """
+    `SolutionConfig <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-personalize-solution-solutionconfig.html>`__
+    """
+
+    props: PropsDictType = {
+        "AlgorithmHyperParameters": (dict, False),
+        "AutoMLConfig": (dict, False),
+        "EventValueThreshold": (str, False),
+        "FeatureTransformationParameters": (dict, False),
+        "HpoConfig": (dict, False),
+    }
+
+
+class Solution(AWSObject):
+    """
+    `Solution <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-personalize-solution.html>`__
+    """
+
+    resource_type = "AWS::Personalize::Solution"
+
+    props: PropsDictType = {
+        "DatasetGroupArn": (str, True),
+        "EventType": (str, False),
+        "Name": (str, True),
+        "PerformAutoML": (boolean, False),
+        "PerformHPO": (boolean, False),
+        "RecipeArn": (str, False),
+        "SolutionConfig": (SolutionConfig, False),
+    }


Test patch:
diff --git a/tests/test_basic.py b/tests/test_basic.py
index bf5ce32e..0b5b13a9 100644
--- a/tests/test_basic.py
+++ b/tests/test_basic.py
@@ -196,6 +196,12 @@ class TestValidators(unittest.TestCase):
         with self.assertRaises(ValueError):
             ExceptionAWSProperty(foo="bar")
 
+    def test_error_message(self):
+        from troposphere.cloudfront import CustomHeader
+
+        with self.assertRaisesRegex(ValueError, "troposphere.cloudfront.CustomHeader"):
+            CustomHeader(Header="Cache-Policy", Value="no-cache").to_dict()
+
 
 class TestHealthCheck(unittest.TestCase):
     def test_healthy_interval_ok(self):