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

r/datasync_location_object_storage #23154

Merged
merged 17 commits into from
Jan 17, 2023
3 changes: 3 additions & 0 deletions .changelog/23154.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_datasync_location_object_storage
```
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -1248,6 +1248,7 @@ func New(ctx context.Context) (*schema.Provider, error) {
"aws_datasync_location_fsx_windows_file_system": datasync.ResourceLocationFSxWindowsFileSystem(),
"aws_datasync_location_hdfs": datasync.ResourceLocationHDFS(),
"aws_datasync_location_nfs": datasync.ResourceLocationNFS(),
"aws_datasync_location_object_storage": datasync.ResourceLocationObjectStorage(),
"aws_datasync_location_s3": datasync.ResourceLocationS3(),
"aws_datasync_location_smb": datasync.ResourceLocationSMB(),
"aws_datasync_task": datasync.ResourceTask(),
Expand Down
25 changes: 25 additions & 0 deletions internal/service/datasync/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,28 @@ func FindFSxOpenZFSLocationByARN(conn *datasync.DataSync, arn string) (*datasync

return output, nil
}

func FindLocationObjectStorageByARN(conn *datasync.DataSync, arn string) (*datasync.DescribeLocationObjectStorageOutput, error) {
input := &datasync.DescribeLocationObjectStorageInput{
LocationArn: aws.String(arn),
}

output, err := conn.DescribeLocationObjectStorage(input)

if tfawserr.ErrMessageContains(err, datasync.ErrCodeInvalidRequestException, "not found") {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil {
return nil, tfresource.NewEmptyResultError(input)
}

return output, nil
}
289 changes: 289 additions & 0 deletions internal/service/datasync/location_object_storage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
package datasync

import (
"fmt"
"log"
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/datasync"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/flex"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
)

func ResourceLocationObjectStorage() *schema.Resource {
return &schema.Resource{
Create: resourceLocationObjectStorageCreate,
Read: resourceLocationObjectStorageRead,
Update: resourceLocationObjectStorageUpdate,
Delete: resourceLocationObjectStorageDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},
"access_key": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringLenBetween(8, 200),
},
"agent_arns": {
Type: schema.TypeSet,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: verify.ValidARN,
},
},
"bucket_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringLenBetween(3, 63),
},
"secret_key": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
ValidateFunc: validation.StringLenBetween(8, 200),
},
"server_certificate": {
Type: schema.TypeString,
Optional: true,
},
"server_hostname": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringLenBetween(0, 255),
},
"server_port": {
Type: schema.TypeInt,
Optional: true,
Default: 443,
ValidateFunc: validation.IsPortNumber,
},
"server_protocol": {
Type: schema.TypeString,
Optional: true,
Default: datasync.ObjectStorageServerProtocolHttps,
ValidateFunc: validation.StringInSlice(datasync.ObjectStorageServerProtocol_Values(), false),
},
"subdirectory": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringLenBetween(1, 4096),
},
"tags": tftags.TagsSchema(),
"tags_all": tftags.TagsSchemaComputed(),
"uri": {
Type: schema.TypeString,
Computed: true,
},
},

CustomizeDiff: verify.SetTagsDiff,
}
}

func resourceLocationObjectStorageCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).DataSyncConn()
defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig
tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{})))

input := &datasync.CreateLocationObjectStorageInput{
AgentArns: flex.ExpandStringSet(d.Get("agent_arns").(*schema.Set)),
Subdirectory: aws.String(d.Get("subdirectory").(string)),
BucketName: aws.String(d.Get("bucket_name").(string)),
ServerHostname: aws.String(d.Get("server_hostname").(string)),
Tags: Tags(tags.IgnoreAWS()),
}

if v, ok := d.GetOk("access_key"); ok {
input.AccessKey = aws.String(v.(string))
}

if v, ok := d.GetOk("server_protocol"); ok {
input.ServerProtocol = aws.String(v.(string))
}

if v, ok := d.GetOk("server_port"); ok {
input.ServerPort = aws.Int64(int64(v.(int)))
}

if v, ok := d.GetOk("secret_key"); ok {
input.SecretKey = aws.String(v.(string))
}

if v, ok := d.GetOk("server_certficate"); ok {
input.ServerCertificate = []byte(v.(string))
}

log.Printf("[DEBUG] Creating DataSync Location Object Storage: %s", input)
output, err := conn.CreateLocationObjectStorage(input)
if err != nil {
return fmt.Errorf("error creating DataSync Location Object Storage: %w", err)
}

d.SetId(aws.StringValue(output.LocationArn))

return resourceLocationObjectStorageRead(d, meta)
}

func resourceLocationObjectStorageRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).DataSyncConn()
defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig
ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig

output, err := FindLocationObjectStorageByARN(conn, d.Id())

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] DataSync Location ObjectStorage (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("error reading DataSync Location ObjectStorage (%s): %w", d.Id(), err)
}

subdirectory, err := SubdirectoryFromLocationURI(aws.StringValue(output.LocationUri))

if err != nil {
return err
}

d.Set("agent_arns", flex.FlattenStringSet(output.AgentArns))
d.Set("arn", output.LocationArn)
d.Set("server_protocol", output.ServerProtocol)
d.Set("subdirectory", subdirectory)
d.Set("access_key", output.AccessKey)
d.Set("server_port", output.ServerPort)
d.Set("server_certificate", string(output.ServerCertificate))

uri := aws.StringValue(output.LocationUri)

hostname, bucketName, err := decodeObjectStorageURI(uri)
if err != nil {
return err
}

d.Set("server_hostname", hostname)
d.Set("bucket_name", bucketName)

d.Set("uri", uri)

tags, err := ListTags(conn, d.Id())

if err != nil {
return fmt.Errorf("error listing tags for DataSync Location Object Storage (%s): %w", d.Id(), err)
}

tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig)

//lintignore:AWSR002
if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil {
return fmt.Errorf("error setting tags: %w", err)
}

if err := d.Set("tags_all", tags.Map()); err != nil {
return fmt.Errorf("error setting tags_all: %w", err)
}

return nil
}

func resourceLocationObjectStorageUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).DataSyncConn()

if d.HasChangesExcept("tags_all", "tags") {
input := &datasync.UpdateLocationObjectStorageInput{
LocationArn: aws.String(d.Id()),
}

if d.HasChange("server_protocol") {
input.ServerProtocol = aws.String(d.Get("server_protocol").(string))
}

if d.HasChange("server_port") {
input.ServerPort = aws.Int64(int64(d.Get("server_port").(int)))
}

if d.HasChange("access_key") {
input.AccessKey = aws.String(d.Get("access_key").(string))
}

if d.HasChange("secret_key") {
input.SecretKey = aws.String(d.Get("secret_key").(string))
}

if d.HasChange("subdirectory") {
input.Subdirectory = aws.String(d.Get("subdirectory").(string))
}

if d.HasChange("server_certficate") {
input.ServerCertificate = []byte(d.Get("server_certficate").(string))
}

_, err := conn.UpdateLocationObjectStorage(input)
if err != nil {
return fmt.Errorf("error updating DataSync Location Object Storage (%s): %w", d.Id(), err)
}
}

if d.HasChange("tags_all") {
o, n := d.GetChange("tags_all")

if err := UpdateTags(conn, d.Id(), o, n); err != nil {
return fmt.Errorf("error updating Datasync Object Storage location (%s) tags: %w", d.Id(), err)
}
}
return resourceLocationObjectStorageRead(d, meta)
}

func resourceLocationObjectStorageDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).DataSyncConn()

input := &datasync.DeleteLocationInput{
LocationArn: aws.String(d.Id()),
}

log.Printf("[DEBUG] Deleting DataSync Location Object Storage: %s", input)
_, err := conn.DeleteLocation(input)

if tfawserr.ErrMessageContains(err, datasync.ErrCodeInvalidRequestException, "not found") {
return nil
}

if err != nil {
return fmt.Errorf("error deleting DataSync Location Object Storage (%s): %w", d.Id(), err)
}

return nil
}

func decodeObjectStorageURI(uri string) (string, string, error) {
prefix := "object-storage://"
if !strings.HasPrefix(uri, prefix) {
return "", "", fmt.Errorf("incorrect uri format needs to start with %s", prefix)
}
trimmedUri := strings.TrimPrefix(uri, prefix)
uriParts := strings.Split(trimmedUri, "/")

if len(uri) < 2 {
return "", "", fmt.Errorf("incorrect uri format needs to start with %sSERVER-NAME/BUCKET-NAME/SUBDIRECTORY", prefix)
}

return uriParts[0], uriParts[1], nil
}
Loading