Repository: cloudtools/troposphere

Issue:
cloudformation distribution: OriginConfig should be CustomOriginConfig
The troposphere cloudformation class has the OriginConfig construct for defining things like load balancer domains. The correct name is CustomOriginConfig.

Details here:
https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CustomOriginConfig.html



Discussion:

Resolving patch:
diff --git a/examples/CloudFront_S3.py b/examples/CloudFront_S3.py
--- a/examples/CloudFront_S3.py
+++ b/examples/CloudFront_S3.py
@@ -30,7 +30,7 @@
     "myDistribution",
     DistributionConfig=DistributionConfig(
         Origins=[Origin(Id="Origin 1", DomainName=Ref(s3dnsname),
-                        S3OriginConfig=S3Origin())],
+                        S3OriginConfig=S3Origin(DomainName=Ref(s3dnsname)))],
         DefaultCacheBehavior=DefaultCacheBehavior(
             TargetOriginId="Origin 1",
             ForwardedValues=ForwardedValues(
diff --git a/troposphere/cloudfront.py b/troposphere/cloudfront.py
--- a/troposphere/cloudfront.py
+++ b/troposphere/cloudfront.py
@@ -4,12 +4,16 @@
 # See LICENSE file for full license.
 
 from . import AWSObject, AWSProperty, Tags
-from .validators import boolean, integer, positive_integer, network_port
+from .validators import (boolean, cloudfront_restriction_type,
+                         cloudfront_event_type,
+                         cloudfront_forward_type,
+                         cloudfront_viewer_protocol_policy, integer,
+                         positive_integer, priceclass_type, network_port)
 
 
 class Cookies(AWSProperty):
     props = {
-        'Forward': (basestring, True),
+        'Forward': (cloudfront_forward_type, True),
         'WhitelistedNames': ([basestring], False),
     }
 
@@ -25,7 +29,7 @@ class ForwardedValues(AWSProperty):
 
 class LambdaFunctionAssociation(AWSProperty):
     props = {
-        'EventType': (basestring, False),
+        'EventType': (cloudfront_event_type, False),
         'LambdaFunctionARN': (basestring, False),
     }
 
@@ -45,7 +49,7 @@ class CacheBehavior(AWSProperty):
         'SmoothStreaming': (boolean, False),
         'TargetOriginId': (basestring, True),
         'TrustedSigners': ([basestring], False),
-        'ViewerProtocolPolicy': (basestring, True),
+        'ViewerProtocolPolicy': (cloudfront_viewer_protocol_policy, True),
     }
 
 
@@ -63,24 +67,25 @@ class DefaultCacheBehavior(AWSProperty):
         'SmoothStreaming': (boolean, False),
         'TargetOriginId': (basestring, True),
         'TrustedSigners': (list, False),
-        'ViewerProtocolPolicy': (basestring, True),
+        'ViewerProtocolPolicy': (cloudfront_viewer_protocol_policy, True),
     }
 
 
 class S3Origin(AWSProperty):
     props = {
+        'DomainName': (basestring, True),
         'OriginAccessIdentity': (basestring, False),
     }
 
 
-class CustomOrigin(AWSProperty):
+class CustomOriginConfig(AWSProperty):
     props = {
         'HTTPPort': (network_port, False),
         'HTTPSPort': (network_port, False),
         'OriginKeepaliveTimeout': (integer, False),
         'OriginProtocolPolicy': (basestring, True),
-        'OriginSSLProtocols': ([basestring], False),
         'OriginReadTimeout': (integer, False),
+        'OriginSSLProtocols': ([basestring], False),
     }
 
 
@@ -93,12 +98,13 @@ class OriginCustomHeader(AWSProperty):
 
 class Origin(AWSProperty):
     props = {
+        'CustomOriginConfig': (CustomOriginConfig, False),
         'DomainName': (basestring, True),
-        'OriginPath': (basestring, False),
         'Id': (basestring, True),
         'OriginCustomHeaders': ([OriginCustomHeader], False),
+        'OriginPath': (basestring, False),
         'S3OriginConfig': (S3Origin, False),
-        'CustomOriginConfig': (CustomOrigin, False),
+
     }
 
 
@@ -122,7 +128,7 @@ class CustomErrorResponse(AWSProperty):
 class GeoRestriction(AWSProperty):
     props = {
         'Locations': ([basestring], False),
-        'RestrictionType': (basestring, True),
+        'RestrictionType': (cloudfront_restriction_type, True),
     }
 
 
@@ -154,8 +160,8 @@ class DistributionConfig(AWSProperty):
         'HttpVersion': (basestring, False),
         'IPV6Enabled': (boolean, False),
         'Logging': (Logging, False),
-        'Origins': (list, True),
-        'PriceClass': (basestring, False),
+        'Origins': ([Origin], True),
+        'PriceClass': (priceclass_type, False),
         'Restrictions': (Restrictions, False),
         'ViewerCertificate': (ViewerCertificate, False),
         'WebACLId': (basestring, False),
@@ -201,7 +207,7 @@ class StreamingDistributionConfig(AWSProperty):
         'Comment': (basestring, True),
         'Enabled': (boolean, True),
         'Logging': (Logging, False),
-        'PriceClass': (basestring, False),
+        'PriceClass': (priceclass_type, False),
         'S3Origin': (S3Origin, True),
         'TrustedSigners': (TrustedSigners, True),
     }
diff --git a/troposphere/validators.py b/troposphere/validators.py
--- a/troposphere/validators.py
+++ b/troposphere/validators.py
@@ -393,3 +393,60 @@ def statistic_type(statistic):
             )
         )
     return(statistic)
+
+
+def cloudfront_event_type(event_type):
+    valid_values = ['viewer-request', 'viewer-response',
+                    'origin-request', 'origin-response']
+    if event_type not in valid_values:
+        raise ValueError(
+            'EventType must be one of: "%s"' % (
+                ', '.join(valid_values)
+            )
+        )
+    return(event_type)
+
+
+def cloudfront_viewer_protocol_policy(viewer_protocol_policy):
+    valid_values = ['allow-all', 'redirect-to-https', 'https-only']
+    if viewer_protocol_policy not in valid_values:
+        raise ValueError(
+            'ViewerProtocolPolicy must be one of: "%s"' % (
+                ', '.join(valid_values)
+            )
+        )
+    return(viewer_protocol_policy)
+
+
+def cloudfront_restriction_type(restriction_type):
+    valid_values = ['none', 'blacklist', 'whitelist']
+    if restriction_type not in valid_values:
+        raise ValueError(
+            'RestrictionType must be one of: "%s"' % (
+                ', '.join(valid_values)
+            )
+        )
+    return(restriction_type)
+
+
+def cloudfront_forward_type(forward):
+    valid_values = ['none', 'all', 'whitelist']
+    if forward not in valid_values:
+        raise ValueError(
+            'Forward must be one of: "%s"' % (
+                ', '.join(valid_values)
+            )
+        )
+    return(forward)
+
+
+def priceclass_type(price_class):
+    valid_values = ['PriceClass_100', 'PriceClass_200',
+                    'PriceClass_All']
+    if price_class not in valid_values:
+        raise ValueError(
+            'PriceClass must be one of: "%s"' % (
+                ', '.join(valid_values)
+            )
+        )
+    return(price_class)


Test patch:
diff --git a/tests/examples_output/CloudFront_S3.template b/tests/examples_output/CloudFront_S3.template
--- a/tests/examples_output/CloudFront_S3.template
+++ b/tests/examples_output/CloudFront_S3.template
@@ -48,7 +48,11 @@
                                 "Ref": "S3DNSName"
                             },
                             "Id": "Origin 1",
-                            "S3OriginConfig": {}
+                            "S3OriginConfig": {
+                                "DomainName": {
+                                    "Ref": "S3DNSName"
+                                }
+                            }
                         }
                     ]
                 }