Repository: cloudtools/troposphere
Pull request #2022 (2022-03-24 16:36:47)

Update serverless.py
Update based on current docs:
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-api.html
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-requestmodel.html


Patch:
diff --git a/scripts/patches/fsx.py b/scripts/patches/fsx.py
new file mode 100644
index 00000000..fa88fac2
--- /dev/null
+++ b/scripts/patches/fsx.py
@@ -0,0 +1,24 @@
+patches = [
+    # Rename AWS::FSx::Volume.OntapConfiguration to AWS::FSx::Volume.VolumeOntapConfiguration - duplicate property name
+    {
+        "op": "move",
+        "from": "/PropertyTypes/AWS::FSx::Volume.OntapConfiguration",
+        "path": "/PropertyTypes/AWS::FSx::Volume.VolumeOntapConfiguration",
+    },
+    {
+        "op": "replace",
+        "path": "/ResourceTypes/AWS::FSx::Volume/Properties/OntapConfiguration/Type",
+        "value": "VolumeOntapConfiguration",
+    },
+    # Rename AWS::FSx::Volume.OpenZFSConfiguration to AWS::FSx::Volume.VolumeOpenZFSConfiguration - duplicate property name
+    {
+        "op": "move",
+        "from": "/PropertyTypes/AWS::FSx::Volume.OpenZFSConfiguration",
+        "path": "/PropertyTypes/AWS::FSx::Volume.VolumeOpenZFSConfiguration",
+    },
+    {
+        "op": "replace",
+        "path": "/ResourceTypes/AWS::FSx::Volume/Properties/OpenZFSConfiguration/Type",
+        "value": "VolumeOpenZFSConfiguration",
+    },
+]
diff --git a/troposphere/awslambda.py b/troposphere/awslambda.py
index cd8f6ae9..54c273fd 100644
--- a/troposphere/awslambda.py
+++ b/troposphere/awslambda.py
@@ -266,6 +266,16 @@ class Environment(AWSProperty):
     }
 
 
+class EphemeralStorage(AWSProperty):
+    """
+    `EphemeralStorage <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-ephemeralstorage.html>`__
+    """
+
+    props: PropsDictType = {
+        "Size": (integer, True),
+    }
+
+
 class FileSystemConfig(AWSProperty):
     """
     `FileSystemConfig <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-filesystemconfig.html>`__
@@ -327,6 +337,7 @@ class Function(AWSObject):
         "DeadLetterConfig": (DeadLetterConfig, False),
         "Description": (str, False),
         "Environment": (Environment, False),
+        "EphemeralStorage": (EphemeralStorage, False),
         "FileSystemConfigs": ([FileSystemConfig], False),
         "FunctionName": (str, False),
         "Handler": (str, False),
@@ -401,6 +412,7 @@ class Permission(AWSObject):
         "EventSourceToken": (str, False),
         "FunctionName": (str, True),
         "Principal": (str, True),
+        "PrincipalOrgID": (str, False),
         "SourceAccount": (str, False),
         "SourceArn": (str, False),
     }
diff --git a/troposphere/devopsguru.py b/troposphere/devopsguru.py
index 13719af7..ffb1ea49 100644
--- a/troposphere/devopsguru.py
+++ b/troposphere/devopsguru.py
@@ -51,6 +51,17 @@ class CloudFormationCollectionFilter(AWSProperty):
     }
 
 
+class TagCollection(AWSProperty):
+    """
+    `TagCollection <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-devopsguru-resourcecollection-tagcollection.html>`__
+    """
+
+    props: PropsDictType = {
+        "AppBoundaryKey": (str, False),
+        "TagValues": ([str], False),
+    }
+
+
 class ResourceCollectionFilter(AWSProperty):
     """
     `ResourceCollectionFilter <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-devopsguru-resourcecollection-resourcecollectionfilter.html>`__
@@ -58,6 +69,7 @@ class ResourceCollectionFilter(AWSProperty):
 
     props: PropsDictType = {
         "CloudFormation": (CloudFormationCollectionFilter, False),
+        "Tags": ([TagCollection], False),
     }
 
 
diff --git a/troposphere/docdb.py b/troposphere/docdb.py
index 98d64b23..142a9835 100644
--- a/troposphere/docdb.py
+++ b/troposphere/docdb.py
@@ -69,6 +69,7 @@ class DBInstance(AWSObject):
         "DBClusterIdentifier": (str, True),
         "DBInstanceClass": (str, True),
         "DBInstanceIdentifier": (str, False),
+        "EnablePerformanceInsights": (boolean, False),
         "PreferredMaintenanceWindow": (str, False),
         "Tags": (Tags, False),
     }
diff --git a/troposphere/ec2.py b/troposphere/ec2.py
index f31df955..7557c0fb 100644
--- a/troposphere/ec2.py
+++ b/troposphere/ec2.py
@@ -1256,6 +1256,16 @@ class Monitoring(AWSProperty):
     }
 
 
+class Ipv4PrefixSpecification(AWSProperty):
+    """
+    `Ipv4PrefixSpecification <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-ipv4prefixspecification.html>`__
+    """
+
+    props: PropsDictType = {
+        "Ipv4Prefix": (str, False),
+    }
+
+
 class Ipv6Add(AWSProperty):
     """
     `Ipv6Add <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-ipv6add.html>`__
@@ -1266,6 +1276,16 @@ class Ipv6Add(AWSProperty):
     }
 
 
+class Ipv6PrefixSpecification(AWSProperty):
+    """
+    `Ipv6PrefixSpecification <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-ipv6prefixspecification.html>`__
+    """
+
+    props: PropsDictType = {
+        "Ipv6Prefix": (str, False),
+    }
+
+
 class NetworkInterfaces(AWSProperty):
     """
     `NetworkInterfaces <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-networkinterface.html>`__
@@ -1279,8 +1299,12 @@ class NetworkInterfaces(AWSProperty):
         "DeviceIndex": (integer, False),
         "Groups": ([str], False),
         "InterfaceType": (str, False),
+        "Ipv4PrefixCount": (integer, False),
+        "Ipv4Prefixes": ([Ipv4PrefixSpecification], False),
         "Ipv6AddressCount": (integer, False),
         "Ipv6Addresses": ([Ipv6Add], False),
+        "Ipv6PrefixCount": (integer, False),
+        "Ipv6Prefixes": ([Ipv6PrefixSpecification], False),
         "NetworkCardIndex": (integer, False),
         "NetworkInterfaceId": (str, False),
         "PrivateIpAddress": (str, False),
diff --git a/troposphere/fsx.py b/troposphere/fsx.py
index 921a3ea7..f88bf74d 100644
--- a/troposphere/fsx.py
+++ b/troposphere/fsx.py
@@ -71,34 +71,34 @@ class OntapConfiguration(AWSProperty):
 
 class ClientConfigurations(AWSProperty):
     """
-    `ClientConfigurations <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-filesystem-openzfsconfiguration-rootvolumeconfiguration-nfsexports-clientconfigurations.html>`__
+    `ClientConfigurations <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-nfsexports-clientconfigurations.html>`__
     """
 
     props: PropsDictType = {
-        "Clients": (str, False),
-        "Options": ([str], False),
+        "Clients": (str, True),
+        "Options": ([str], True),
     }
 
 
 class NfsExports(AWSProperty):
     """
-    `NfsExports <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-filesystem-openzfsconfiguration-rootvolumeconfiguration-nfsexports.html>`__
+    `NfsExports <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-nfsexports.html>`__
     """
 
     props: PropsDictType = {
-        "ClientConfigurations": ([ClientConfigurations], False),
+        "ClientConfigurations": ([ClientConfigurations], True),
     }
 
 
 class UserAndGroupQuotas(AWSProperty):
     """
-    `UserAndGroupQuotas <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-filesystem-openzfsconfiguration-rootvolumeconfiguration-userandgroupquotas.html>`__
+    `UserAndGroupQuotas <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-userandgroupquotas.html>`__
     """
 
     props: PropsDictType = {
-        "Id": (integer, False),
-        "StorageCapacityQuotaGiB": (integer, False),
-        "Type": (str, False),
+        "Id": (integer, True),
+        "StorageCapacityQuotaGiB": (integer, True),
+        "Type": (str, True),
     }
 
 
@@ -150,7 +150,7 @@ class AuditLogConfiguration(AWSProperty):
 
 class SelfManagedActiveDirectoryConfiguration(AWSProperty):
     """
-    `SelfManagedActiveDirectoryConfiguration <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-filesystem-windowsconfiguration-selfmanagedactivedirectoryconfiguration.html>`__
+    `SelfManagedActiveDirectoryConfiguration <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-storagevirtualmachine-activedirectoryconfiguration-selfmanagedactivedirectoryconfiguration.html>`__
     """
 
     props: PropsDictType = {
@@ -208,3 +208,122 @@ class FileSystem(AWSObject):
         "Tags": (Tags, False),
         "WindowsConfiguration": (WindowsConfiguration, False),
     }
+
+
+class Snapshot(AWSObject):
+    """
+    `Snapshot <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-snapshot.html>`__
+    """
+
+    resource_type = "AWS::FSx::Snapshot"
+
+    props: PropsDictType = {
+        "Name": (str, True),
+        "Tags": (Tags, False),
+        "VolumeId": (str, True),
+    }
+
+
+class ActiveDirectoryConfiguration(AWSProperty):
+    """
+    `ActiveDirectoryConfiguration <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-storagevirtualmachine-activedirectoryconfiguration.html>`__
+    """
+
+    props: PropsDictType = {
+        "NetBiosName": (str, False),
+        "SelfManagedActiveDirectoryConfiguration": (
+            SelfManagedActiveDirectoryConfiguration,
+            False,
+        ),
+    }
+
+
+class StorageVirtualMachine(AWSObject):
+    """
+    `StorageVirtualMachine <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-storagevirtualmachine.html>`__
+    """
+
+    resource_type = "AWS::FSx::StorageVirtualMachine"
+
+    props: PropsDictType = {
+        "ActiveDirectoryConfiguration": (ActiveDirectoryConfiguration, False),
+        "FileSystemId": (str, True),
+        "Name": (str, True),
+        "RootVolumeSecurityStyle": (str, False),
+        "SvmAdminPassword": (str, False),
+        "Tags": (Tags, False),
+    }
+
+
+class TieringPolicy(AWSProperty):
+    """
+    `TieringPolicy <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-ontapconfiguration-tieringpolicy.html>`__
+    """
+
+    props: PropsDictType = {
+        "CoolingPeriod": (integer, False),
+        "Name": (str, False),
+    }
+
+
+class VolumeOntapConfiguration(AWSProperty):
+    """
+    `VolumeOntapConfiguration <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-ontapconfiguration.html>`__
+    """
+
+    props: PropsDictType = {
+        "JunctionPath": (str, True),
+        "SecurityStyle": (str, False),
+        "SizeInMegabytes": (str, True),
+        "StorageEfficiencyEnabled": (str, True),
+        "StorageVirtualMachineId": (str, True),
+        "TieringPolicy": (TieringPolicy, False),
+    }
+
+
+class OriginSnapshot(AWSProperty):
+    """
+    `OriginSnapshot <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration-originsnapshot.html>`__
+    """
+
+    props: PropsDictType = {
+        "CopyStrategy": (str, True),
+        "SnapshotARN": (str, True),
+    }
+
+
+class VolumeOpenZFSConfiguration(AWSProperty):
+    """
+    `VolumeOpenZFSConfiguration <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-fsx-volume-openzfsconfiguration.html>`__
+    """
+
+    props: PropsDictType = {
+        "CopyTagsToSnapshots": (boolean, False),
+        "DataCompressionType": (str, False),
+        "NfsExports": ([NfsExports], False),
+        "Options": ([str], False),
+        "OriginSnapshot": (OriginSnapshot, False),
+        "ParentVolumeId": (str, True),
+        "ReadOnly": (boolean, False),
+        "RecordSizeKiB": (integer, False),
+        "StorageCapacityQuotaGiB": (integer, False),
+        "StorageCapacityReservationGiB": (integer, False),
+        "UserAndGroupQuotas": ([UserAndGroupQuotas], False),
+    }
+
+
+class Volume(AWSObject):
+    """
+    `Volume <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-volume.html>`__
+    """
+
+    resource_type = "AWS::FSx::Volume"
+
+    props: PropsDictType = {
+        "BackupId": (str, False),
+        "Name": (str, True),
+        "OntapConfiguration": (VolumeOntapConfiguration, False),
+        "OpenZFSConfiguration": (VolumeOpenZFSConfiguration, False),
+        "Tags": (Tags, False),
+        "VolumeType": (str, False),
+    }
diff --git a/troposphere/iotevents.py b/troposphere/iotevents.py
index 0bf8b0fb..9d6da72a 100644
--- a/troposphere/iotevents.py
+++ b/troposphere/iotevents.py
@@ -10,13 +10,34 @@ from . import AWSObject, AWSProperty, PropsDictType, Tags
 from .validators import boolean, integer
 
 
-class ClearTimer(AWSProperty):
+class AcknowledgeFlow(AWSProperty):
     """
-    `ClearTimer <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-cleartimer.html>`__
+    `AcknowledgeFlow <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-acknowledgeflow.html>`__
     """
 
     props: PropsDictType = {
-        "TimerName": (str, True),
+        "Enabled": (boolean, False),
+    }
+
+
+class InitializationConfiguration(AWSProperty):
+    """
+    `InitializationConfiguration <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-initializationconfiguration.html>`__
+    """
+
+    props: PropsDictType = {
+        "DisabledOnInitialization": (boolean, True),
+    }
+
+
+class AlarmCapabilities(AWSProperty):
+    """
+    `AlarmCapabilities <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmcapabilities.html>`__
+    """
+
+    props: PropsDictType = {
+        "AcknowledgeFlow": (AcknowledgeFlow, False),
+        "InitializationConfiguration": (InitializationConfiguration, False),
     }
 
 
@@ -156,59 +177,139 @@ class Lambda(AWSProperty):
     }
 
 
-class ResetTimer(AWSProperty):
+class Sns(AWSProperty):
     """
-    `ResetTimer <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-resettimer.html>`__
+    `Sns <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-sns.html>`__
     """
 
     props: PropsDictType = {
-        "TimerName": (str, True),
+        "Payload": (Payload, False),
+        "TargetArn": (str, True),
     }
 
 
-class SetTimer(AWSProperty):
+class Sqs(AWSProperty):
     """
-    `SetTimer <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-settimer.html>`__
+    `Sqs <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-sqs.html>`__
+    """
+
+    props: PropsDictType = {
+        "Payload": (Payload, False),
+        "QueueUrl": (str, True),
+        "UseBase64": (boolean, False),
+    }
+
+
+class AlarmAction(AWSProperty):
+    """
+    `AlarmAction <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmaction.html>`__
+    """
+
+    props: PropsDictType = {
+        "DynamoDB": (DynamoDB, False),
+        "DynamoDBv2": (DynamoDBv2, False),
+        "Firehose": (Firehose, False),
+        "IotEvents": (IotEvents, False),
+        "IotSiteWise": (IotSiteWise, False),
+        "IotTopicPublish": (IotTopicPublish, False),
+        "Lambda": (Lambda, False),
+        "Sns": (Sns, False),
+        "Sqs": (Sqs, False),
+    }
+
+
+class AlarmEventActions(AWSProperty):
+    """
+    `AlarmEventActions <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmeventactions.html>`__
+    """
+
+    props: PropsDictType = {
+        "AlarmActions": ([AlarmAction], False),
+    }
+
+
+class SimpleRule(AWSProperty):
+    """
+    `SimpleRule <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-simplerule.html>`__
+    """
+
+    props: PropsDictType = {
+        "ComparisonOperator": (str, True),
+        "InputProperty": (str, True),
+        "Threshold": (str, True),
+    }
+
+
+class AlarmRule(AWSProperty):
+    """
+    `AlarmRule <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-alarmmodel-alarmrule.html>`__
+    """
+
+    props: PropsDictType = {
+        "SimpleRule": (SimpleRule, False),
+    }
+
+
+class AlarmModel(AWSObject):
+    """
+    `AlarmModel <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iotevents-alarmmodel.html>`__
+    """
+
+    resource_type = "AWS::IoTEvents::AlarmModel"
+
+    props: PropsDictType = {
+        "AlarmCapabilities": (AlarmCapabilities, False),
+        "AlarmEventActions": (AlarmEventActions, False),
+        "AlarmModelDescription": (str, False),
+        "AlarmModelName": (str, False),
+        "AlarmRule": (AlarmRule, True),
+        "Key": (str, False),
+        "RoleArn": (str, True),
+        "Severity": (integer, False),
+        "Tags": (Tags, False),
+    }
+
+
+class ClearTimer(AWSProperty):
+    """
+    `ClearTimer <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-cleartimer.html>`__
     """
 
     props: PropsDictType = {
-        "DurationExpression": (str, False),
-        "Seconds": (integer, False),
         "TimerName": (str, True),
     }
 
 
-class SetVariable(AWSProperty):
+class ResetTimer(AWSProperty):
     """
-    `SetVariable <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-setvariable.html>`__
+    `ResetTimer <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-resettimer.html>`__
     """
 
     props: PropsDictType = {
-        "Value": (str, True),
-        "VariableName": (str, True),
+        "TimerName": (str, True),
     }
 
 
-class Sns(AWSProperty):
+class SetTimer(AWSProperty):
     """
-    `Sns <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-sns.html>`__
+    `SetTimer <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-settimer.html>`__
     """
 
     props: PropsDictType = {
-        "Payload": (Payload, False),
-        "TargetArn": (str, True),
+        "DurationExpression": (str, False),
+        "Seconds": (integer, False),
+        "TimerName": (str, True),
     }
 
 
-class Sqs(AWSProperty):
+class SetVariable(AWSProperty):
     """
-    `Sqs <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-sqs.html>`__
+    `SetVariable <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotevents-detectormodel-setvariable.html>`__
     """
 
     props: PropsDictType = {
-        "Payload": (Payload, False),
-        "QueueUrl": (str, True),
-        "UseBase64": (boolean, False),
+        "Value": (str, True),
+        "VariableName": (str, True),
     }
 
 
diff --git a/troposphere/lex.py b/troposphere/lex.py
index 20b661ac..32475c56 100644
--- a/troposphere/lex.py
+++ b/troposphere/lex.py
@@ -11,6 +11,27 @@ from .validators import boolean, double, integer
 from .validators.lex import policytypes
 
 
+class CustomVocabularyItem(AWSProperty):
+    """
+    `CustomVocabularyItem <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-customvocabularyitem.html>`__
+    """
+
+    props: PropsDictType = {
+        "Phrase": (str, True),
+        "Weight": (integer, False),
+    }
+
+
+class CustomVocabulary(AWSProperty):
+    """
+    `CustomVocabulary <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-customvocabulary.html>`__
+    """
+
+    props: PropsDictType = {
+        "CustomVocabularyItems": ([CustomVocabularyItem], True),
+    }
+
+
 class DialogCodeHookSetting(AWSProperty):
     """
     `DialogCodeHookSetting <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-dialogcodehooksetting.html>`__
@@ -434,6 +455,16 @@ class SlotTypeValue(AWSProperty):
     }
 
 
+class AdvancedRecognitionSetting(AWSProperty):
+    """
+    `AdvancedRecognitionSetting <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-advancedrecognitionsetting.html>`__
+    """
+
+    props: PropsDictType = {
+        "AudioRecognitionStrategy": (str, False),
+    }
+
+
 class SlotValueRegexFilter(AWSProperty):
     """
     `SlotValueRegexFilter <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-slotvalueregexfilter.html>`__
@@ -450,6 +481,7 @@ class SlotValueSelectionSetting(AWSProperty):
     """
 
     props: PropsDictType = {
+        "AdvancedRecognitionSetting": (AdvancedRecognitionSetting, False),
         "RegexFilter": (SlotValueRegexFilter, False),
         "ResolutionStrategy": (str, True),
     }
@@ -486,6 +518,7 @@ class BotLocale(AWSProperty):
     """
 
     props: PropsDictType = {
+        "CustomVocabulary": (CustomVocabulary, False),
         "Description": (str, False),
         "Intents": ([Intent], False),
         "LocaleId": (str, True),
@@ -507,27 +540,6 @@ class S3Location(AWSProperty):
     }
 
 
-class Bot(AWSObject):
-    """
-    `Bot <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lex-bot.html>`__
-    """
-
-    resource_type = "AWS::Lex::Bot"
-
-    props: PropsDictType = {
-        "AutoBuildBotLocales": (boolean, False),
-        "BotFileS3Location": (S3Location, False),
-        "BotLocales": ([BotLocale], False),
-        "BotTags": (Tags, False),
-        "DataPrivacy": (dict, True),
-        "Description": (str, False),
-        "IdleSessionTTLInSeconds": (integer, True),
-        "Name": (str, True),
-        "RoleArn": (str, True),
-        "TestBotAliasTags": (Tags, False),
-    }
-
-
 class LambdaCodeHook(AWSProperty):
     """
     `LambdaCodeHook <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-botalias-lambdacodehook.html>`__
@@ -647,6 +659,41 @@ class ConversationLogSettings(AWSProperty):
     }
 
 
+class TestBotAliasSettings(AWSProperty):
+    """
+    `TestBotAliasSettings <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lex-bot-testbotaliassettings.html>`__
+    """
+
+    props: PropsDictType = {
+        "BotAliasLocaleSettings": ([BotAliasLocaleSettingsItem], False),
+        "ConversationLogSettings": (ConversationLogSettings, False),
+        "Description": (str, False),
+        "SentimentAnalysisSettings": (dict, False),
+    }
+
+
+class Bot(AWSObject):
+    """
+    `Bot <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lex-bot.html>`__
+    """
+
+    resource_type = "AWS::Lex::Bot"
+
+    props: PropsDictType = {
+        "AutoBuildBotLocales": (boolean, False),
+        "BotFileS3Location": (S3Location, False),
+        "BotLocales": ([BotLocale], False),
+        "BotTags": (Tags, False),
+        "DataPrivacy": (dict, True),
+        "Description": (str, False),
+        "IdleSessionTTLInSeconds": (integer, True),
+        "Name": (str, True),
+        "RoleArn": (str, True),
+        "TestBotAliasSettings": (TestBotAliasSettings, False),
+        "TestBotAliasTags": (Tags, False),
+    }
+
+
 class BotAlias(AWSObject):
     """
     `BotAlias <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lex-botalias.html>`__
diff --git a/troposphere/mediapackage.py b/troposphere/mediapackage.py
index 4126a0f3..1d107067 100644
--- a/troposphere/mediapackage.py
+++ b/troposphere/mediapackage.py
@@ -64,6 +64,17 @@ class Authorization(AWSProperty):
     }
 
 
+class EncryptionContractConfiguration(AWSProperty):
+    """
+    `EncryptionContractConfiguration <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediapackage-originendpoint-encryptioncontractconfiguration.html>`__
+    """
+
+    props: PropsDictType = {
+        "PresetSpeke20Audio": (str, True),
+        "PresetSpeke20Video": (str, True),
+    }
+
+
 class OriginEndpointSpekeKeyProvider(AWSProperty):
     """
     `OriginEndpointSpekeKeyProvider <http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-mediapackage-originendpoint-spekekeyprovider.html>`__
@@ -71,6 +82,7 @@ class OriginEndpointSpekeKeyProvider(AWSProperty):
 
     props: PropsDictType = {
         "CertificateArn": (str, False),
+        "EncryptionContractConfiguration": (EncryptionContractConfiguration, False),
         "ResourceId": (str, True),
         "RoleArn": (str, True),
         "SystemIds": ([str], True),
diff --git a/troposphere/serverless.py b/troposphere/serverless.py
index e8d47e0b..b5773dc9 100644
--- a/troposphere/serverless.py
+++ b/troposphere/serverless.py
@@ -366,13 +366,18 @@ class Api(AWSObject):
         "Cors": ((str, Cors), False),
         "DefinitionBody": (dict, False),
         "DefinitionUri": ((str, ApiDefinition), False),
+        "Description": (str, False),
+        "DisableExecuteApiEndpoint": (bool, False),
         "Domain": (Domain, False),
         "EndpointConfiguration": (EndpointConfiguration, False),
         "MethodSettings": ([MethodSetting], False),
         "MinimumCompressionSize": (integer_range(0, 10485760), False),
+        "Mode": (str, False),
+        "Models": (dict, False),
         "Name": (str, False),
         "OpenApiVersion": (str, False),
         "StageName": (str, True),
+        "Tags": (dict, False),
         "TracingEnabled": (bool, False),
         "Variables": (dict, False),
     }
@@ -559,6 +564,8 @@ class RequestModel(AWSProperty):
     props: PropsDictType = {
         "Model": (str, True),
         "Required": (bool, False),
+        "ValidateBody": (bool, False),
+        "ValidateParameters": (bool, False),
     }
 
 
diff --git a/troposphere/validators/cloudfront.py b/troposphere/validators/cloudfront.py
index 8187086d..0a5fc6e6 100644
--- a/troposphere/validators/cloudfront.py
+++ b/troposphere/validators/cloudfront.py
@@ -28,10 +28,16 @@ def cloudfront_access_control_allow_methods(access_control_allow_methods):
     Property: AccessControlAllowMethods.Items
     """
     valid_values = ["GET", "DELETE", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "ALL"]
-    if access_control_allow_methods not in valid_values:
-        raise ValueError(
-            'AccessControlAllowMethods must be of: "%s"' % (", ".join(valid_values))
-        )
+
+    if not isinstance(access_control_allow_methods, list):
+        raise TypeError("AccessControlAllowMethods is not a list")
+
+    for method in access_control_allow_methods:
+        if method not in valid_values:
+            raise ValueError(
+                'AccessControlAllowMethods must be one of: "%s"'
+                % (", ".join(valid_values))
+            )
     return access_control_allow_methods
 
 


Test patch:
diff --git a/tests/test_cloudfront.py b/tests/test_cloudfront.py
new file mode 100644
index 00000000..f67693e1
--- /dev/null
+++ b/tests/test_cloudfront.py
@@ -0,0 +1,25 @@
+import unittest
+
+import troposphere.cloudfront as cloudfront
+from troposphere import If
+
+
+class TestCorsConfig(unittest.TestCase):
+    def test_allowmethods(self):
+        cloudfront.AccessControlAllowMethods(Items=[])
+        cloudfront.AccessControlAllowMethods(Items=["GET", "POST"])
+        cloudfront.AccessControlAllowMethods(
+            Items=If("SomeCondition", ["GET"], ["POST"])
+        )
+        with self.assertRaises(ValueError):
+            cloudfront.AccessControlAllowMethods(Items=["get"])
+        with self.assertRaises(ValueError):
+            cloudfront.AccessControlAllowMethods(Items=["GET", "get", "PUT"])
+        with self.assertRaises(TypeError):
+            cloudfront.AccessControlAllowMethods(Items=10)
+        with self.assertRaises(TypeError):
+            cloudfront.AccessControlAllowMethods(Items="GET")
+
+
+if __name__ == "__main__":
+    unittest.main()