Skip to content

Commit

Permalink
Add ability to set Performance Mode in aws_efs_file_system. (#7791)
Browse files Browse the repository at this point in the history
* Add ability to set Performance Mode in aws_efs_file_system.

The Elastic File System (EFS) allows for setting a Performance Mode during
creation, thus enabling anyone to chose performance of the file system according
to their particular needs. This commit adds an optional "performance_mode"
attribte to the aws_efs_file_system resource so that an appropriate mode can be
set as needed.

Signed-off-by: Krzysztof Wilczynski <[email protected]>

* Add test coverage for the ValidateFunc used.

Signed-off-by: Krzysztof Wilczynski <[email protected]>

* Add "creation_token" and deprecate "reference_name".

Add the "creation_token" attribute so that the resource follows the API more
closely (as per the convention), thus deprecate the "reference_name" attribute.

Update tests and documentation accordingly.

Signed-off-by: Krzysztof Wilczynski <[email protected]>
  • Loading branch information
kwilczynski authored and stack72 committed Jul 28, 2016
1 parent 2195a67 commit 63a14be
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 49 deletions.
2 changes: 1 addition & 1 deletion builtin/providers/aws/import_aws_efs_file_system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestAccAWSEFSFileSystem_importBasic(t *testing.T) {
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"reference_name"},
ImportStateVerifyIgnore: []string{"reference_name", "creation_token"},
},
},
})
Expand Down
91 changes: 72 additions & 19 deletions builtin/providers/aws/resource_aws_efs_file_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,27 @@ func resourceAwsEfsFileSystem() *schema.Resource {
},

Schema: map[string]*schema.Schema{
"creation_token": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validateMaxLength(64),
},

"reference_name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Deprecated: "Please use attribute `creation_token' instead. This attribute might be removed in future releases.",
ConflictsWith: []string{"creation_token"},
ValidateFunc: validateReferenceName,
},

"performance_mode": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validatePerformanceModeType,
},

"tags": tagsSchema(),
Expand All @@ -38,20 +55,34 @@ func resourceAwsEfsFileSystem() *schema.Resource {
func resourceAwsEfsFileSystemCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).efsconn

referenceName := ""
if v, ok := d.GetOk("reference_name"); ok {
referenceName = v.(string) + "-"
creationToken := ""
if v, ok := d.GetOk("creation_token"); ok {
creationToken = v.(string)
} else {
if v, ok := d.GetOk("reference_name"); ok {
creationToken = resource.PrefixedUniqueId(fmt.Sprintf("%s-", v.(string)))
log.Printf("[WARN] Using deprecated `reference_name' attribute.")
} else {
creationToken = resource.UniqueId()
}
}
token := referenceName + resource.UniqueId()
fs, err := conn.CreateFileSystem(&efs.CreateFileSystemInput{
CreationToken: aws.String(token),
})

createOpts := &efs.CreateFileSystemInput{
CreationToken: aws.String(creationToken),
}

if v, ok := d.GetOk("performance_mode"); ok {
createOpts.PerformanceMode = aws.String(v.(string))
}

log.Printf("[DEBUG] EFS file system create options: %#v", *createOpts)
fs, err := conn.CreateFileSystem(createOpts)
if err != nil {
return err
return fmt.Errorf("Error creating EFS file system: %s", err)
}

log.Printf("[DEBUG] Creating EFS file system: %s", *fs)
d.SetId(*fs.FileSystemId)
log.Printf("[INFO] EFS file system ID: %s", d.Id())

stateConf := &resource.StateChangeConf{
Pending: []string{"creating"},
Expand Down Expand Up @@ -82,7 +113,7 @@ func resourceAwsEfsFileSystemCreate(d *schema.ResourceData, meta interface{}) er
return fmt.Errorf("Error waiting for EFS file system (%q) to create: %q",
d.Id(), err.Error())
}
log.Printf("[DEBUG] EFS file system created: %q", *fs.FileSystemId)
log.Printf("[DEBUG] EFS file system %q created.", d.Id())

return resourceAwsEfsFileSystemUpdate(d, meta)
}
Expand All @@ -91,7 +122,8 @@ func resourceAwsEfsFileSystemUpdate(d *schema.ResourceData, meta interface{}) er
conn := meta.(*AWSClient).efsconn
err := setTagsEFS(conn, d)
if err != nil {
return err
return fmt.Errorf("Error setting EC2 tags for EFS file system (%q): %q",
d.Id(), err.Error())
}

return resourceAwsEfsFileSystemRead(d, meta)
Expand Down Expand Up @@ -119,7 +151,8 @@ func resourceAwsEfsFileSystemRead(d *schema.ResourceData, meta interface{}) erro
FileSystemId: aws.String(d.Id()),
})
if err != nil {
return err
return fmt.Errorf("Error retrieving EC2 tags for EFS file system (%q): %q",
d.Id(), err.Error())
}

d.Set("tags", tagsToMapEFS(tagsResp.Tags))
Expand All @@ -130,7 +163,7 @@ func resourceAwsEfsFileSystemRead(d *schema.ResourceData, meta interface{}) erro
func resourceAwsEfsFileSystemDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).efsconn

log.Printf("[DEBUG] Deleting EFS file system %s", d.Id())
log.Printf("[DEBUG] Deleting EFS file system: %s", d.Id())
_, err := conn.DeleteFileSystem(&efs.DeleteFileSystemInput{
FileSystemId: aws.String(d.Id()),
})
Expand All @@ -154,8 +187,7 @@ func resourceAwsEfsFileSystemDelete(d *schema.ResourceData, meta interface{}) er
}

fs := resp.FileSystems[0]
log.Printf("[DEBUG] current status of %q: %q",
*fs.FileSystemId, *fs.LifeCycleState)
log.Printf("[DEBUG] current status of %q: %q", *fs.FileSystemId, *fs.LifeCycleState)
return fs, *fs.LifeCycleState, nil
},
Timeout: 10 * time.Minute,
Expand All @@ -165,10 +197,31 @@ func resourceAwsEfsFileSystemDelete(d *schema.ResourceData, meta interface{}) er

_, err = stateConf.WaitForState()
if err != nil {
return err
return fmt.Errorf("Error waiting for EFS file system (%q) to delete: %q",
d.Id(), err.Error())
}

log.Printf("[DEBUG] EFS file system %q deleted.", d.Id())

return nil
}

func validateReferenceName(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
creationToken := resource.PrefixedUniqueId(fmt.Sprintf("%s-", value))
if len(creationToken) > 64 {
errors = append(errors, fmt.Errorf(
"%q cannot take the Creation Token over the limit of 64 characters: %q", k, value))
}
return
}

func validatePerformanceModeType(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if value != "generalPurpose" && value != "maxIO" {
errors = append(errors, fmt.Errorf(
"%q contains an invalid Performance Mode %q. Valid modes are either %q or %q",
k, value, "generalPurpose", "maxIO"))
}
return
}
160 changes: 151 additions & 9 deletions builtin/providers/aws/resource_aws_efs_file_system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,71 @@ import (
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/efs"

"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func TestResourceAWSEFSReferenceName_validation(t *testing.T) {
var value string
var errors []error

value = acctest.RandString(128)
_, errors = validateReferenceName(value, "reference_name")
if len(errors) == 0 {
t.Fatalf("Expected to trigger a validation error")
}

value = acctest.RandString(32)
_, errors = validateReferenceName(value, "reference_name")
if len(errors) != 0 {
t.Fatalf("Expected to trigger a validation error")
}
}

func TestResourceAWSEFSPerformanceMode_validation(t *testing.T) {
type testCase struct {
Value string
ErrCount int
}

invalidCases := []testCase{
{
Value: "garrusVakarian",
ErrCount: 1,
},
{
Value: acctest.RandString(80),
ErrCount: 1,
},
}

for _, tc := range invalidCases {
_, errors := validatePerformanceModeType(tc.Value, "performance_mode")
if len(errors) != tc.ErrCount {
t.Fatalf("Expected to trigger a validation error")
}
}

validCases := []testCase{
{
Value: "generalPurpose",
ErrCount: 0,
},
{
Value: "maxIO",
ErrCount: 0,
},
}

for _, tc := range validCases {
_, errors := validatePerformanceModeType(tc.Value, "aws_efs_file_system")
if len(errors) != tc.ErrCount {
t.Fatalf("Expected not to trigger a validation error")
}
}
}

func TestAccAWSEFSFileSystem_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand All @@ -25,6 +86,10 @@ func TestAccAWSEFSFileSystem_basic(t *testing.T) {
testAccCheckEfsFileSystem(
"aws_efs_file_system.foo",
),
testAccCheckEfsFileSystemPerformanceMode(
"aws_efs_file_system.foo",
"generalPurpose",
),
),
},
resource.TestStep{
Expand All @@ -33,6 +98,10 @@ func TestAccAWSEFSFileSystem_basic(t *testing.T) {
testAccCheckEfsFileSystem(
"aws_efs_file_system.foo-with-tags",
),
testAccCheckEfsFileSystemPerformanceMode(
"aws_efs_file_system.foo-with-tags",
"generalPurpose",
),
testAccCheckEfsFileSystemTags(
"aws_efs_file_system.foo-with-tags",
map[string]string{
Expand All @@ -42,6 +111,22 @@ func TestAccAWSEFSFileSystem_basic(t *testing.T) {
),
),
},
resource.TestStep{
Config: testAccAWSEFSFileSystemConfigWithPerformanceMode,
Check: resource.ComposeTestCheckFunc(
testAccCheckEfsFileSystem(
"aws_efs_file_system.foo-with-performance-mode",
),
testAccCheckEfsCreationToken(
"aws_efs_file_system.foo-with-performance-mode",
"supercalifragilisticexpialidocious",
),
testAccCheckEfsFileSystemPerformanceMode(
"aws_efs_file_system.foo-with-performance-mode",
"maxIO",
),
),
},
},
})
}
Expand Down Expand Up @@ -82,14 +167,9 @@ func testAccCheckEfsFileSystem(resourceID string) resource.TestCheckFunc {
return fmt.Errorf("No ID is set")
}

fs, ok := s.RootModule().Resources[resourceID]
if !ok {
return fmt.Errorf("Not found: %s", resourceID)
}

conn := testAccProvider.Meta().(*AWSClient).efsconn
_, err := conn.DescribeFileSystems(&efs.DescribeFileSystemsInput{
FileSystemId: aws.String(fs.Primary.ID),
FileSystemId: aws.String(rs.Primary.ID),
})

if err != nil {
Expand All @@ -100,7 +180,7 @@ func testAccCheckEfsFileSystem(resourceID string) resource.TestCheckFunc {
}
}

func testAccCheckEfsFileSystemTags(resourceID string, expectedTags map[string]string) resource.TestCheckFunc {
func testAccCheckEfsCreationToken(resourceID string, expectedToken string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resourceID]
if !ok {
Expand All @@ -111,14 +191,39 @@ func testAccCheckEfsFileSystemTags(resourceID string, expectedTags map[string]st
return fmt.Errorf("No ID is set")
}

fs, ok := s.RootModule().Resources[resourceID]
conn := testAccProvider.Meta().(*AWSClient).efsconn
resp, err := conn.DescribeFileSystems(&efs.DescribeFileSystemsInput{
FileSystemId: aws.String(rs.Primary.ID),
})

fs := resp.FileSystems[0]
if *fs.CreationToken != expectedToken {
return fmt.Errorf("Creation Token mismatch.\nExpected: %s\nGiven: %v",
expectedToken, *fs.CreationToken)
}

if err != nil {
return err
}

return nil
}
}

func testAccCheckEfsFileSystemTags(resourceID string, expectedTags map[string]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.DescribeTags(&efs.DescribeTagsInput{
FileSystemId: aws.String(fs.Primary.ID),
FileSystemId: aws.String(rs.Primary.ID),
})

if !reflect.DeepEqual(expectedTags, tagsToMapEFS(resp.Tags)) {
Expand All @@ -134,6 +239,36 @@ func testAccCheckEfsFileSystemTags(resourceID string, expectedTags map[string]st
}
}

func testAccCheckEfsFileSystemPerformanceMode(resourceID string, expectedMode 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),
})

fs := resp.FileSystems[0]
if *fs.PerformanceMode != expectedMode {
return fmt.Errorf("Performance Mode mismatch.\nExpected: %s\nGiven: %v",
expectedMode, *fs.PerformanceMode)
}

if err != nil {
return err
}

return nil
}
}

const testAccAWSEFSFileSystemConfig = `
resource "aws_efs_file_system" "foo" {
reference_name = "radeksimko"
Expand All @@ -149,3 +284,10 @@ resource "aws_efs_file_system" "foo-with-tags" {
}
}
`

const testAccAWSEFSFileSystemConfigWithPerformanceMode = `
resource "aws_efs_file_system" "foo-with-performance-mode" {
creation_token = "supercalifragilisticexpialidocious"
performance_mode = "maxIO"
}
`
Loading

0 comments on commit 63a14be

Please sign in to comment.