Skip to content

Commit

Permalink
Merge branch 'feat/scw-handle-orphan-flexible-ips' into 'main'
Browse files Browse the repository at this point in the history
feat(SCW): handle orphan flexible IPs

See merge request qovery/backend/pleco!122
  • Loading branch information
benjaminch committed Oct 21, 2024
2 parents 79ea7e9 + 8aa28fe commit 127d394
Show file tree
Hide file tree
Showing 14 changed files with 101 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Check out our Blog announcement of Pleco: https://www.qovery.com/blog/announceme
- [X] Detached volumes
- [X] S3 Buckets
- [X] Unused Security Groups
- [X] Orphan IPs
- [X] DIGITAL OCEAN
- [X] Kubernetes clusters
- [X] Database instances
Expand Down
4 changes: 2 additions & 2 deletions charts/pleco/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ name: pleco
description: Automatically removes Cloud managed services and Kubernetes resources based on tags with TTL
type: application
home: https://github.com/Qovery/pleco
version: 0.18.5
appVersion: 0.18.5
version: 0.19.0
appVersion: 0.19.0
icon: https://github.com/Qovery/pleco/raw/main/assets/pleco_logo.png
3 changes: 3 additions & 0 deletions charts/pleco/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ spec:
{{ if eq .Values.scwFeatures.sg true }}
- --enable-sg
{{ end }}
{{ if eq .Values.scwFeatures.orphanIp true } }
- --enable-orphan-ip
{{ end }}
{{- end }}

# GCP features
Expand Down
1 change: 1 addition & 0 deletions charts/pleco/values-scw.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ scwFeatures:
db: true
volume: true
sg: true
orphanIp: true

resources:
limits:
Expand Down
1 change: 1 addition & 0 deletions charts/pleco/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ scwFeatures:
db: false
volume: false
sg: false
orphanIp: false

doFeatures:
doRegions: [ ]
Expand Down
2 changes: 1 addition & 1 deletion cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ func init() {
}

func GetCurrentVersion() string {
return "0.18.5" // ci-version-check
return "0.19.0" // ci-version-check
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ require (
github.com/digitalocean/godo v1.108.0
github.com/minio/minio-go/v7 v7.0.66
github.com/mitchellh/go-homedir v1.1.0
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.30
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.0
github.com/spf13/viper v1.18.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6g
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22 h1:wJrcTdddKOI8TFxs8cemnhKP2EmKy3yfUKHj3ZdfzYo=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.30 h1:yoKAVkEVwAqbGbR8n87rHQ1dulL25rKloGadb3vm770=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.30/go.mod h1:sH0u6fq6x4R5M7WxkoQFY/o7UaiItec0o1LinLCJNq8=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
Expand Down
1 change: 1 addition & 0 deletions pkg/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ func startScaleway(cmd *cobra.Command, interval int64, dryRun bool, disableTTLCh
EnableLB: getCmdBool(cmd, "enable-lb"),
EnableVolume: getCmdBool(cmd, "enable-volume"),
EnableSG: getCmdBool(cmd, "enable-sg"),
EnableOrphanIP: getCmdBool(cmd, "enable-orphan-ip"),
}
scaleway.RunPlecoScaleway(zones, interval, wg, scalewayOptions)
wg.Done()
Expand Down
1 change: 1 addition & 0 deletions pkg/common/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func initScalewayFlags(startCmd *cobra.Command) {
startCmd.Flags().BoolP("enable-lb", "l", false, "Enable load balancers watch")
startCmd.Flags().BoolP("enable-volume", "b", false, "Enable volumes watch")
startCmd.Flags().BoolP("enable-sg", "p", false, "Enable security groups watch")
startCmd.Flags().BoolP("enable-orphan-ip", "", false, "Enable orphan IPs watch")

}

Expand Down
6 changes: 4 additions & 2 deletions pkg/gcp/object_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,16 @@ func DeleteExpiredBuckets(sessions GCPSessions, options GCPOptions) {
break
}

err = sessions.Bucket.Bucket(bucket.Name).Object(object.Name).Delete(ctx)
ctxDeleteObject, _ := context.WithTimeout(context.Background(), time.Second*15)
err = sessions.Bucket.Bucket(bucket.Name).Object(object.Name).Delete(ctxDeleteObject)
if err != nil {
log.Error(fmt.Sprintf("Error deleting object `%s` from bucket `%s`, error: %s", object.Name, bucket.Name, err))
}
}

log.Info(fmt.Sprintf("Deleting bucket `%s` created at `%s` UTC (TTL `{%d}` seconds)", bucket.Name, bucket.Created.UTC(), ttl))
if err := sessions.Bucket.Bucket(bucket.Name).Delete(ctx); err != nil {
ctxDeleteBucket, _ := context.WithTimeout(context.Background(), time.Second*60)
if err := sessions.Bucket.Bucket(bucket.Name).Delete(ctxDeleteBucket); err != nil {
log.Error(fmt.Sprintf("Error deleting bucket `%s`, error: %s", bucket.Name, err))
}
}
Expand Down
13 changes: 11 additions & 2 deletions pkg/scaleway/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ type ScalewayOptions struct {
EnableLB bool
EnableVolume bool
EnableSG bool
EnableOrphanIP bool
}

type ScalewaySessions struct {
Cluster *k8s.API
Database *rdb.API
Namespace *registry.API
LoadBalancer *lb.ZonedAPI
Volume *instance.API
Instance *instance.API
Bucket *minio.Client
SG *instance.API
}
Expand Down Expand Up @@ -84,7 +85,7 @@ func runPlecoInZone(zone string, interval int64, wg *sync.WaitGroup, options Sca
}

if options.EnableVolume {
sessions.Volume = instance.NewAPI(currentSession)
sessions.Instance = instance.NewAPI(currentSession)

listServiceToCheckStatus = append(listServiceToCheckStatus, DeleteExpiredVolumes)
}
Expand All @@ -102,6 +103,14 @@ func runPlecoInZone(zone string, interval int64, wg *sync.WaitGroup, options Sca
listServiceToCheckStatus = append(listServiceToCheckStatus, DeleteEmptyContainerRegistries)
}

if options.EnableOrphanIP {
if sessions.LoadBalancer == nil {
sessions.LoadBalancer = lb.NewZonedAPI(currentSession)
}

listServiceToCheckStatus = append(listServiceToCheckStatus, DeleteOrphanIPAddresses)
}

if options.IsDestroyingCommand {
for _, check := range listServiceToCheckStatus {
check(sessions, options)
Expand Down
70 changes: 70 additions & 0 deletions pkg/scaleway/static_ip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package scaleway

import (
"github.com/Qovery/pleco/pkg/common"
"github.com/scaleway/scaleway-sdk-go/api/lb/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
log "github.com/sirupsen/logrus"
)

type ScalewayIP struct {
ID string
Address string
}

func DeleteOrphanIPAddresses(sessions ScalewaySessions, options ScalewayOptions) {
orphanIPs, _ := getOrphanIPAddresses(sessions.LoadBalancer, options)

count, start := common.ElemToDeleteFormattedInfos("orphan IP address", len(orphanIPs), options.Zone, true)

log.Info(count)

if options.DryRun || len(orphanIPs) == 0 {
return
}

log.Info(start)

for _, orphanIP := range orphanIPs {
log.Info("Deleting orphan IP address: ", orphanIP.Address)
if err := sessions.LoadBalancer.ReleaseIP(&lb.ZonedAPIReleaseIPRequest{
Zone: scw.Zone(options.Zone),
IPID: orphanIP.ID,
}); err != nil {
log.Errorf("Error deleting IP %s: %v", orphanIP.Address, err)
}
}
}

func getOrphanIPAddresses(lbAPI *lb.ZonedAPI, options ScalewayOptions) ([]ScalewayIP, error) {
// List all IPs
orphanIPs := make([]ScalewayIP, 0)
var page int32 = 1
var itemsPerPage uint32 = 100

for {
ipsResponse, err := lbAPI.ListIPs(&lb.ZonedAPIListIPsRequest{
Page: &page,
PageSize: &itemsPerPage,
Zone: scw.Zone(options.Zone),
})
if err != nil {
log.Fatalf("Error listing IPs: %v", err)
return nil, err
}

for _, ip := range ipsResponse.IPs {
if ip.LBID == nil { // Check if IP is not attached to any LB
orphanIPs = append(orphanIPs, ScalewayIP{ID: ip.ID, Address: ip.IPAddress})
}
}

if ipsResponse.TotalCount <= uint32(page)*itemsPerPage {
break
}

page += 1
}

return orphanIPs, nil
}
4 changes: 2 additions & 2 deletions pkg/scaleway/volumes_root.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type ScalewayVolume struct {
}

func DeleteExpiredVolumes(sessions ScalewaySessions, options ScalewayOptions) {
expiredVolumes := getDetachedVolumes(sessions.Volume, &options)
expiredVolumes := getDetachedVolumes(sessions.Instance, &options)

count, start := common.ElemToDeleteFormattedInfos(fmt.Sprintf("detached (%d hours delay) volume", volumeTimeout()), len(expiredVolumes), options.Zone, true)

Expand All @@ -31,7 +31,7 @@ func DeleteExpiredVolumes(sessions ScalewaySessions, options ScalewayOptions) {
log.Info(start)

for _, expiredVolume := range expiredVolumes {
deleteVolume(sessions.Volume, expiredVolume, options.Zone)
deleteVolume(sessions.Instance, expiredVolume, options.Zone)
}
}

Expand Down

0 comments on commit 127d394

Please sign in to comment.