Skip to content

Commit b89650f

Browse files
committed
Provide support for deleting pending caches present on bucket, This would help our customers to destory their bucket consisting of caches managed outside terraform without any other step
1 parent b4264a9 commit b89650f

File tree

1 file changed

+108
-4
lines changed

1 file changed

+108
-4
lines changed

mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl

+108-4
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func ResourceStorageBucket() *schema.Resource {
101101
Type: schema.TypeBool,
102102
Optional: true,
103103
Default: false,
104-
Description: `When deleting a bucket, this boolean option will delete all contained objects. If you try to delete a bucket that contains objects, Terraform will fail that run.`,
104+
Description: `When deleting a bucket, this boolean option will delete all contained objects, or anywhereCaches (if any). If you try to delete a bucket that contains objects or anywhereCaches, Terraform will fail that run.`,
105105
},
106106

107107
"labels": {
@@ -590,6 +590,98 @@ func labelKeyValidator(val interface{}, key string) (warns []string, errs []erro
590590
return
591591
}
592592

593+
func getAnywhereCacheListResult(config *transport_tpg.Config, bucket string) ([]interface{}, error) {
594+
// Define the cache list URL
595+
cacheListUrl := fmt.Sprintf("https://storage.googleapis.com/storage/v1/b/%s/anywhereCaches/", bucket)
596+
597+
// Send request to get resource list
598+
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
599+
Config: config,
600+
Method: "GET",
601+
Project: config.Project,
602+
RawURL: cacheListUrl,
603+
UserAgent: config.UserAgent,
604+
})
605+
if err != nil {
606+
return nil, err
607+
}
608+
609+
resourceList, ok := res["items"]
610+
if !ok {
611+
return nil, nil // No cache exists, return nil list and no error
612+
}
613+
614+
rl, ok := resourceList.([]interface{})
615+
if !ok {
616+
return nil, fmt.Errorf("unexpected type for resource list: %T", resourceList)
617+
}
618+
619+
return rl, nil
620+
}
621+
622+
func deleteAnywhereCacheIfAny(config *transport_tpg.Config, bucket string) error {
623+
// Get the initial list of Anywhere Caches
624+
cacheList, err := getAnywhereCacheListResult(config, bucket)
625+
if err != nil {
626+
return err
627+
}
628+
629+
// If no cache exists initially, return early
630+
if len(cacheList) == 0 {
631+
return nil
632+
}
633+
634+
// Iterate over each object in the resource list
635+
for _, item := range cacheList {
636+
// Ensure the item is a map
637+
obj, ok := item.(map[string]interface{})
638+
if !ok {
639+
return fmt.Errorf("unexpected type for resource list item: %T", item)
640+
}
641+
642+
// Check the state of the object
643+
state, ok := obj["state"].(string)
644+
if !ok {
645+
continue // If state is not a string, skip this item
646+
}
647+
if state != "running" && state != "paused" {
648+
continue
649+
}
650+
651+
// Disable the cache if state is running or paused
652+
anywhereCacheId, ok := obj["anywhereCacheId"].(string)
653+
if !ok {
654+
return fmt.Errorf("missing or invalid anywhereCacheId: %v", obj)
655+
}
656+
disableUrl := fmt.Sprintf("https://storage.googleapis.com/storage/v1/b/%s/anywhereCaches/%s/disable", bucket, anywhereCacheId)
657+
_, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
658+
Config: config,
659+
Method: "POST",
660+
Project: config.Project,
661+
RawURL: disableUrl,
662+
UserAgent: config.UserAgent,
663+
})
664+
if err != nil {
665+
return err
666+
}
667+
}
668+
time.Sleep(80 * time.Minute) // It takes around 70 minutes of time for cache to finally delete post it disable time.
669+
670+
// Post this time, we check again!
671+
// Get the list of Anywhere Caches after the sleep
672+
cacheList, err = getAnywhereCacheList(config, bucket)
673+
if err != nil {
674+
return err
675+
}
676+
677+
// Check if the cache list is now empty
678+
if len(cacheList) == 0 {
679+
return nil
680+
}
681+
682+
return fmt.Errorf("error while disabling the cache!")
683+
}
684+
593685
func resourceDataplexLabelDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
594686
if strings.HasPrefix(k, resourceDataplexGoogleProvidedLabelPrefix) && new == "" {
595687
return true
@@ -992,8 +1084,13 @@ func resourceStorageBucketDelete(d *schema.ResourceData, meta interface{}) error
9921084
break
9931085
}
9941086

995-
if len(res.Items) == 0 {
996-
break // 0 items, bucket empty
1087+
cacheList, cacheListErr := getAnywhereCacheListResult(config, bucket)
1088+
if cacheListErr != nil {
1089+
return cacheListErr
1090+
}
1091+
1092+
if len(res.Items) == 0 and len(cacheList) == 0 {
1093+
break // 0 items and no caches, bucket empty
9971094
}
9981095

9991096
if d.Get("retention_policy.0.is_locked").(bool) {
@@ -1011,10 +1108,11 @@ func resourceStorageBucketDelete(d *schema.ResourceData, meta interface{}) error
10111108
}
10121109

10131110
if !d.Get("force_destroy").(bool) {
1014-
deleteErr := fmt.Errorf("Error trying to delete bucket %s containing objects without `force_destroy` set to true", bucket)
1111+
deleteErr := fmt.Errorf("Error trying to delete bucket %s without `force_destroy` set to true", bucket)
10151112
log.Printf("Error! %s : %s\n\n", bucket, deleteErr)
10161113
return deleteErr
10171114
}
1115+
10181116
// GCS requires that a bucket be empty (have no objects or object
10191117
// versions) before it can be deleted.
10201118
log.Printf("[DEBUG] GCS Bucket attempting to forceDestroy\n\n")
@@ -1046,6 +1144,12 @@ func resourceStorageBucketDelete(d *schema.ResourceData, meta interface{}) error
10461144
})
10471145
}
10481146

1147+
// While we wait our objects to be deleted in background, delete the cache if any!
1148+
err = deleteAnywhereCacheIfAny(config, bucket)
1149+
if err != nil {
1150+
return fmt.Errorf("Error deleting the caches on the bucket %s : %v", bucket, err)
1151+
}
1152+
10491153
// Wait for everything to finish.
10501154
wp.StopWait()
10511155
}

0 commit comments

Comments
 (0)