Skip to content

Commit 034aa3d

Browse files
authored
tools/clean: add VPC orphan cleanup (#1450)
1 parent 169f682 commit 034aa3d

File tree

3 files changed

+137
-30
lines changed

3 files changed

+137
-30
lines changed

tools/clean/atlas/atlas.go

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func (pd *ProjectDependencies) Length() int {
4848
len(pd.Clusters) + len(pd.ServerlessClusters) + len(pd.FederatedDatabases)
4949
}
5050

51-
func (c *Cleaner) Clean(ctx context.Context, lifetime int) error {
51+
func (c *Cleaner) Clean(ctx context.Context, lifetimeHours int) error {
5252
projects := c.listProjectsByOrg(ctx, c.orgID)
5353

5454
if len(projects) > 0 {
@@ -60,9 +60,8 @@ func (c *Cleaner) Clean(ctx context.Context, lifetime int) error {
6060

6161
fmt.Println(text.FgHiWhite.Sprintf("\tStarting deletion of project %s(%s) (created at %v)...", p.GetName(), p.GetId(), p.Created))
6262

63-
if time.Since(p.Created) < time.Duration(lifetime)*time.Hour {
64-
fmt.Println(text.FgYellow.Sprintf("\tProject %s(%s) skipped once created less than %d hour ago", p.GetName(), p.GetId(), lifetime))
65-
63+
if time.Since(p.Created) < time.Duration(lifetimeHours)*time.Hour {
64+
fmt.Println(text.FgYellow.Sprintf("\tProject %s(%s) skipped once created less than %d hour ago", p.GetName(), p.GetId(), lifetimeHours))
6665
continue
6766
}
6867

@@ -92,21 +91,42 @@ func (c *Cleaner) Clean(ctx context.Context, lifetime int) error {
9291
c.deleteTeam(ctx, c.orgID, &t)
9392
}
9493

95-
return c.cleanOrphanResources(ctx, lifetime)
94+
c.cleanOrphanResources(ctx, lifetimeHours)
95+
return nil
9696
}
9797

98-
func (c *Cleaner) cleanOrphanResources(ctx context.Context, lifetime int) error {
98+
func (c *Cleaner) cleanOrphanResources(ctx context.Context, lifetimeHours int) {
9999
region := envOrDefault("GCP_CLEANUP_REGION", "europe-west1")
100100
subnet := envOrDefault("GCP_CLEANUP_SUBNET", "atlas-operator-e2e-test-subnet1")
101-
done, skipped, err := c.gcp.DeleteOrphanPrivateEndpoints(ctx, lifetime, region, subnet)
101+
vpcPrefix := envOrDefault("GCP_CLEANUP_VPC_NAME_PREFIX", "network-peering-gcp-1-vpc")
102+
103+
var done, skipped []string
104+
var errs []error
105+
106+
addResults := func(f func() ([]string, []string, []error)) {
107+
d, s, e := f()
108+
done = append(done, d...)
109+
skipped = append(skipped, s...)
110+
errs = append(errs, e...)
111+
}
112+
113+
addResults(func() ([]string, []string, []error) {
114+
return c.gcp.DeleteOrphanPrivateEndpoints(ctx, lifetimeHours, region, subnet)
115+
})
116+
117+
addResults(func() ([]string, []string, []error) {
118+
return c.gcp.DeleteOrphanVPCs(ctx, lifetimeHours, vpcPrefix)
119+
})
120+
102121
for _, doneMsg := range done {
103122
fmt.Println(text.FgGreen.Sprintf("%s", doneMsg))
104123
}
105124
for _, skippedMsg := range skipped {
106125
fmt.Println(text.FgYellow.Sprintf("\t%s", skippedMsg))
107126
}
108-
109-
return err
127+
for _, err := range errs {
128+
fmt.Println(text.FgRed.Sprintf(err.Error()))
129+
}
110130
}
111131

112132
func NewCleaner(aws *provider.AWS, gcp *provider.GCP, azure *provider.Azure) (*Cleaner, error) {

tools/clean/main.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,15 @@ func main() {
3636
return
3737
}
3838

39-
lifetime, err := strconv.Atoi(os.Getenv("PROJECT_LIFETIME"))
39+
lifetimeHours, err := strconv.Atoi(os.Getenv("PROJECT_LIFETIME"))
4040
if err != nil {
41+
err = fmt.Errorf("error parsing PROJECT_LIFETIME environment variable: %w", err)
4142
fmt.Println(text.FgRed.Sprintf(err.Error()))
4243

4344
return
4445
}
4546

46-
err = c.Clean(ctx, lifetime)
47+
err = c.Clean(ctx, lifetimeHours)
4748
if err != nil {
4849
fmt.Println(text.FgRed.Sprintf(err.Error()))
4950
}

tools/clean/provider/gcp.go

Lines changed: 105 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -102,60 +102,146 @@ func (gcp *GCP) DeletePrivateEndpoint(ctx context.Context, groupName, sAttachmen
102102
return nil
103103
}
104104

105-
func (gcp *GCP) DeleteOrphanPrivateEndpoints(ctx context.Context, lifetime int, region string, subnet string) ([]string, []string, error) {
105+
func (gcp *GCP) DeleteOrphanVPCs(ctx context.Context, lifetimeHours int, vpcNamePrefix string) ([]string, []string, []error) {
106+
vpcs := gcp.networkClient.List(ctx, &computepb.ListNetworksRequest{
107+
Project: gcp.projectID,
108+
})
109+
110+
var done, skipped []string
111+
var errs []error
112+
for {
113+
vpc, err := vpcs.Next()
114+
if errors.Is(err, iterator.Done) {
115+
break
116+
}
117+
if err != nil {
118+
errs = append(errs,
119+
fmt.Errorf("failed iterating VPC networks in project %v: %w", gcp.projectID, err),
120+
)
121+
continue
122+
}
123+
if !strings.HasPrefix(vpc.GetName(), vpcNamePrefix) {
124+
skipped = append(skipped,
125+
fmt.Sprintf("VPC %s skipped\n", vpc.GetName()),
126+
)
127+
continue
128+
}
129+
createdAt, err := asTime(vpc.GetCreationTimestamp())
130+
if err != nil {
131+
errs = append(errs,
132+
fmt.Errorf("failed parsing VPC creation timestamp %q: %w", vpc.GetCreationTimestamp(), err),
133+
)
134+
continue
135+
}
136+
if time.Since(createdAt) < time.Duration(lifetimeHours)*time.Hour {
137+
skipped = append(skipped,
138+
fmt.Sprintf("VPC %s skipped once created less than %d hours ago\n", vpc.GetName(), lifetimeHours),
139+
)
140+
continue
141+
}
142+
143+
op, err := gcp.networkClient.Delete(ctx, &computepb.DeleteNetworkRequest{
144+
Project: gcp.projectID,
145+
Network: vpc.GetName(),
146+
})
147+
if err != nil {
148+
errs = append(errs,
149+
fmt.Errorf("error deleting VPC %s: %w", vpc.GetName(), err),
150+
)
151+
continue
152+
}
153+
154+
err = op.Wait(ctx)
155+
if err != nil {
156+
errs = append(errs,
157+
fmt.Errorf("error waiting for deletion of VPC %s: %w", vpc.GetName(), err),
158+
)
159+
continue
160+
}
161+
done = append(done,
162+
fmt.Sprintf("Released orphan VPC %s\n", vpc.GetName()),
163+
)
164+
}
165+
166+
return done, skipped, errs
167+
}
168+
169+
func (gcp *GCP) DeleteOrphanPrivateEndpoints(ctx context.Context, lifetimeHours int, region string, subnet string) ([]string, []string, []error) {
106170
addresses := gcp.addressClient.List(ctx, &computepb.ListAddressesRequest{
107171
Project: gcp.projectID,
108172
Region: region,
109173
})
110-
done := []string{}
111-
skipped := []string{}
174+
var done, skipped []string
175+
var errs []error
112176
for {
113177
addr, err := addresses.Next()
114178
if errors.Is(err, iterator.Done) {
115179
break
116180
}
117181
if err != nil {
118-
return nil, nil, fmt.Errorf("failed iterating addresses in project %v region %v: %w",
119-
gcp.projectID, region, err)
182+
errs = append(errs,
183+
fmt.Errorf("failed iterating addresses in project %v region %v: %w", gcp.projectID, region, err),
184+
)
185+
continue
120186
}
121187
suffix := fmt.Sprintf("subnetworks/%s", subnet)
122188
if !strings.HasSuffix(addr.GetSubnetwork(), suffix) {
123189
skipped = append(skipped,
124-
fmt.Sprintf("Address %s(%s) skipped, not in %s\n", addr.GetName(), addr.GetAddress(), subnet))
190+
fmt.Sprintf("Address %s(%s) skipped, not in %s\n", addr.GetName(), addr.GetAddress(), subnet),
191+
)
125192
continue
126193
}
127194
createdAt, err := asTime(addr.GetCreationTimestamp())
128195
if err != nil {
129-
return nil, nil, fmt.Errorf("failed parsing Address creation timestamp %q: %w",
130-
addr.GetCreationTimestamp(), err)
196+
errs = append(errs,
197+
fmt.Errorf(
198+
"failed parsing Address %s(%s) creation timestamp %q: %w",
199+
addr.GetCreationTimestamp(), addr.GetName(), addr.GetAddress(), err,
200+
),
201+
)
202+
continue
131203
}
132-
if time.Since(createdAt) < time.Duration(lifetime)*time.Hour {
133-
skipped = append(skipped, fmt.Sprintf("Address %s(%s) skipped once created less than %d hours ago\n",
134-
addr.GetName(), addr.GetAddress(), lifetime))
204+
if time.Since(createdAt) < time.Duration(lifetimeHours)*time.Hour {
205+
skipped = append(skipped,
206+
fmt.Sprintf(
207+
"Address %s(%s) skipped once created less than %d hours ago\n",
208+
addr.GetName(), addr.GetAddress(), lifetimeHours,
209+
),
210+
)
211+
continue
135212
}
136213
frName, err := expectForwardingRule(addr.GetUsers())
137214
if err != nil {
138-
return nil, nil, err
215+
errs = append(errs, err)
216+
continue
139217
}
140218

141219
if frName != "" {
142-
if err := gcp.deleteForwardingRule(ctx, frName, region); err != nil {
143-
return nil, nil, fmt.Errorf("failed deleting Forwarding Rule %q in region %q: %w", region, frName, err)
220+
err := gcp.deleteForwardingRule(ctx, frName, region)
221+
if err != nil {
222+
errs = append(errs,
223+
fmt.Errorf("failed deleting Forwarding Rule %q in region %q: %w", region, frName, err),
224+
)
225+
continue
144226
}
145-
done = append(done, fmt.Sprintf("Deleted Forwarding Rule %s for %s\n",
146-
frName, addr.GetAddress()))
227+
done = append(done,
228+
fmt.Sprintf("Deleted Forwarding Rule %s for %s\n", frName, addr.GetAddress()),
229+
)
147230
} else {
148231
skipped = append(skipped,
149232
fmt.Sprintf("No forwarding rule using Address %s(%s)", addr.GetName(), addr.GetAddress()))
150233
}
151234
if err := gcp.deleteIPAddress(ctx, addr.GetName(), region); err != nil {
152-
return nil, nil, fmt.Errorf("error deleting Address %s(%s) in region %q: %w",
153-
region, addr.GetName(), addr.GetAddress(), err)
235+
errs = append(errs,
236+
fmt.Errorf("error deleting Address %s(%s) in region %q: %w",
237+
region, addr.GetName(), addr.GetAddress(), err),
238+
)
239+
continue
154240
}
155241
done = append(done, fmt.Sprintf("Released orphan Address %s(%s)\n", addr.GetName(), addr.GetAddress()))
156242
}
157243

158-
return done, skipped, nil
244+
return done, skipped, errs
159245
}
160246

161247
func asTime(rfc3339time string) (time.Time, error) {

0 commit comments

Comments
 (0)