Skip to content
Open
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
be21a5d
add new tags
nmarukovich Feb 11, 2023
2af7b96
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Feb 13, 2023
01ac6b1
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Feb 21, 2023
47ca4fc
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Feb 22, 2023
22cccea
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Feb 24, 2023
781cf55
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Feb 27, 2023
9d210cd
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Mar 3, 2023
a21d84d
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Mar 3, 2023
0943a44
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Mar 5, 2023
61da77c
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Mar 13, 2023
a2d7deb
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Mar 22, 2023
651f35a
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Mar 30, 2023
0978f65
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Mar 31, 2023
da02386
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Apr 4, 2023
3795e3b
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Apr 5, 2023
f91a4e1
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Apr 7, 2023
a436d73
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich May 15, 2023
6d9005c
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich May 19, 2023
280afc4
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich May 26, 2023
119b6c4
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich May 30, 2023
289e69e
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Jun 15, 2023
141d0ae
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Jul 26, 2023
51f4bf2
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Aug 1, 2023
c2e07ed
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Aug 7, 2023
78d6471
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Oct 9, 2023
204bbd1
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Oct 17, 2023
f279ff9
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Nov 13, 2023
966f3ae
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Dec 23, 2023
7ccd165
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Jan 15, 2024
294683d
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Mar 3, 2024
9aecb73
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Jul 25, 2024
733d7d6
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Aug 14, 2024
aecf1f3
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Aug 23, 2024
66c150b
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Sep 10, 2024
79e3310
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Sep 12, 2024
02736d8
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Sep 17, 2024
09a04a6
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Sep 18, 2024
735fc2b
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Oct 13, 2024
c04917c
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Nov 11, 2024
2a14385
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Jan 20, 2025
27bdb21
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Apr 15, 2025
728c9e3
Merge branch 'master' of github.com:Percona-Lab/jenkins-pipelines
nmarukovich Oct 9, 2025
236c0e0
fix fw rules deletion
nmarukovich Oct 28, 2025
b352d8f
fix PR
nmarukovich Oct 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 163 additions & 42 deletions cloud/gcp-functions/cmd/orphanedResources.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package orphanedResources

import (
"context"
"fmt"
"log"
"net/http"
"os"
Expand All @@ -11,71 +10,193 @@ import (
"google.golang.org/api/compute/v1"
)

func CleanOrphanedResources(w http.ResponseWriter, r *http.Request) {
func matchesFirewallPattern(name string) bool {
if strings.HasPrefix(name, "gke-jen") || strings.HasPrefix(name, "k8s-") {
return true
}
return false
}

func tagUsed(usedTags map[string]struct{}, tags []string) bool {
for _, t := range tags {
if _, ok := usedTags[t]; ok {
return true
}
}
return false
}

// CleanOrphanedResources deletes orphan TargetPools (+ related ForwardingRules/Addresses/firewalls)
// and also deletes dangling firewall rules whose target tags are unused.
func CleanOrphanedResources(w http.ResponseWriter, r *http.Request) {
ctx := context.Background()
computeService, err := compute.NewService(ctx)
if err != nil {
log.Fatal("Error: create service", err)
log.Fatalf("Error creating compute service: %v", err)
}

project := os.Getenv("GCP_DEV_PROJECT")
targetPoolAggregatedList, err := computeService.TargetPools.AggregatedList(project).Do()
if project == "" {
log.Fatalf("GCP_DEV_PROJECT is not set")
}

// 1) Fetch firewalls (index by name)
fwList, err := computeService.Firewalls.List(project).Context(ctx).Do()
if err != nil {
log.Fatal("Error: get targetPoolAggregatedList", err)
log.Fatalf("Error listing firewalls: %v", err)
}
firewallByName := make(map[string]*compute.Firewall, len(fwList.Items))
for _, fw := range fwList.Items {
firewallByName[fw.Name] = fw
}

toDelete := false
for _, targetPoolList := range targetPoolAggregatedList.Items {
for _, targetPoolItem := range targetPoolList.TargetPools {
region := strings.Split(targetPoolItem.Region, "/")[8]

if len(targetPoolItem.Instances) > 0 {
instanceName := strings.Split(targetPoolItem.Instances[0], "/")[10]
zone := strings.Split(targetPoolItem.Instances[0], "/")[8]
_, err := computeService.Instances.Get(project, zone, instanceName).Context(ctx).Do()
if err != nil && strings.Contains(err.Error(), "404") {
toDelete = true
// 2) Build a set of all in-use tags from all instances
usedTags := make(map[string]struct{}, 1024)
instAgg, err := computeService.Instances.AggregatedList(project).Context(ctx).Do()
if err != nil {
log.Printf("Error aggregating instances (building usedTags): %v", err)
}
if instAgg != nil {
for _, il := range instAgg.Items {
for _, ins := range il.Instances {
for _, t := range ins.Tags.Items {
usedTags[t] = struct{}{}
}
}
}
}
log.Printf("Collected %d used tags", len(usedTags))

if len(targetPoolItem.Instances) == 0 || toDelete == true {
// 3) Fetch aggregated TargetPools
tpAgg, err := computeService.TargetPools.AggregatedList(project).Context(ctx).Do()
if err != nil {
log.Fatalf("Error getting target pool aggregated list: %v", err)
}

// Firewall-rule deleting
firewallRuleId := fmt.Sprintf("k8s-fw-%s", targetPoolItem.Name)
deletedAny := false
deletedFW := make(map[string]struct{}) // remember deleted firewall names to avoid double-delete later

respFirewall, err := computeService.Firewalls.Delete(project, firewallRuleId).Context(ctx).Do()
if err != nil {
log.Printf("We can't delete firewallRuleId: %v", err)
} else {
log.Printf("firewall-rule deleted: k8s-fw- %s was deleted with status %s\n", targetPoolItem.Name, respFirewall.Status)
}
// 4) Delete orphan TargetPools and their related resources and related firewalls if tags unused
for _, tpList := range tpAgg.Items {
for _, tp := range tpList.TargetPools {
region := strings.Split(tp.Region, "/")[8]

// Forwarding-rule deleting
respFWRule, err := computeService.ForwardingRules.Delete(project, region, targetPoolItem.Name).Context(ctx).Do()
if err != nil {
log.Printf("We can't delete Forwarding-rule: %v", err)
} else {
log.Printf("forwarding-rule deleted: %s was deleted with status %s\n", targetPoolItem.Name, respFWRule.Status)
toDelete := false
// orphan if no instances OR the first instance ref returns 404
if len(tp.Instances) == 0 {
toDelete = true
} else {
instanceName := strings.Split(tp.Instances[0], "/")[10]
zone := strings.Split(tp.Instances[0], "/")[8]

_, gerr := computeService.Instances.Get(project, zone, instanceName).Context(ctx).Do()
if gerr != nil && strings.Contains(gerr.Error(), "404") {
toDelete = true
}
if gerr != nil && !strings.Contains(gerr.Error(), "404") {
log.Printf("Error checking instance %s in %s: %v", instanceName, zone, gerr)
continue
}
}

// Address deleting
respAdd, err := computeService.Addresses.Delete(project, region, targetPoolItem.Name).Context(ctx).Do()
if err != nil {
log.Printf("We can't delete Address: %v", err)
} else {
log.Printf("address deleted: %s was deleted with status %s\n", targetPoolItem.Name, respAdd.Status)
if !toDelete {
continue
}

// Build candidate firewalls to delete that are "related" to this TP
var candidates []string
for name, fw := range firewallByName {
if fw == nil {
continue
}
if strings.Contains(name, tp.Name) || matchesFirewallPattern(name) {
if len(fw.TargetTags) == 0 {
candidates = append(candidates, name)
continue
}
// only consider if FW tags "look related" to this TP
related := false
for _, tag := range fw.TargetTags {
if strings.Contains(tag, tp.Name) || matchesFirewallPattern(tag) {
related = true
break
}
}
if related {
candidates = append(candidates, name)
}
}
}

// Target pool deleting
respTP, err := computeService.TargetPools.Delete(project, region, targetPoolItem.Name).Context(ctx).Do()
if err != nil {
log.Printf("We can't delete target pool: %v", err)
// Delete candidate firewalls when tags are NOT used
for _, fname := range candidates {
fw := firewallByName[fname]
if fw == nil {
continue
}
if len(fw.TargetTags) == 0 || !tagUsed(usedTags, fw.TargetTags) {
if _, derr := computeService.Firewalls.Delete(project, fname).Context(ctx).Do(); derr != nil {
log.Printf("Failed to delete firewall %s: %v", fname, derr)
} else {
deletedAny = true
deletedFW[fname] = struct{}{}
firewallByName[fname] = nil
}
} else {
log.Printf("Target-pool deleted: %s was deleted with status %s\n", targetPoolItem.Name, respTP.Status)
log.Printf("Skipping firewall %s: target tags are still in use\n", fname)
}
}

// Delete ForwardingRule
if _, err := computeService.ForwardingRules.Delete(project, region, tp.Name).Context(ctx).Do(); err != nil {
log.Printf("Can't delete Forwarding rule %s in %s: %v", tp.Name, region, err)
} else {
log.Printf("Forwarding-rule deleted: %s\n", tp.Name)
deletedAny = true
}

// Delete Address
if _, err := computeService.Addresses.Delete(project, region, tp.Name).Context(ctx).Do(); err != nil {
log.Printf("Can't delete Address %s in %s: %v", tp.Name, region, err)
} else {
log.Printf("Address deleted: %s\n", tp.Name)
deletedAny = true
}

// Delete the TargetPool
if _, err := computeService.TargetPools.Delete(project, region, tp.Name).Context(ctx).Do(); err != nil {
log.Printf("Can't delete target pool %s in %s: %v", tp.Name, region, err)
} else {
log.Printf("Target-pool deleted: %s\n", tp.Name)
deletedAny = true
}
}
}

// 5) Delete any remaining dangling firewalls
// that match our patterns and have unused tags. This catches cases with no orphan TP trigger.
for name, fw := range firewallByName {
if fw == nil {
continue
}
if !matchesFirewallPattern(name) {
continue
}
// no tags -> dangling
if len(fw.TargetTags) == 0 || !tagUsed(usedTags, fw.TargetTags) {
if _, derr := computeService.Firewalls.Delete(project, name).Context(ctx).Do(); derr != nil {
log.Printf("Failed to delete dangling firewall %s: %v", name, derr)
} else {
log.Printf("Dangling firewall %s deleted\n", name)
deletedAny = true
firewallByName[name] = nil
}
}
}

if !deletedAny {
log.Println("No orphaned resources found or deleted")
}

w.WriteHeader(http.StatusOK)
}