-
Notifications
You must be signed in to change notification settings - Fork 9.2k
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
data_source/aws_ecr_lifecycle_policy_document: adding new data source for ECR #6133
Changes from all commits
08da208
8d96c00
c3c906d
d3995af
819b1d6
0f1ad18
101ef75
be70303
22734c7
1a4f6cc
8fc0627
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
package aws | ||
|
||
import ( | ||
"encoding/json" | ||
"strconv" | ||
|
||
"github.com/hashicorp/terraform/helper/hashcode" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/hashicorp/terraform/helper/validation" | ||
) | ||
|
||
type EcrLifecyclePolicyDoc struct { | ||
Rules []*EcrLifecyclePolicyStatement `json:"rules"` | ||
} | ||
|
||
type EcrLifecyclePolicyStatement struct { | ||
RulePriority int `json:"rulePriority,omitempty"` | ||
Description string `json:"description,omitempty"` | ||
Selection EcrLifecyclePolicyStatementSelectionSet `json:"selection,omitempty"` | ||
Action EcrLifecyclePolicyAction `json:"action"` | ||
} | ||
|
||
type EcrLifecyclePolicySelection struct { | ||
TagStatus string `json:"tagStatus,omitempty"` | ||
TagPrefixList []interface{} `json:"tagPrefixList,omitempty"` | ||
CountType string `json:"countType,omitempty"` | ||
CountUnit string `json:"countUnit,omitempty"` | ||
CountNumber int `json:"countNumber,omitempty"` | ||
} | ||
|
||
type EcrLifecyclePolicyAction struct { | ||
Type string `json:"type"` | ||
} | ||
|
||
type EcrLifecyclePolicyStatementSelectionSet EcrLifecyclePolicySelection | ||
|
||
func dataSourceAwsEcrLifecyclePolicyDocument() *schema.Resource { | ||
|
||
return &schema.Resource{ | ||
Read: dataSourceAwsEcrLifecyclePolicyDocumentRead, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"rule": { | ||
Type: schema.TypeList, | ||
Required: true, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"priority": { | ||
Type: schema.TypeInt, | ||
Required: true, | ||
}, | ||
"description": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
"selection": { | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"tag_status": { | ||
Type: schema.TypeString, | ||
Required: false, | ||
Optional: true, | ||
Default: "any", | ||
ValidateFunc: validation.StringInSlice([]string{"tagged", "untagged", "any"}, false), | ||
}, | ||
"tag_prefix_list": { | ||
Type: schema.TypeList, | ||
Required: false, | ||
Optional: true, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
}, | ||
"count_type": { | ||
Type: schema.TypeString, | ||
Required: false, | ||
Optional: true, | ||
ValidateFunc: validation.StringInSlice([]string{"imageCountMoreThan", "sinceImagePushed", "any"}, false), | ||
}, | ||
"count_unit": { | ||
Type: schema.TypeString, | ||
Required: false, | ||
Optional: true, | ||
ValidateFunc: validation.StringInSlice([]string{"days"}, false), | ||
}, | ||
"count_number": { | ||
Type: schema.TypeInt, | ||
Required: false, | ||
Optional: true, | ||
}, | ||
}, | ||
}, | ||
}, | ||
"action": { | ||
Type: schema.TypeList, | ||
Required: false, | ||
Optional: true, | ||
MaxItems: 1, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"type": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Default: "expire", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
"json": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func dataSourceAwsEcrLifecyclePolicyDocumentRead(d *schema.ResourceData, meta interface{}) error { | ||
mergedDoc := &EcrLifecyclePolicyDoc{} | ||
|
||
// process the current document | ||
doc := &EcrLifecyclePolicyDoc{} | ||
|
||
var cfgStmts = d.Get("rule").([]interface{}) | ||
stmts := make([]*EcrLifecyclePolicyStatement, len(cfgStmts)) | ||
for i, stmtI := range cfgStmts { | ||
cfgStmt := stmtI.(map[string]interface{}) | ||
|
||
stmt := &EcrLifecyclePolicyStatement{ | ||
RulePriority: cfgStmt["priority"].(int), | ||
} | ||
|
||
if description, ok := cfgStmt["description"]; ok { | ||
stmt.Description = description.(string) | ||
} | ||
|
||
if selection := cfgStmt["selection"].(*schema.Set).List(); len(selection) > 0 { | ||
stmt.Selection = dataSourceAwsEcrLifecyclePolicyDocumentMakeSelection(selection) | ||
} | ||
|
||
if action := cfgStmt["action"].([]interface{}); len(action) == 0 { | ||
stmt.Action = EcrLifecyclePolicyAction{ | ||
Type: "expire", | ||
} | ||
} | ||
|
||
stmts[i] = stmt | ||
} | ||
|
||
doc.Rules = stmts | ||
|
||
// merge our current document into mergedDoc | ||
mergedDoc.Merge(doc) | ||
|
||
jsonDoc, err := json.MarshalIndent(mergedDoc, "", " ") | ||
if err != nil { | ||
// should never happen if the above code is correct | ||
return err | ||
} | ||
jsonString := string(jsonDoc) | ||
|
||
d.Set("json", jsonString) | ||
d.SetId(strconv.Itoa(hashcode.String(jsonString))) | ||
|
||
return nil | ||
} | ||
|
||
func dataSourceAwsEcrLifecyclePolicyDocumentMakeSelection(in []interface{}) EcrLifecyclePolicyStatementSelectionSet { | ||
item := in[0].(map[string]interface{}) | ||
out := EcrLifecyclePolicySelection{ | ||
TagStatus: item["tag_status"].(string), | ||
TagPrefixList: item["tag_prefix_list"].([]interface{}), | ||
CountType: item["count_type"].(string), | ||
CountUnit: item["count_unit"].(string), | ||
CountNumber: item["count_number"].(int), | ||
} | ||
return EcrLifecyclePolicyStatementSelectionSet(out) | ||
} | ||
|
||
func (self *EcrLifecyclePolicyDoc) Merge(newDoc *EcrLifecyclePolicyDoc) { | ||
// merge in newDoc's statements, overwriting any existing Sids | ||
var seen bool | ||
for _, newRule := range newDoc.Rules { | ||
if newRule.RulePriority == 0 { | ||
self.Rules = append(self.Rules, newRule) | ||
continue | ||
} | ||
seen = false | ||
for i, existingRule := range self.Rules { | ||
if existingRule.RulePriority == newRule.RulePriority { | ||
self.Rules[i] = newRule | ||
seen = true | ||
break | ||
} | ||
} | ||
if !seen { | ||
self.Rules = append(self.Rules, newRule) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
package aws | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
) | ||
|
||
func TestAccAWSDataSourceEcrLifecyclePolicyDocument_basic(t *testing.T) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nice to see additional testing that covers:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just added a couple more tests: one that omits an optional attribute ( |
||
// This really ought to be able to be a unit test rather than an | ||
// acceptance test, but just instantiating the AWS provider requires | ||
// some AWS API calls, and so this needs valid AWS credentials to work. | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccAWSEcrLifecyclePolicyDocumentConfig, | ||
Check: resource.TestCheckResourceAttr( | ||
"data.aws_ecr_lifecycle_policy_document.test", "json", | ||
testAccAWSEcrLifecyclePolicyDocumentExpectedJSON, | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccAWSDataSourceEcrLifecyclePolicyDocument_multipleRules(t *testing.T) { | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccAWSEcrLifecyclePolicyDocumentConfig_multipleRules, | ||
Check: resource.TestCheckResourceAttr( | ||
"data.aws_ecr_lifecycle_policy_document.test", "json", | ||
testAccAWSEcrLifecyclePolicyDocumentExpectedJSON_multipleRules, | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccAWSDataSourceEcrLifecyclePolicyDocument_noDesc(t *testing.T) { | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccAWSEcrLifecyclePolicyDocumentConfig_noDesc, | ||
Check: resource.TestCheckResourceAttr( | ||
"data.aws_ecr_lifecycle_policy_document.test", "json", | ||
testAccAWSEcrLifecyclePolicyDocumentExpectedJSON_noDesc, | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
var testAccAWSEcrLifecyclePolicyDocumentConfig = ` | ||
data "aws_ecr_lifecycle_policy_document" "test" { | ||
rule { | ||
priority = 1 | ||
description = "This is a test." | ||
selection = { | ||
tag_status = "tagged" | ||
tag_prefix_list = ["prod"] | ||
count_type = "imageCountMoreThan" | ||
count_number = 100 | ||
} | ||
} | ||
} | ||
` | ||
|
||
var testAccAWSEcrLifecyclePolicyDocumentExpectedJSON = `{ | ||
"rules": [ | ||
{ | ||
"rulePriority": 1, | ||
"description": "This is a test.", | ||
"selection": { | ||
"tagStatus": "tagged", | ||
"tagPrefixList": [ | ||
"prod" | ||
], | ||
"countType": "imageCountMoreThan", | ||
"countNumber": 100 | ||
}, | ||
"action": { | ||
"type": "expire" | ||
} | ||
} | ||
] | ||
}` | ||
|
||
var testAccAWSEcrLifecyclePolicyDocumentConfig_multipleRules = ` | ||
data "aws_ecr_lifecycle_policy_document" "test" { | ||
rule { | ||
priority = 1 | ||
description = "This is a test." | ||
selection = { | ||
tag_status = "tagged" | ||
tag_prefix_list = ["prod"] | ||
count_type = "imageCountMoreThan" | ||
count_number = 100 | ||
} | ||
} | ||
rule { | ||
priority = 2 | ||
description = "This is another test." | ||
selection = { | ||
tag_status = "tagged" | ||
tag_prefix_list = ["dev"] | ||
count_type = "imageCountMoreThan" | ||
count_number = 25 | ||
} | ||
} | ||
} | ||
` | ||
|
||
var testAccAWSEcrLifecyclePolicyDocumentExpectedJSON_multipleRules = `{ | ||
"rules": [ | ||
{ | ||
"rulePriority": 1, | ||
"description": "This is a test.", | ||
"selection": { | ||
"tagStatus": "tagged", | ||
"tagPrefixList": [ | ||
"prod" | ||
], | ||
"countType": "imageCountMoreThan", | ||
"countNumber": 100 | ||
}, | ||
"action": { | ||
"type": "expire" | ||
} | ||
}, | ||
{ | ||
"rulePriority": 2, | ||
"description": "This is another test.", | ||
"selection": { | ||
"tagStatus": "tagged", | ||
"tagPrefixList": [ | ||
"dev" | ||
], | ||
"countType": "imageCountMoreThan", | ||
"countNumber": 25 | ||
}, | ||
"action": { | ||
"type": "expire" | ||
} | ||
} | ||
] | ||
}` | ||
|
||
var testAccAWSEcrLifecyclePolicyDocumentConfig_noDesc = ` | ||
data "aws_ecr_lifecycle_policy_document" "test" { | ||
rule { | ||
priority = 1 | ||
selection = { | ||
tag_status = "tagged" | ||
tag_prefix_list = ["prod"] | ||
count_type = "imageCountMoreThan" | ||
count_number = 100 | ||
} | ||
} | ||
} | ||
` | ||
|
||
var testAccAWSEcrLifecyclePolicyDocumentExpectedJSON_noDesc = `{ | ||
"rules": [ | ||
{ | ||
"rulePriority": 1, | ||
"selection": { | ||
"tagStatus": "tagged", | ||
"tagPrefixList": [ | ||
"prod" | ||
], | ||
"countType": "imageCountMoreThan", | ||
"countNumber": 100 | ||
}, | ||
"action": { | ||
"type": "expire" | ||
} | ||
} | ||
] | ||
}` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Example B of Filtering All Images uses
hour
as a count unit: https://docs.aws.amazon.com/AmazonECR/latest/userguide/lifecycle_policy_examples.html#lp_example_allimages