@@ -103,7 +103,7 @@ func ResourceStorageBucket() *schema.Resource {
103
103
Type : schema .TypeBool ,
104
104
Optional : true ,
105
105
Default : false ,
106
- 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.` ,
106
+ 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, deleting anywhereCaches may take 80 minutes to complete .` ,
107
107
},
108
108
109
109
"labels" : {
@@ -592,6 +592,98 @@ func labelKeyValidator(val interface{}, key string) (warns []string, errs []erro
592
592
return
593
593
}
594
594
595
+ func getAnywhereCacheListResult (config * transport_tpg.Config , bucket string ) ([]interface {}, error ) {
596
+ // Define the cache list URL
597
+ cacheListUrl := fmt .Sprintf ("https://storage.googleapis.com/storage/v1/b/%s/anywhereCaches/" , bucket )
598
+
599
+ // Send request to get resource list
600
+ res , err := transport_tpg .SendRequest (transport_tpg.SendRequestOptions {
601
+ Config : config ,
602
+ Method : "GET" ,
603
+ Project : config .Project ,
604
+ RawURL : cacheListUrl ,
605
+ UserAgent : config .UserAgent ,
606
+ })
607
+ if err != nil {
608
+ return nil , err
609
+ }
610
+
611
+ resourceList , ok := res ["items" ]
612
+ if ! ok {
613
+ return nil , nil // No cache exists, return nil list and no error
614
+ }
615
+
616
+ rl , ok := resourceList .([]interface {})
617
+ if ! ok {
618
+ return nil , fmt .Errorf ("unexpected type for resource list: %T" , resourceList )
619
+ }
620
+
621
+ return rl , nil
622
+ }
623
+
624
+ func deleteAnywhereCacheIfAny (config * transport_tpg.Config , bucket string ) error {
625
+ // Get the initial list of Anywhere Caches
626
+ cacheList , err := getAnywhereCacheListResult (config , bucket )
627
+ if err != nil {
628
+ return err
629
+ }
630
+
631
+ // If no cache exists initially, return early
632
+ if len (cacheList ) == 0 {
633
+ return nil
634
+ }
635
+
636
+ // Iterate over each object in the resource list
637
+ for _ , item := range cacheList {
638
+ // Ensure the item is a map
639
+ obj , ok := item .(map [string ]interface {})
640
+ if ! ok {
641
+ return fmt .Errorf ("unexpected type for resource list item: %T" , item )
642
+ }
643
+
644
+ // Check the state of the object
645
+ state , ok := obj ["state" ].(string )
646
+ if ! ok {
647
+ continue // If state is not a string, skip this item
648
+ }
649
+ if ! strings .EqualFold (state , "running" ) && ! strings .EqualFold (state , "paused" ) {
650
+ continue
651
+ }
652
+
653
+ // Disable the cache if state is running or paused
654
+ anywhereCacheId , ok := obj ["anywhereCacheId" ].(string )
655
+ if ! ok {
656
+ return fmt .Errorf ("missing or invalid anywhereCacheId: %v" , obj )
657
+ }
658
+ disableUrl := fmt .Sprintf ("https://storage.googleapis.com/storage/v1/b/%s/anywhereCaches/%s/disable" , bucket , anywhereCacheId )
659
+ _ , err := transport_tpg .SendRequest (transport_tpg.SendRequestOptions {
660
+ Config : config ,
661
+ Method : "POST" ,
662
+ Project : config .Project ,
663
+ RawURL : disableUrl ,
664
+ UserAgent : config .UserAgent ,
665
+ })
666
+ if err != nil {
667
+ return err
668
+ }
669
+ }
670
+ time .Sleep (80 * time .Minute ) // It takes around 70 minutes of time for cache to finally delete post it disable time.
671
+
672
+ // Post this time, we check again!
673
+ // Get the list of Anywhere Caches after the sleep
674
+ cacheList , err = getAnywhereCacheListResult (config , bucket )
675
+ if err != nil {
676
+ return err
677
+ }
678
+
679
+ // Check if the cache list is now empty
680
+ if len (cacheList ) == 0 {
681
+ return nil
682
+ }
683
+
684
+ return fmt .Errorf ("Error while deleting the cache: caches still exists post 80mins of their disable time" )
685
+ }
686
+
595
687
func resourceDataplexLabelDiffSuppress (k , old , new string , d * schema.ResourceData ) bool {
596
688
if strings .HasPrefix (k , resourceDataplexGoogleProvidedLabelPrefix ) && new == "" {
597
689
return true
@@ -994,8 +1086,13 @@ func resourceStorageBucketDelete(d *schema.ResourceData, meta interface{}) error
994
1086
break
995
1087
}
996
1088
997
- if len (res .Items ) == 0 {
998
- break // 0 items, bucket empty
1089
+ cacheList , cacheListErr := getAnywhereCacheListResult (config , bucket )
1090
+ if cacheListErr != nil {
1091
+ return cacheListErr
1092
+ }
1093
+
1094
+ if len (res .Items ) == 0 && len (cacheList ) == 0 {
1095
+ break // 0 items and no caches, bucket empty
999
1096
}
1000
1097
1001
1098
if d .Get ("retention_policy.0.is_locked" ).(bool ) {
@@ -1013,10 +1110,11 @@ func resourceStorageBucketDelete(d *schema.ResourceData, meta interface{}) error
1013
1110
}
1014
1111
1015
1112
if ! d .Get ("force_destroy" ).(bool ) {
1016
- deleteErr := fmt .Errorf ("Error trying to delete bucket %s containing objects without `force_destroy` set to true" , bucket )
1113
+ deleteErr := fmt .Errorf ("Error trying to delete bucket %s without `force_destroy` set to true" , bucket )
1017
1114
log .Printf ("Error! %s : %s\n \n " , bucket , deleteErr )
1018
1115
return deleteErr
1019
1116
}
1117
+
1020
1118
// GCS requires that a bucket be empty (have no objects or object
1021
1119
// versions) before it can be deleted.
1022
1120
log .Printf ("[DEBUG] GCS Bucket attempting to forceDestroy\n \n " )
@@ -1033,6 +1131,13 @@ func resourceStorageBucketDelete(d *schema.ResourceData, meta interface{}) error
1033
1131
// is it scheduled to be plumbed to individual providers.
1034
1132
wp := workerpool .New (runtime .NumCPU () - 1 )
1035
1133
1134
+ wp .Submit (func () {
1135
+ err = deleteAnywhereCacheIfAny (config , bucket )
1136
+ if err != nil {
1137
+ deleteObjectError = fmt .Errorf ("error deleting the caches on the bucket %s : %w" , bucket , err )
1138
+ }
1139
+ })
1140
+
1036
1141
for _ , object := range res .Items {
1037
1142
log .Printf ("[DEBUG] Found %s" , object .Name )
1038
1143
object := object
0 commit comments