Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cloudfront Distribution: Origin Groups support #7202

Merged
merged 10 commits into from
Mar 17, 2019
Merged
163 changes: 162 additions & 1 deletion aws/cloudfront_distribution_configuration_structure.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ func expandDistributionConfig(d *schema.ResourceData) *cloudfront.DistributionCo
if v, ok := d.GetOk("viewer_certificate"); ok {
distributionConfig.ViewerCertificate = expandViewerCertificate(v.([]interface{})[0].(map[string]interface{}))
}

if v, ok := d.GetOk("origin_group"); ok {
distributionConfig.OriginGroups = expandOriginGroups(v.(*schema.Set))
}
return distributionConfig
}

Expand Down Expand Up @@ -151,6 +153,12 @@ func flattenDistributionConfig(d *schema.ResourceData, distributionConfig *cloud
return err
}
}
if *distributionConfig.OriginGroups.Quantity > 0 {
err = d.Set("origin_group", flattenOriginGroups(distributionConfig.OriginGroups))
if err != nil {
return err
}
}

return nil
}
Expand Down Expand Up @@ -595,6 +603,115 @@ func flattenOrigin(or *cloudfront.Origin) map[string]interface{} {
return m
}

func expandOriginGroups(s *schema.Set) *cloudfront.OriginGroups {
qty := 0
items := []*cloudfront.OriginGroup{}
for _, v := range s.List() {
items = append(items, expandOriginGroup(v.(map[string]interface{})))
qty++
}
return &cloudfront.OriginGroups{
Quantity: aws.Int64(int64(qty)),
Items: items,
}
}

func flattenOriginGroups(ogs *cloudfront.OriginGroups) *schema.Set {
s := []interface{}{}
for _, v := range ogs.Items {
s = append(s, flattenOriginGroup(v))
}
return schema.NewSet(originGroupHash, s)
}

func expandOriginGroup(m map[string]interface{}) *cloudfront.OriginGroup {
failoverCriteria := m["failover_criteria"].(*schema.Set)
members := m["members"].(*schema.Set)
originGroup := &cloudfront.OriginGroup{
Id: aws.String(m["origin_id"].(string)),
FailoverCriteria: expandOriginGroupFailoverCriteria(failoverCriteria),
Members: expandOriginGroupMembers(members),
}
return originGroup
}

func flattenOriginGroup(og *cloudfront.OriginGroup) map[string]interface{} {
m := make(map[string]interface{})
m["origin_id"] = *og.Id
if og.FailoverCriteria != nil {
m["failover_criteria"] = flattenOriginGroupFailoverCriteria(og.FailoverCriteria)
}
if og.Members != nil {
m["members"] = flattenOriginGroupMembers(og.Members)
}
return m
}

func expandOriginGroupFailoverCriteria(s *schema.Set) *cloudfront.OriginGroupFailoverCriteria {
failoverCriteria := &cloudfront.OriginGroupFailoverCriteria{}
m := s.List()[0].(map[string]interface{})
if v, ok := m["status_codes"]; ok {
codes := []*int64{}
for _, code := range v.([]interface{}) {
codes = append(codes, aws.Int64(int64(code.(int))))
}
failoverCriteria.StatusCodes = &cloudfront.StatusCodes{
Items: codes,
Quantity: aws.Int64(int64(len(codes))),
}
}
return failoverCriteria
}

func flattenOriginGroupFailoverCriteria(ogfc *cloudfront.OriginGroupFailoverCriteria) *schema.Set {
m := make(map[string]interface{})
codes := []interface{}{}
for _, code := range ogfc.StatusCodes.Items {
codes = append(codes, *code)
}
m["status_codes"] = codes
s := []interface{}{m}
return schema.NewSet(failoverCriteriaHash, s)
}

func expandOriginGroupMembers(s *schema.Set) *cloudfront.OriginGroupMembers {
members := s.List()[0].(map[string]interface{})["ordered_origin_group_member"].([]interface{})
qty := 0
items := []*cloudfront.OriginGroupMember{}
for _, v := range members {
items = append(items, expandOriginGroupMember(v.(map[string]interface{})))
qty++
}
return &cloudfront.OriginGroupMembers{
Quantity: aws.Int64(int64(qty)),
Items: items,
}
}

func flattenOriginGroupMembers(ogm *cloudfront.OriginGroupMembers) *schema.Set {
s := []interface{}{}
for _, v := range ogm.Items {
s = append(s, flattenOriginGroupMember(v))
}
m := []interface{}{map[string]interface{}{
"ordered_origin_group_member": s,
}}
return schema.NewSet(membersHash, m)
}

func expandOriginGroupMember(m map[string]interface{}) *cloudfront.OriginGroupMember {
return &cloudfront.OriginGroupMember{
OriginId: aws.String(m["origin_id"].(string)),
}
}

func flattenOriginGroupMember(ogms *cloudfront.OriginGroupMember) map[string]interface{} {
m := map[string]interface{}{
"origin_id": *ogms.OriginId,
}
return m
}

// Assemble the hash for the aws_cloudfront_distribution origin
// TypeSet attribute.
func originHash(v interface{}) int {
Expand All @@ -621,6 +738,50 @@ func originHash(v interface{}) int {
return hashcode.String(buf.String())
}

// Assemble the hash for the aws_cloudfront_distribution origin group
// TypeSet attribute.
func originGroupHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["origin_id"].(string)))
if v, ok := m["failover_criteria"]; ok {
if s := v.(*schema.Set).List(); len(s) > 0 {
buf.WriteString(fmt.Sprintf("%d-", failoverCriteriaHash(s[0])))
}
}
if v, ok := m["members"]; ok {
if members := v.(*schema.Set).List(); len(members) > 0 {
for _, member := range members {
buf.WriteString(fmt.Sprintf("%d-", membersHash(member)))
}
}
}
return hashcode.String(buf.String())
}

func membersHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})["ordered_origin_group_member"]
gm := m.([]interface{})
for _, member := range gm {
buf.WriteString(fmt.Sprintf("%s-", member.(map[string]interface{})["origin_id"]))
}

return hashcode.String(buf.String())
}

func failoverCriteriaHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
if v, ok := m["status_codes"]; ok {
codes := sortIntInterfaceSlice(v.([]interface{}))
for _, w := range codes {
buf.WriteString(fmt.Sprintf("%d-", w))
}
}
return hashcode.String(buf.String())
}

func expandCustomHeaders(s *schema.Set) *cloudfront.CustomHeaders {
qty := 0
items := []*cloudfront.OriginCustomHeader{}
Expand Down
83 changes: 83 additions & 0 deletions aws/cloudfront_distribution_configuration_structure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,42 @@ func multiOriginConf() *schema.Set {
return schema.NewSet(originHash, []interface{}{originWithCustomConf(), originWithS3Conf()})
}

func orderedMemberConf() map[string]interface{} {
return map[string]interface{}{
"ordered_origin_group_member": []interface{}{map[string]interface{}{
"origin_id": "S3failover",
}, map[string]interface{}{
"origin_id": "S3origin",
}},
}
}

func originGroupMembers() *schema.Set {
return schema.NewSet(membersHash, []interface{}{orderedMemberConf()})
}

func failoverStatusCodes() map[string]interface{} {
return map[string]interface{}{
"status_codes": []interface{}{503, 504},
}
}

func failoverCriteriaConf() *schema.Set {
return schema.NewSet(failoverCriteriaHash, []interface{}{failoverStatusCodes()})
}

func originGroupConf() map[string]interface{} {
return map[string]interface{}{
"origin_id": "groupS3",
"failover_criteria": failoverCriteriaConf(),
"members": originGroupMembers(),
}
}

func originGroupsConf() *schema.Set {
return schema.NewSet(originGroupHash, []interface{}{originGroupConf()})
}

func geoRestrictionWhitelistConf() map[string]interface{} {
return map[string]interface{}{
"restriction_type": "whitelist",
Expand Down Expand Up @@ -540,6 +576,53 @@ func TestCloudFrontStructure_flattenOrigins(t *testing.T) {
}
}

func TestCloudFrontStructure_expandOriginGroups(t *testing.T) {
in := originGroupsConf()
groups := expandOriginGroups(in)

if *groups.Quantity != 1 {
t.Fatalf("Expected origin group quantity to be %v, got %v", 1, *groups.Quantity)
}
originGroup := groups.Items[0]
if *originGroup.Id != "groupS3" {
t.Fatalf("Expected origin group id to be %v, got %v", "groupS3", *originGroup.Id)
}
if *originGroup.FailoverCriteria.StatusCodes.Quantity != 2 {
t.Fatalf("Expected 2 origin group members, got %v", *originGroup.FailoverCriteria.StatusCodes.Quantity)
barrytam20 marked this conversation as resolved.
Show resolved Hide resolved
}
statusCodes := originGroup.FailoverCriteria.StatusCodes.Items
for _, code := range statusCodes {
if *code != 503 && *code != 504 {
t.Fatalf("Expected origin group failover status code to either 503 or 504 got %v", *code)
}
}

if *originGroup.Members.Quantity > 2 {
t.Fatalf("Expected origin group member quantity to be 2, got %v", *originGroup.Members.Quantity)
}

members := originGroup.Members.Items
if len(members) > 2 {
t.Fatalf("Expected 2 origin group members, got %v", len(members))
}
for _, member := range members {
if *member.OriginId != "S3failover" && *member.OriginId != "S3origin" {
t.Fatalf("Expected origin group member to either S3failover or s3origin got %v", *member.OriginId)
}
}
}

func TestCloudFrontStructure_flattenOriginGroups(t *testing.T) {
in := originGroupsConf()
groups := expandOriginGroups(in)
out := flattenOriginGroups(groups)
diff := in.Difference(out)

if len(diff.List()) > 0 {
t.Fatalf("Expected out to be %v, got %v, diff: %v", in, out, diff)
}
}

func TestCloudFrontStructure_expandOrigin(t *testing.T) {
data := originWithCustomConf()
or := expandOrigin(data)
Expand Down
50 changes: 50 additions & 0 deletions aws/resource_aws_cloudfront_distribution.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,56 @@ func resourceAwsCloudFrontDistribution() *schema.Resource {
},
},
},
"origin_group": {
Type: schema.TypeSet,
Optional: true,
Set: originGroupHash,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"origin_id": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.NoZeroValues,
},
"failover_criteria": {
Type: schema.TypeSet,
barrytam20 marked this conversation as resolved.
Show resolved Hide resolved
Required: true,
Set: failoverCriteriaHash,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"status_codes": {
Type: schema.TypeList,
barrytam20 marked this conversation as resolved.
Show resolved Hide resolved
Required: true,
Elem: &schema.Schema{Type: schema.TypeInt},
},
},
},
},
"members": {
barrytam20 marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeSet,
Required: true,
Set: membersHash,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"ordered_origin_group_member": {
Type: schema.TypeList,
Required: true,
MinItems: 2,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"origin_id": {
Type: schema.TypeString,
Required: true,
},
},
},
},
},
},
},
},
},
},
"origin": {
Type: schema.TypeSet,
Required: true,
Expand Down
Loading