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

adding lifecycle_policy config block to efs_file_system (fixes #7623) #9636

Merged
merged 1 commit into from
Aug 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions aws/resource_aws_efs_file_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func resourceAwsEfsFileSystem() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},

"creation_token": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -93,6 +94,26 @@ func resourceAwsEfsFileSystem() *schema.Resource {
efs.ThroughputModeProvisioned,
}, false),
},

"lifecycle_policy": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"transition_to_ia": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
efs.TransitionToIARulesAfter14Days,
efs.TransitionToIARulesAfter30Days,
efs.TransitionToIARulesAfter60Days,
efs.TransitionToIARulesAfter90Days,
}, false),
},
},
},
},
},
}
}
Expand Down Expand Up @@ -160,6 +181,18 @@ func resourceAwsEfsFileSystemCreate(d *schema.ResourceData, meta interface{}) er
}
log.Printf("[DEBUG] EFS file system %q created.", d.Id())

_, hasLifecyclePolicy := d.GetOk("lifecycle_policy")
if hasLifecyclePolicy {
_, err := conn.PutLifecycleConfiguration(&efs.PutLifecycleConfigurationInput{
FileSystemId: aws.String(d.Id()),
LifecyclePolicies: resourceAwsEfsFileSystemLifecyclePolicy(d.Get("lifecycle_policy").([]interface{})),
})
if err != nil {
return fmt.Errorf("Error creating lifecycle policy for EFS file system %q: %s",
d.Id(), err.Error())
}
}

err = setTagsEFS(conn, d)
if err != nil {
return fmt.Errorf("error setting tags for EFS file system (%q): %s", d.Id(), err)
Expand Down Expand Up @@ -203,6 +236,17 @@ func resourceAwsEfsFileSystemUpdate(d *schema.ResourceData, meta interface{}) er
}
}

if d.HasChange("lifecycle_policy") {
_, err := conn.PutLifecycleConfiguration(&efs.PutLifecycleConfigurationInput{
FileSystemId: aws.String(d.Id()),
LifecyclePolicies: resourceAwsEfsFileSystemLifecyclePolicy(d.Get("lifecycle_policy").([]interface{})),
})
if err != nil {
return fmt.Errorf("Error updating lifecycle policy for EFS file system %q: %s",
d.Id(), err.Error())
}
}

if d.HasChange("tags") {
err := setTagsEFS(conn, d)
if err != nil {
Expand Down Expand Up @@ -297,6 +341,17 @@ func resourceAwsEfsFileSystemRead(d *schema.ResourceData, meta interface{}) erro
return fmt.Errorf("error setting dns_name: %s", err)
}

res, err := conn.DescribeLifecycleConfiguration(&efs.DescribeLifecycleConfigurationInput{
FileSystemId: fs.FileSystemId,
})
if err != nil {
return fmt.Errorf("Error describing lifecycle configuration for EFS file system (%s): %s",
aws.StringValue(fs.FileSystemId), err)
}
if err := resourceAwsEfsFileSystemSetLifecyclePolicy(d, res.LifecyclePolicies); err != nil {
return err
}

return nil
}

Expand Down Expand Up @@ -379,3 +434,37 @@ func resourceEfsFileSystemCreateUpdateRefreshFunc(id string, conn *efs.EFS) reso
return fs, state, nil
}
}

func resourceAwsEfsFileSystemSetLifecyclePolicy(d *schema.ResourceData, lp []*efs.LifecyclePolicy) error {
log.Printf("[DEBUG] lifecycle pols: %s %d", lp, len(lp))
if len(lp) == 0 {
d.Set("lifecycle_policy", nil)
return nil
}
newLP := make([]*map[string]interface{}, len(lp))

for i := 0; i < len(lp); i++ {
config := lp[i]
data := make(map[string]interface{})
newLP[i] = &data
if config.TransitionToIA != nil {
data["transition_to_ia"] = *config.TransitionToIA
}
log.Printf("[DEBUG] lp: %s", data)
}

if err := d.Set("lifecycle_policy", newLP); err != nil {
return fmt.Errorf("error setting lifecycle_policy: %s", err)
}
return nil
}

func resourceAwsEfsFileSystemLifecyclePolicy(lcPol []interface{}) []*efs.LifecyclePolicy {
result := make([]*efs.LifecyclePolicy, len(lcPol))

for i := 0; i < len(lcPol); i++ {
lp := lcPol[i].(map[string]interface{})
result[i] = &efs.LifecyclePolicy{TransitionToIA: aws.String(lp["transition_to_ia"].(string))}
}
return result
}
176 changes: 175 additions & 1 deletion aws/resource_aws_efs_file_system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ func TestAccAWSEFSFileSystem_importBasic(t *testing.T) {
{
Config: testAccAWSEFSFileSystemConfigWithTags(rInt),
},

{
ResourceName: resourceName,
ImportState: true,
Expand Down Expand Up @@ -261,6 +260,123 @@ func TestAccAWSEFSFileSystem_ThroughputMode(t *testing.T) {
})
}

func TestAccAWSEFSFileSystem_lifecyclePolicy(t *testing.T) {
resourceName := "aws_efs_file_system.foo-with-lifecycle-policy"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckEfsFileSystemDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSEFSFileSystemConfigWithLifecyclePolicy(
"transition_to_ia",
"invalid_value",
),
ExpectError: regexp.MustCompile(`got invalid_value`),
},
{
Config: testAccAWSEFSFileSystemConfigWithLifecyclePolicy(
"transition_to_ia",
efs.TransitionToIARulesAfter30Days,
),
Check: resource.ComposeTestCheckFunc(
testAccCheckEfsFileSystem(resourceName),
testAccCheckEfsFileSystemLifecyclePolicy(resourceName, "badExpectation"),
),
ExpectError: regexp.MustCompile(`Expected: badExpectation`),
},
{
Config: testAccAWSEFSFileSystemConfigWithLifecyclePolicy(
"transition_to_ia",
efs.TransitionToIARulesAfter30Days,
),
Check: resource.ComposeTestCheckFunc(
testAccCheckEfsFileSystem(resourceName),
testAccCheckEfsFileSystemLifecyclePolicy(resourceName, efs.TransitionToIARulesAfter30Days),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccAWSEFSFileSystem_lifecyclePolicy_update(t *testing.T) {
resourceName := "aws_efs_file_system.foo-with-lifecycle-policy"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckEfsFileSystemDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSEFSFileSystemConfigWithLifecyclePolicy(
"transition_to_ia",
efs.TransitionToIARulesAfter30Days,
),
Check: resource.ComposeTestCheckFunc(
testAccCheckEfsFileSystem(resourceName),
testAccCheckEfsFileSystemLifecyclePolicy(resourceName, efs.TransitionToIARulesAfter30Days),
),
},
{
Config: testAccAWSEFSFileSystemConfigWithLifecyclePolicy(
"transition_to_ia",
efs.TransitionToIARulesAfter90Days,
),
Check: resource.ComposeTestCheckFunc(
testAccCheckEfsFileSystem(resourceName),
testAccCheckEfsFileSystemLifecyclePolicy(resourceName, efs.TransitionToIARulesAfter90Days),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccAWSEFSFileSystem_lifecyclePolicy_removal(t *testing.T) {
resourceName := "aws_efs_file_system.foo-with-lifecycle-policy"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckEfsFileSystemDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSEFSFileSystemConfigWithLifecyclePolicy(
"transition_to_ia",
efs.TransitionToIARulesAfter14Days,
),
Check: resource.ComposeTestCheckFunc(
testAccCheckEfsFileSystem(resourceName),
testAccCheckEfsFileSystemLifecyclePolicy(resourceName, efs.TransitionToIARulesAfter14Days),
),
},
{
Config: testAccAWSEFSFileSystemConfigRemovedLifecyclePolicy,
Check: resource.ComposeTestCheckFunc(
testAccCheckEfsFileSystem(resourceName),
testAccCheckEfsFileSystemLifecyclePolicy(resourceName, efs.TransitionToIARulesAfter14Days),
),
ExpectError: regexp.MustCompile(fmt.Sprintf(`Expected: %s`, efs.TransitionToIARulesAfter14Days)),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccCheckEfsFileSystemDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).efsconn
for _, rs := range s.RootModule().Resources {
Expand Down Expand Up @@ -391,6 +507,50 @@ func testAccCheckEfsFileSystemPerformanceMode(resourceID string, expectedMode st
}
}

func testAccCheckEfsFileSystemLifecyclePolicy(resourceID string, expectedVal string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resourceID]
if !ok {
return fmt.Errorf("Not found: %s", resourceID)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}

conn := testAccProvider.Meta().(*AWSClient).efsconn
resp, err := conn.DescribeFileSystems(&efs.DescribeFileSystemsInput{
FileSystemId: aws.String(rs.Primary.ID),
})
if err != nil {
return fmt.Errorf("Error describing EFS file systems: %s", err.Error())
}

fs := resp.FileSystems[0]

res, err := conn.DescribeLifecycleConfiguration(&efs.DescribeLifecycleConfigurationInput{
FileSystemId: fs.FileSystemId,
})
if err != nil {
return fmt.Errorf("Error describing lifecycle policy for EFS file system (%s): %s",
aws.StringValue(fs.FileSystemId), err.Error())
}
lp := res.LifecyclePolicies

newLP := make([]*map[string]interface{}, len(lp))

for i := 0; i < len(lp); i++ {
config := lp[i]
data := make(map[string]interface{})
newLP[i] = &data
if *config.TransitionToIA == expectedVal {
return nil
}
}
return fmt.Errorf("Lifecycle Policy mismatch.\nExpected: %s\nFound: %+v", expectedVal, lp)
}
}

const testAccAWSEFSFileSystemConfig = `
resource "aws_efs_file_system" "foo" {
creation_token = "radeksimko"
Expand Down Expand Up @@ -477,3 +637,17 @@ resource "aws_efs_file_system" "test" {
}
`, provisionedThroughputInMibps)
}

func testAccAWSEFSFileSystemConfigWithLifecyclePolicy(lpName string, lpVal string) string {
return fmt.Sprintf(`
resource "aws_efs_file_system" "foo-with-lifecycle-policy" {
lifecycle_policy {
%s = %q
}
}
`, lpName, lpVal)
}

const testAccAWSEFSFileSystemConfigRemovedLifecyclePolicy = `
resource "aws_efs_file_system" "foo-with-lifecycle-policy" {}
`
20 changes: 20 additions & 0 deletions website/docs/r/efs_file_system.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Provides an Elastic File System (EFS) resource.

## Example Usage

### EFS File System w/ tags

```hcl
resource "aws_efs_file_system" "foo" {
creation_token = "my-product"
Expand All @@ -22,6 +24,18 @@ resource "aws_efs_file_system" "foo" {
}
```

### Using lifecycle policy

```hcl
resource "aws_efs_file_system" "foo_with_lifecyle_policy" {
creation_token = "my-product"

lifecycle_policy {
transition_to_ia = "AFTER_30_DAYS"
}
}
```

## Argument Reference

The following arguments are supported:
Expand All @@ -32,11 +46,17 @@ system creation. By default generated by Terraform. See [Elastic File System]
(http://docs.aws.amazon.com/efs/latest/ug/) user guide for more information.
* `encrypted` - (Optional) If true, the disk will be encrypted.
* `kms_key_id` - (Optional) The ARN for the KMS encryption key. When specifying kms_key_id, encrypted needs to be set to true.
* `lifecycle_policy` - (Optional) A file system [lifecycle policy](https://docs.aws.amazon.com/efs/latest/ug/API_LifecyclePolicy.html) object (documented below).
* `performance_mode` - (Optional) The file system performance mode. Can be either `"generalPurpose"` or `"maxIO"` (Default: `"generalPurpose"`).
* `provisioned_throughput_in_mibps` - (Optional) The throughput, measured in MiB/s, that you want to provision for the file system. Only applicable with `throughput_mode` set to `provisioned`.
* `tags` - (Optional) A mapping of tags to assign to the file system.
* `throughput_mode` - (Optional) Throughput mode for the file system. Defaults to `bursting`. Valid values: `bursting`, `provisioned`. When using `provisioned`, also set `provisioned_throughput_in_mibps`.

### Lifecycle Policy Arguments
For **lifecycle_policy** the following attributes are supported:

* `transition_to_ia` - (Optional) Indicates how long it takes to transition files to the IA storage class. Valid values: `AFTER_14_DAYS`, `AFTER_30_DAYS`, `AFTER_60_DAYS`, or `AFTER_90_DAYS`.

## Attributes Reference

In addition to all arguments above, the following attributes are exported:
Expand Down