diff --git a/aws/provider.go b/aws/provider.go index d91222e54305..c1912d77a4aa 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -587,6 +587,7 @@ func Provider() terraform.ResourceProvider { "aws_ssm_resource_data_sync": resourceAwsSsmResourceDataSync(), "aws_storagegateway_gateway": resourceAwsStorageGatewayGateway(), "aws_storagegateway_nfs_file_share": resourceAwsStorageGatewayNfsFileShare(), + "aws_storagegateway_upload_buffer": resourceAwsStorageGatewayUploadBuffer(), "aws_storagegateway_working_storage": resourceAwsStorageGatewayWorkingStorage(), "aws_spot_datafeed_subscription": resourceAwsSpotDataFeedSubscription(), "aws_spot_instance_request": resourceAwsSpotInstanceRequest(), diff --git a/aws/resource_aws_storagegateway_upload_buffer.go b/aws/resource_aws_storagegateway_upload_buffer.go new file mode 100644 index 000000000000..4864c3f65679 --- /dev/null +++ b/aws/resource_aws_storagegateway_upload_buffer.go @@ -0,0 +1,131 @@ +package aws + +import ( + "fmt" + "log" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go/service/storagegateway" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsStorageGatewayUploadBuffer() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsStorageGatewayUploadBufferCreate, + Read: resourceAwsStorageGatewayUploadBufferRead, + Delete: schema.Noop, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "disk_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "gateway_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateArn, + }, + }, + } +} + +func resourceAwsStorageGatewayUploadBufferCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).storagegatewayconn + + diskID := d.Get("disk_id").(string) + gatewayARN := d.Get("gateway_arn").(string) + + input := &storagegateway.AddUploadBufferInput{ + DiskIds: []*string{aws.String(diskID)}, + GatewayARN: aws.String(gatewayARN), + } + + log.Printf("[DEBUG] Adding Storage Gateway upload buffer: %s", input) + _, err := conn.AddUploadBuffer(input) + if err != nil { + return fmt.Errorf("error adding Storage Gateway upload buffer: %s", err) + } + + d.SetId(fmt.Sprintf("%s:%s", gatewayARN, diskID)) + + return resourceAwsStorageGatewayUploadBufferRead(d, meta) +} + +func resourceAwsStorageGatewayUploadBufferRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).storagegatewayconn + + gatewayARN, diskID, err := decodeStorageGatewayUploadBufferID(d.Id()) + if err != nil { + return err + } + + input := &storagegateway.DescribeUploadBufferInput{ + GatewayARN: aws.String(gatewayARN), + } + + log.Printf("[DEBUG] Reading Storage Gateway upload buffer: %s", input) + output, err := conn.DescribeUploadBuffer(input) + if err != nil { + if isAWSErrStorageGatewayGatewayNotFound(err) { + log.Printf("[WARN] Storage Gateway upload buffer %q not found - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("error reading Storage Gateway upload buffer: %s", err) + } + + if output == nil || len(output.DiskIds) == 0 { + log.Printf("[WARN] Storage Gateway upload buffer %q not found - removing from state", d.Id()) + d.SetId("") + return nil + } + + found := false + for _, existingDiskID := range output.DiskIds { + if aws.StringValue(existingDiskID) == diskID { + found = true + break + } + } + + if !found { + log.Printf("[WARN] Storage Gateway upload buffer %q not found - removing from state", d.Id()) + d.SetId("") + return nil + } + + d.Set("disk_id", diskID) + d.Set("gateway_arn", gatewayARN) + + return nil +} + +func decodeStorageGatewayUploadBufferID(id string) (string, string, error) { + // id = arn:aws:storagegateway:us-east-1:123456789012:gateway/sgw-12345678:pci-0000:03:00.0-scsi-0:0:0:0 + idFormatErr := fmt.Errorf("expected ID in form of GatewayARN:DiskId, received: %s", id) + gatewayARNAndDisk, err := arn.Parse(id) + if err != nil { + return "", "", idFormatErr + } + // gatewayARNAndDisk.Resource = gateway/sgw-12345678:pci-0000:03:00.0-scsi-0:0:0:0 + resourceParts := strings.SplitN(gatewayARNAndDisk.Resource, ":", 2) + if len(resourceParts) != 2 { + return "", "", idFormatErr + } + // resourceParts = ["gateway/sgw-12345678", "pci-0000:03:00.0-scsi-0:0:0:0"] + gatewayARN := &arn.ARN{ + AccountID: gatewayARNAndDisk.AccountID, + Partition: gatewayARNAndDisk.Partition, + Region: gatewayARNAndDisk.Region, + Service: gatewayARNAndDisk.Service, + Resource: resourceParts[0], + } + return gatewayARN.String(), resourceParts[1], nil +} diff --git a/aws/resource_aws_storagegateway_upload_buffer_test.go b/aws/resource_aws_storagegateway_upload_buffer_test.go new file mode 100644 index 000000000000..9af32c832144 --- /dev/null +++ b/aws/resource_aws_storagegateway_upload_buffer_test.go @@ -0,0 +1,165 @@ +package aws + +import ( + "fmt" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/storagegateway" + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestDecodeStorageGatewayUploadBufferID(t *testing.T) { + var testCases = []struct { + Input string + ExpectedGatewayARN string + ExpectedDiskID string + ErrCount int + }{ + { + Input: "arn:aws:storagegateway:us-east-1:123456789012:gateway/sgw-12345678:pci-0000:03:00.0-scsi-0:0:0:0", + ExpectedGatewayARN: "arn:aws:storagegateway:us-east-1:123456789012:gateway/sgw-12345678", + ExpectedDiskID: "pci-0000:03:00.0-scsi-0:0:0:0", + ErrCount: 0, + }, + { + Input: "sgw-12345678:pci-0000:03:00.0-scsi-0:0:0:0", + ErrCount: 1, + }, + { + Input: "example:pci-0000:03:00.0-scsi-0:0:0:0", + ErrCount: 1, + }, + { + Input: "arn:aws:storagegateway:us-east-1:123456789012:gateway/sgw-12345678", + ErrCount: 1, + }, + { + Input: "pci-0000:03:00.0-scsi-0:0:0:0", + ErrCount: 1, + }, + { + Input: "gateway/sgw-12345678", + ErrCount: 1, + }, + { + Input: "sgw-12345678", + ErrCount: 1, + }, + } + + for _, tc := range testCases { + gatewayARN, diskID, err := decodeStorageGatewayUploadBufferID(tc.Input) + if tc.ErrCount == 0 && err != nil { + t.Fatalf("expected %q not to trigger an error, received: %s", tc.Input, err) + } + if tc.ErrCount > 0 && err == nil { + t.Fatalf("expected %q to trigger an error", tc.Input) + } + if gatewayARN != tc.ExpectedGatewayARN { + t.Fatalf("expected %q to return Gateway ARN %q, received: %s", tc.Input, tc.ExpectedGatewayARN, gatewayARN) + } + if diskID != tc.ExpectedDiskID { + t.Fatalf("expected %q to return Disk ID %q, received: %s", tc.Input, tc.ExpectedDiskID, diskID) + } + } +} + +func TestAccAWSStorageGatewayUploadBuffer_Basic(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_storagegateway_upload_buffer.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + // Storage Gateway API does not support removing upload buffers + // CheckDestroy: testAccCheckAWSStorageGatewayUploadBufferDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSStorageGatewayUploadBufferConfig_Basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSStorageGatewayUploadBufferExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "disk_id"), + resource.TestMatchResourceAttr(resourceName, "gateway_arn", regexp.MustCompile(`^arn:[^:]+:storagegateway:[^:]+:[^:]+:gateway/sgw-.+$`)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckAWSStorageGatewayUploadBufferExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + conn := testAccProvider.Meta().(*AWSClient).storagegatewayconn + + gatewayARN, diskID, err := decodeStorageGatewayUploadBufferID(rs.Primary.ID) + if err != nil { + return err + } + + input := &storagegateway.DescribeUploadBufferInput{ + GatewayARN: aws.String(gatewayARN), + } + + output, err := conn.DescribeUploadBuffer(input) + + if err != nil { + return fmt.Errorf("error reading Storage Gateway upload buffer: %s", err) + } + + if output == nil || len(output.DiskIds) == 0 { + return fmt.Errorf("Storage Gateway upload buffer %q not found", rs.Primary.ID) + } + + for _, existingDiskID := range output.DiskIds { + if aws.StringValue(existingDiskID) == diskID { + return nil + } + } + + return fmt.Errorf("Storage Gateway upload buffer %q not found", rs.Primary.ID) + } +} + +func testAccAWSStorageGatewayUploadBufferConfig_Basic(rName string) string { + return testAccAWSStorageGatewayGatewayConfig_GatewayType_Stored(rName) + fmt.Sprintf(` +resource "aws_ebs_volume" "test" { + availability_zone = "${aws_instance.test.availability_zone}" + size = "10" + type = "gp2" + + tags { + Name = %q + } +} + +resource "aws_volume_attachment" "test" { + device_name = "/dev/xvdc" + force_detach = true + instance_id = "${aws_instance.test.id}" + volume_id = "${aws_ebs_volume.test.id}" +} + +data "aws_storagegateway_local_disk" "test" { + disk_path = "${aws_volume_attachment.test.device_name}" + gateway_arn = "${aws_storagegateway_gateway.test.arn}" +} + +resource "aws_storagegateway_upload_buffer" "test" { + disk_id = "${data.aws_storagegateway_local_disk.test.id}" + gateway_arn = "${aws_storagegateway_gateway.test.arn}" +} +`, rName) +} diff --git a/website/aws.erb b/website/aws.erb index ffadd674dbca..b01383b131b7 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -2148,6 +2148,10 @@ aws_storagegateway_nfs_file_share + > + aws_storagegateway_upload_buffer + + > aws_storagegateway_working_storage diff --git a/website/docs/r/storagegateway_upload_buffer.html.markdown b/website/docs/r/storagegateway_upload_buffer.html.markdown new file mode 100644 index 000000000000..d74349722950 --- /dev/null +++ b/website/docs/r/storagegateway_upload_buffer.html.markdown @@ -0,0 +1,43 @@ +--- +layout: "aws" +page_title: "AWS: aws_storagegateway_upload_buffer" +sidebar_current: "docs-aws-resource-storagegateway-upload-buffer" +description: |- + Manages an AWS Storage Gateway upload buffer +--- + +# aws_storagegateway_upload_buffer + +Manages an AWS Storage Gateway upload buffer. + +~> **NOTE:** The Storage Gateway API provides no method to remove an upload buffer disk. Destroying this Terraform resource does not perform any Storage Gateway actions. + +## Example Usage + +```hcl +resource "aws_storagegateway_upload_buffer" "example" { + disk_id = "${data.aws_storagegateway_local_disk.example.id}" + gateway_arn = "${aws_storagegateway_gateway.example.arn}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `disk_id` - (Required) Local disk identifier. For example, `pci-0000:03:00.0-scsi-0:0:0:0`. +* `gateway_arn` - (Required) The Amazon Resource Name (ARN) of the gateway. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - Combined gateway Amazon Resource Name (ARN) and local disk identifier. + +## Import + +`aws_storagegateway_upload_buffer` can be imported by using the gateway Amazon Resource Name (ARN) and local disk identifier separated with a colon (`:`), e.g. + +``` +$ terraform import aws_storagegateway_upload_buffer.example arn:aws:storagegateway:us-east-1:123456789012:gateway/sgw-12345678:pci-0000:03:00.0-scsi-0:0:0:0 +```