From 49cd31d7a6d930a271ccb63936cbbe71d986bb89 Mon Sep 17 00:00:00 2001 From: Helio Machado <0x2b3bfa0+git@googlemail.com> Date: Thu, 3 Mar 2022 15:04:03 +0000 Subject: [PATCH 1/5] Empty buckets during Delete() --- .gitignore | 2 +- task/aws/resources/resource_bucket.go | 45 +++------------------------ task/aws/task.go | 4 +++ task/az/task.go | 4 +++ task/common/machine/storage.go | 27 +++++++++++++++- task/gcp/resources/resource_bucket.go | 13 -------- task/gcp/task.go | 4 +++ 7 files changed, 43 insertions(+), 56 deletions(-) diff --git a/.gitignore b/.gitignore index e0aae47d..387b1b90 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,4 @@ terraform # Ignore the Go vendor directory, superseded by proxy.golang.org and go.{mod,sum} vendor -./terraform-provider-iterative +terraform-provider-iterative diff --git a/task/aws/resources/resource_bucket.go b/task/aws/resources/resource_bucket.go index b0d64530..84cbefa9 100644 --- a/task/aws/resources/resource_bucket.go +++ b/task/aws/resources/resource_bucket.go @@ -76,54 +76,17 @@ func (b *Bucket) Update(ctx context.Context) error { } func (b *Bucket) Delete(ctx context.Context) error { - listInput := s3.ListObjectsV2Input{ + input := s3.DeleteBucketInput{ Bucket: aws.String(b.Identifier), } - for paginator := s3.NewListObjectsV2Paginator(b.Client.Services.S3, &listInput); paginator.HasMorePages(); { - page, err := paginator.NextPage(ctx) - - if err != nil { - var e smithy.APIError - if errors.As(err, &e) && e.ErrorCode() == "NoSuchBucket" { - b.Resource = nil - return nil - } - return err - } - - if len(page.Contents) == 0 { - break - } - - var objects []types.ObjectIdentifier - for _, object := range page.Contents { - objects = append(objects, types.ObjectIdentifier{ - Key: object.Key, - }) - } - - input := s3.DeleteObjectsInput{ - Bucket: aws.String(b.Identifier), - Delete: &types.Delete{ - Objects: objects, - }, - } - - if _, err = b.Client.Services.S3.DeleteObjects(ctx, &input); err != nil { + if _, err := b.Client.Services.S3.DeleteBucket(ctx, &input); err != nil { + var e smithy.APIError + if errors.As(err, &e) && e.ErrorCode() != "NoSuchBucket" { return err } } - deleteInput := s3.DeleteBucketInput{ - Bucket: aws.String(b.Identifier), - } - - _, err := b.Client.Services.S3.DeleteBucket(ctx, &deleteInput) - if err != nil { - return err - } - b.Resource = nil return nil } diff --git a/task/aws/task.go b/task/aws/task.go index 625f99ec..700142a6 100644 --- a/task/aws/task.go +++ b/task/aws/task.go @@ -199,6 +199,10 @@ func (t *Task) Delete(ctx context.Context) error { if err := t.Pull(ctx, t.Attributes.Environment.DirectoryOut); err != nil && err != common.NotFoundError { return err } + log.Println("[INFO] Emptying Bucket...") + if err := machine.Delete(ctx, (*t.DataSources.Credentials.Resource)["RCLONE_REMOTE"]); err != nil && err != common.NotFoundError { + return err + } } log.Println("[INFO] Deleting AutoScalingGroup...") if err := t.Resources.AutoScalingGroup.Delete(ctx); err != nil { diff --git a/task/az/task.go b/task/az/task.go index d062d86b..9a0a5784 100644 --- a/task/az/task.go +++ b/task/az/task.go @@ -188,6 +188,10 @@ func (t *Task) Delete(ctx context.Context) error { if err := t.Pull(ctx, t.Attributes.Environment.DirectoryOut); err != nil && err != common.NotFoundError { return err } + log.Println("[INFO] Emptying BlobContainer...") + if err := machine.Delete(ctx, (*t.DataSources.Credentials.Resource)["RCLONE_REMOTE"]); err != nil && err != common.NotFoundError { + return err + } } log.Println("[INFO] Deleting VirtualMachineScaleSet...") if err := t.Resources.VirtualMachineScaleSet.Delete(ctx); err != nil { diff --git a/task/common/machine/storage.go b/task/common/machine/storage.go index f10f2f54..0ccad56b 100644 --- a/task/common/machine/storage.go +++ b/task/common/machine/storage.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "io" "path/filepath" "strings" @@ -14,6 +15,7 @@ import ( _ "github.com/rclone/rclone/backend/s3" "github.com/rclone/rclone/fs" + "github.com/rclone/rclone/fs/operations" "github.com/rclone/rclone/fs/sync" "terraform-provider-iterative/task/common" @@ -99,9 +101,32 @@ func Transfer(ctx context.Context, source, destination string) error { return err } - if err := sync.CopyDir(ctx, destinationFileSystem, sourceFileSystem, true); err != nil { + return sync.CopyDir(ctx, destinationFileSystem, sourceFileSystem, true) +} + +func Delete(ctx context.Context, destination string) error { + destinationFileSystem, err := fs.NewFs(ctx, destination) + if err != nil { return err } + actions := []func(context.Context) error { + func(ctx context.Context) error { + return operations.Delete(ctx, destinationFileSystem) + }, + func(ctx context.Context) error { + return operations.Rmdirs(ctx, destinationFileSystem, "", true) + }, + } + + for _, action := range actions { + if err := action(ctx); err != nil { + if !errors.Is(err, fs.ErrorDirNotFound) && !strings.Contains(err.Error(), "no such host") { + return common.NotFoundError + } + return err + } + } + return nil } diff --git a/task/gcp/resources/resource_bucket.go b/task/gcp/resources/resource_bucket.go index b7c23b79..a473338d 100644 --- a/task/gcp/resources/resource_bucket.go +++ b/task/gcp/resources/resource_bucket.go @@ -65,19 +65,6 @@ func (b *Bucket) Delete(ctx context.Context) error { return nil } - deletePage := func(objects *storage.Objects) error { - for _, object := range objects.Items { - if err := b.Client.Services.Storage.Objects.Delete(b.Identifier, object.Name).Do(); err != nil { - return err - } - } - return nil - } - - if err := b.Client.Services.Storage.Objects.List(b.Identifier).Pages(ctx, deletePage); err != nil { - return err - } - if err := b.Client.Services.Storage.Buckets.Delete(b.Identifier).Do(); err != nil { return err } diff --git a/task/gcp/task.go b/task/gcp/task.go index 0db1dbeb..9deda895 100644 --- a/task/gcp/task.go +++ b/task/gcp/task.go @@ -267,6 +267,10 @@ func (t *Task) Delete(ctx context.Context) error { if err := t.Pull(ctx, t.Attributes.Environment.DirectoryOut); err != nil && err != common.NotFoundError { return err } + log.Println("[INFO] Emptying Bucket...") + if err := machine.Delete(ctx, (*t.DataSources.Credentials.Resource)["RCLONE_REMOTE"]); err != nil && err != common.NotFoundError { + return err + } } log.Println("[INFO] Deleting InstanceGroupManager...") if err := t.Resources.InstanceGroupManager.Delete(ctx); err != nil { From a134610845be8aaa4f6c857982269550052a53ef Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Thu, 3 Mar 2022 21:04:55 +0000 Subject: [PATCH 2/5] Restyled by gofmt --- .../resources/resource_auto_scaling_group.go | 2 ++ task/aws/task.go | 8 +++++--- .../resource_virtual_machine_scale_set.go | 2 ++ task/az/task.go | 10 ++++++---- task/common/machine/storage.go | 2 +- task/gcp/resources/resource_bucket.go | 17 ++++++++++------- .../resource_instance_group_manager.go | 2 ++ task/gcp/task.go | 8 +++++--- 8 files changed, 33 insertions(+), 18 deletions(-) diff --git a/task/aws/resources/resource_auto_scaling_group.go b/task/aws/resources/resource_auto_scaling_group.go index 19910516..ee0f07cd 100644 --- a/task/aws/resources/resource_auto_scaling_group.go +++ b/task/aws/resources/resource_auto_scaling_group.go @@ -3,6 +3,7 @@ package resources import ( "context" "errors" + "log" "net" "strconv" "time" @@ -133,6 +134,7 @@ func (a *AutoScalingGroup) Read(ctx context.Context) error { if instance.StateReason != nil { status += " " + aws.ToString(instance.StateReason.Message) } + log.Println("[DEBUG] AutoScaling Group State:", status) if status == "running" { a.Attributes.Status[common.StatusCodeActive]++ } diff --git a/task/aws/task.go b/task/aws/task.go index 700142a6..2e454bbd 100644 --- a/task/aws/task.go +++ b/task/aws/task.go @@ -195,9 +195,11 @@ func (t *Task) Read(ctx context.Context) error { func (t *Task) Delete(ctx context.Context) error { log.Println("[INFO] Downloading Directory...") - if t.Attributes.Environment.DirectoryOut != "" && t.Read(ctx) == nil { - if err := t.Pull(ctx, t.Attributes.Environment.DirectoryOut); err != nil && err != common.NotFoundError { - return err + if t.Read(ctx) == nil { + if t.Attributes.Environment.DirectoryOut != "" { + if err := t.Pull(ctx, t.Attributes.Environment.DirectoryOut); err != nil && err != common.NotFoundError { + return err + } } log.Println("[INFO] Emptying Bucket...") if err := machine.Delete(ctx, (*t.DataSources.Credentials.Resource)["RCLONE_REMOTE"]); err != nil && err != common.NotFoundError { diff --git a/task/az/resources/resource_virtual_machine_scale_set.go b/task/az/resources/resource_virtual_machine_scale_set.go index aa8a8468..6c4650a5 100644 --- a/task/az/resources/resource_virtual_machine_scale_set.go +++ b/task/az/resources/resource_virtual_machine_scale_set.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "errors" "fmt" + "log" "net" "regexp" "time" @@ -243,6 +244,7 @@ func (v *VirtualMachineScaleSet) Read(ctx context.Context) error { if scaleSetView.VirtualMachine.StatusesSummary != nil { for _, status := range *scaleSetView.VirtualMachine.StatusesSummary { code := to.String(status.Code) + log.Println("[DEBUG] ScaleSet Status Summary:", code, int(to.Int32(status.Count))) if code == "ProvisioningState/succeeded" { v.Attributes.Status[common.StatusCodeActive] = int(to.Int32(status.Count)) } diff --git a/task/az/task.go b/task/az/task.go index 9a0a5784..fe9b1cfa 100644 --- a/task/az/task.go +++ b/task/az/task.go @@ -184,11 +184,13 @@ func (t *Task) Read(ctx context.Context) error { func (t *Task) Delete(ctx context.Context) error { log.Println("[INFO] Downloading Directory...") - if t.Attributes.Environment.DirectoryOut != "" && t.Read(ctx) == nil { - if err := t.Pull(ctx, t.Attributes.Environment.DirectoryOut); err != nil && err != common.NotFoundError { - return err + if t.Read(ctx) == nil { + if t.Attributes.Environment.DirectoryOut != "" { + if err := t.Pull(ctx, t.Attributes.Environment.DirectoryOut); err != nil && err != common.NotFoundError { + return err + } } - log.Println("[INFO] Emptying BlobContainer...") + log.Println("[INFO] Emptying Bucket...") if err := machine.Delete(ctx, (*t.DataSources.Credentials.Resource)["RCLONE_REMOTE"]); err != nil && err != common.NotFoundError { return err } diff --git a/task/common/machine/storage.go b/task/common/machine/storage.go index 0ccad56b..a73b3170 100644 --- a/task/common/machine/storage.go +++ b/task/common/machine/storage.go @@ -110,7 +110,7 @@ func Delete(ctx context.Context, destination string) error { return err } - actions := []func(context.Context) error { + actions := []func(context.Context) error{ func(ctx context.Context) error { return operations.Delete(ctx, destinationFileSystem) }, diff --git a/task/gcp/resources/resource_bucket.go b/task/gcp/resources/resource_bucket.go index a473338d..5e852e38 100644 --- a/task/gcp/resources/resource_bucket.go +++ b/task/gcp/resources/resource_bucket.go @@ -3,7 +3,8 @@ package resources import ( "context" "errors" - + "time" + "google.golang.org/api/googleapi" "google.golang.org/api/storage/v1" @@ -61,12 +62,14 @@ func (b *Bucket) Update(ctx context.Context) error { } func (b *Bucket) Delete(ctx context.Context) error { - if b.Read(ctx) == common.NotFoundError { - return nil - } - - if err := b.Client.Services.Storage.Buckets.Delete(b.Identifier).Do(); err != nil { - return err + for i, err := 0, b.Client.Services.Storage.Buckets.Delete(b.Identifier).Do(); b.Read(ctx) != common.NotFoundError; i++ { + var e *googleapi.Error + if !errors.As(err, &e) || e.Code != 409 { + return err + } else if i > 10 { + return errors.New("timed out waiting for bucket to be deleted") + } + time.Sleep(10*time.Second) } b.Resource = nil diff --git a/task/gcp/resources/resource_instance_group_manager.go b/task/gcp/resources/resource_instance_group_manager.go index 2585969a..b30dd5ff 100644 --- a/task/gcp/resources/resource_instance_group_manager.go +++ b/task/gcp/resources/resource_instance_group_manager.go @@ -3,6 +3,7 @@ package resources import ( "context" "errors" + "log" "net" "path/filepath" "strings" @@ -77,6 +78,7 @@ func (i *InstanceGroupManager) Read(ctx context.Context) error { i.Attributes.Addresses = []net.IP{} i.Attributes.Status = common.Status{common.StatusCodeActive: 0} for _, groupInstance := range groupInstances.Items { + log.Println("[DEBUG] Instance Group Manager Status:", groupInstance.Status) if groupInstance.Status == "RUNNING" { instance, err := i.Client.Services.Compute.Instances.Get(i.Client.Credentials.ProjectID, i.Client.Region, filepath.Base(groupInstance.Instance)).Do() if err != nil { diff --git a/task/gcp/task.go b/task/gcp/task.go index 9deda895..4c673052 100644 --- a/task/gcp/task.go +++ b/task/gcp/task.go @@ -263,9 +263,11 @@ func (t *Task) Read(ctx context.Context) error { func (t *Task) Delete(ctx context.Context) error { log.Println("[INFO] Downloading Directory...") - if t.Attributes.Environment.DirectoryOut != "" && t.Read(ctx) == nil { - if err := t.Pull(ctx, t.Attributes.Environment.DirectoryOut); err != nil && err != common.NotFoundError { - return err + if t.Read(ctx) == nil { + if t.Attributes.Environment.DirectoryOut != "" { + if err := t.Pull(ctx, t.Attributes.Environment.DirectoryOut); err != nil && err != common.NotFoundError { + return err + } } log.Println("[INFO] Emptying Bucket...") if err := machine.Delete(ctx, (*t.DataSources.Credentials.Resource)["RCLONE_REMOTE"]); err != nil && err != common.NotFoundError { From b5281f44168692122710a2cb10181cae2541f18d Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Thu, 3 Mar 2022 21:56:26 +0000 Subject: [PATCH 3/5] Restyled by gofmt --- task/az/resources/resource_virtual_machine_scale_set.go | 2 +- task/gcp/resources/resource_bucket.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/task/az/resources/resource_virtual_machine_scale_set.go b/task/az/resources/resource_virtual_machine_scale_set.go index 6c4650a5..110ad375 100644 --- a/task/az/resources/resource_virtual_machine_scale_set.go +++ b/task/az/resources/resource_virtual_machine_scale_set.go @@ -244,7 +244,7 @@ func (v *VirtualMachineScaleSet) Read(ctx context.Context) error { if scaleSetView.VirtualMachine.StatusesSummary != nil { for _, status := range *scaleSetView.VirtualMachine.StatusesSummary { code := to.String(status.Code) - log.Println("[DEBUG] ScaleSet Status Summary:", code, int(to.Int32(status.Count))) + log.Println("[DEBUG] ScaleSet Status Summary:", code, int(to.Int32(status.Count))) if code == "ProvisioningState/succeeded" { v.Attributes.Status[common.StatusCodeActive] = int(to.Int32(status.Count)) } diff --git a/task/gcp/resources/resource_bucket.go b/task/gcp/resources/resource_bucket.go index 5e852e38..f1b19aec 100644 --- a/task/gcp/resources/resource_bucket.go +++ b/task/gcp/resources/resource_bucket.go @@ -4,7 +4,7 @@ import ( "context" "errors" "time" - + "google.golang.org/api/googleapi" "google.golang.org/api/storage/v1" @@ -69,7 +69,7 @@ func (b *Bucket) Delete(ctx context.Context) error { } else if i > 10 { return errors.New("timed out waiting for bucket to be deleted") } - time.Sleep(10*time.Second) + time.Sleep(10 * time.Second) } b.Resource = nil From 34f37e17e1f0736fe7baccd5709a1482bbef7788 Mon Sep 17 00:00:00 2001 From: Helio Machado <0x2b3bfa0+git@googlemail.com> Date: Thu, 3 Mar 2022 23:25:19 +0000 Subject: [PATCH 4/5] Add bucket deletion waiting mechanism --- task/gcp/resources/resource_bucket.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/task/gcp/resources/resource_bucket.go b/task/gcp/resources/resource_bucket.go index 5e852e38..110fadba 100644 --- a/task/gcp/resources/resource_bucket.go +++ b/task/gcp/resources/resource_bucket.go @@ -3,6 +3,7 @@ package resources import ( "context" "errors" + "log" "time" "google.golang.org/api/googleapi" @@ -63,10 +64,11 @@ func (b *Bucket) Update(ctx context.Context) error { func (b *Bucket) Delete(ctx context.Context) error { for i, err := 0, b.Client.Services.Storage.Buckets.Delete(b.Identifier).Do(); b.Read(ctx) != common.NotFoundError; i++ { + log.Println("[DEBUG] Deleting Bucket...") var e *googleapi.Error if !errors.As(err, &e) || e.Code != 409 { return err - } else if i > 10 { + } else if i > 30 { return errors.New("timed out waiting for bucket to be deleted") } time.Sleep(10*time.Second) From 880bf0ca86125aa997c13824dfc6ca342ba0f667 Mon Sep 17 00:00:00 2001 From: Helio Machado <0x2b3bfa0+git@googlemail.com> Date: Thu, 3 Mar 2022 23:30:50 +0000 Subject: [PATCH 5/5] Revert Google Cloud --- task/gcp/resources/resource_bucket.go | 28 +++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/task/gcp/resources/resource_bucket.go b/task/gcp/resources/resource_bucket.go index 432f6b6a..b7c23b79 100644 --- a/task/gcp/resources/resource_bucket.go +++ b/task/gcp/resources/resource_bucket.go @@ -3,8 +3,6 @@ package resources import ( "context" "errors" - "log" - "time" "google.golang.org/api/googleapi" "google.golang.org/api/storage/v1" @@ -63,15 +61,25 @@ func (b *Bucket) Update(ctx context.Context) error { } func (b *Bucket) Delete(ctx context.Context) error { - for i, err := 0, b.Client.Services.Storage.Buckets.Delete(b.Identifier).Do(); b.Read(ctx) != common.NotFoundError; i++ { - log.Println("[DEBUG] Deleting Bucket...") - var e *googleapi.Error - if !errors.As(err, &e) || e.Code != 409 { - return err - } else if i > 30 { - return errors.New("timed out waiting for bucket to be deleted") + if b.Read(ctx) == common.NotFoundError { + return nil + } + + deletePage := func(objects *storage.Objects) error { + for _, object := range objects.Items { + if err := b.Client.Services.Storage.Objects.Delete(b.Identifier, object.Name).Do(); err != nil { + return err + } } - time.Sleep(10 * time.Second) + return nil + } + + if err := b.Client.Services.Storage.Objects.List(b.Identifier).Pages(ctx, deletePage); err != nil { + return err + } + + if err := b.Client.Services.Storage.Buckets.Delete(b.Identifier).Do(); err != nil { + return err } b.Resource = nil