Skip to content

Commit 19acdd0

Browse files
committed
Remove configured capability in the folders
1 parent 99247df commit 19acdd0

File tree

1 file changed

+119
-5
lines changed

1 file changed

+119
-5
lines changed

mmv1/third_party/terraform/services/resourcemanager/resource_google_folder_sweeper.go

Lines changed: 119 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,20 @@ import (
55
"fmt"
66
"log"
77
"strings"
8+
"time"
89

910
"github.com/hashicorp/terraform-provider-google/google/envvar"
11+
"github.com/hashicorp/terraform-provider-google/google/services/resourcemanager3"
1012
"github.com/hashicorp/terraform-provider-google/google/sweeper"
13+
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
14+
"google.golang.org/api/cloudresourcemanager/v1"
15+
"google.golang.org/api/googleapi"
1116
)
1217

1318
func init() {
1419
sweeper.AddTestSweepersLegacy("GoogleFolder", testSweepFolder)
1520
}
21+
1622
func testSweepFolder(region string) error {
1723
config, err := sweeper.SharedConfigForRegion(region)
1824
if err != nil {
@@ -27,7 +33,6 @@ func testSweepFolder(region string) error {
2733
}
2834

2935
org := envvar.UnsafeGetTestOrgFromEnv()
30-
log.Printf("[DEBUG] org %s", org)
3136

3237
if org == "" {
3338
log.Printf("[INFO][SWEEPER_LOG] no organization set, failing folder sweeper")
@@ -37,9 +42,8 @@ func testSweepFolder(region string) error {
3742
parent := "organizations/" + org
3843

3944
token := ""
45+
svc := config.NewResourceManagerV3Client(config.UserAgent)
4046
for paginate := true; paginate; {
41-
// Filter for folders with test prefix
42-
// filter := fmt.Sprintf("id:\"%s*\" -lifecycleState:DELETE_REQUESTED parent.id:%v", TestPrefix, org)
4347
found, err := config.NewResourceManagerV3Client(config.UserAgent).Folders.List().Parent(parent).PageToken(token).Do()
4448
if err != nil {
4549
log.Printf("[INFO][SWEEPER_LOG] error listing folders: %s", err)
@@ -53,8 +57,35 @@ func testSweepFolder(region string) error {
5357
log.Printf("[INFO][SWEEPER_LOG] Sweeping Folder id: %s, name: %s", folder.Name, folder.DisplayName)
5458
_, err := config.NewResourceManagerV3Client(config.UserAgent).Folders.Delete(folder.Name).Do()
5559
if err != nil {
56-
log.Printf("[INFO][SWEEPER_LOG] Error, failed to delete folder %s: %s", folder.Name, err)
57-
continue
60+
if isCapabilityError(err) {
61+
log.Println("[INFO][SWEEPER_LOG]Detected 'configured capability' violation. Starting cleanup...")
62+
63+
// 2. Get Folder to find ManagementProject
64+
folder, err := config.NewResourceManagerV3Client(config.UserAgent).Folders.Get(folder.Name).Do()
65+
if err != nil {
66+
log.Printf("[INFO][SWEEPER_LOG] Error, failed to delete folder %s: %s", folder.Name, err)
67+
continue
68+
}
69+
70+
// 3. Handle Liens on Management Project
71+
if folder.ManagementProject != "" {
72+
cleanupLiens(svc, folder.ManagementProject)
73+
}
74+
75+
// 4. Disable configured capability
76+
disableCapability(folder.Name)
77+
78+
// 5. Retry Delete
79+
log.Println("[INFO][SWEEPER_LOG]Retrying folder deletion...")
80+
_, err = config.NewResourceManagerV3Client(config.UserAgent).Folders.Delete(folder.Name).Do()
81+
if err != nil {
82+
log.Printf("[INFO][SWEEPER_LOG] Error, failed to delete folder %s: %s", folder.Name, err)
83+
continue
84+
}
85+
} else {
86+
log.Printf("[INFO][SWEEPER_LOG] Error, failed to delete folder %s: %s", folder.Name, err)
87+
continue
88+
}
5889
}
5990
}
6091
token = found.NextPageToken
@@ -63,3 +94,86 @@ func testSweepFolder(region string) error {
6394

6495
return nil
6596
}
97+
98+
// isCapabilityError parses the GCP error for the specific PreconditionFailure
99+
func isCapabilityError(err error) bool {
100+
if gErr, ok := err.(*googleapi.Error); ok {
101+
if gErr.Code == 400 && strings.Contains(gErr.Message, "Precondition check failed") {
102+
// Deep check for the description in the error details
103+
for _, detail := range gErr.Details {
104+
if dMap, ok := detail.(map[string]interface{}); ok {
105+
if violations, ok := dMap["violations"].([]interface{}); ok {
106+
for _, v := range violations {
107+
if vMap, ok := v.(map[string]interface{}); ok {
108+
if strings.Contains(fmt.Sprint(vMap["description"]), "configured capability") {
109+
return true
110+
}
111+
}
112+
}
113+
}
114+
}
115+
}
116+
}
117+
}
118+
return false
119+
}
120+
121+
func cleanupLiens(svc *cloudresourcemanager.Service, project string) {
122+
log.Printf("[INFO][SWEEPER_LOG]Checking liens on %s...\n", project)
123+
resp, err := svc.Liens.List().Parent(project).Do()
124+
if err != nil {
125+
log.Printf("[INFO][SWEEPER_LOG]Failed to list liens: %v", err)
126+
return
127+
}
128+
for _, l := range resp.Liens {
129+
log.Printf("[INFO][SWEEPER_LOG]Deleting lien: %s\n", l.Name)
130+
_, _ = svc.Liens.Delete(l.Name).Do()
131+
}
132+
}
133+
134+
func disableCapability(folderName string) {
135+
// Format is folders/{id}/capabilities/app-management
136+
capName := fmt.Sprintf("%s/capabilities/app-management", folderName)
137+
log.Printf("[INFO][SWEEPER_LOG]Disabling capability: %s\n", capName)
138+
139+
config, err := sweeper.SharedConfigForRegion("global")
140+
if err != nil {
141+
log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err)
142+
return
143+
}
144+
145+
err = config.LoadAndValidate(context.Background())
146+
if err != nil {
147+
log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err)
148+
return
149+
}
150+
151+
obj := map[string]interface{}{
152+
"value": false,
153+
}
154+
155+
url := "https://cloudresourcemanager.googleapis.com/v3/" + capName
156+
157+
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
158+
Config: config,
159+
Method: "PATCH",
160+
Project: config.Project,
161+
RawURL: url,
162+
UserAgent: config.UserAgent,
163+
Body: obj,
164+
})
165+
166+
if err != nil {
167+
log.Printf("[INFO][SWEEPER_LOG] Error disabling Capability: %s, err: %s", capName, err)
168+
} else {
169+
log.Printf("[INFO][SWEEPER_LOG] Finished disabled Capability: %s", capName)
170+
}
171+
172+
err = resourcemanager3.ResourceManager3OperationWaitTime(
173+
config, res, "Updating Capability", config.UserAgent,
174+
20*time.Minute)
175+
176+
if err != nil {
177+
log.Printf("[INFO][SWEEPER_LOG] Error for disabling Capability operation: %s, err: %s", capName, err)
178+
}
179+
}

0 commit comments

Comments
 (0)