Skip to content

Commit 0fc0c04

Browse files
cpanatoprksu
authored andcommitted
janitor: add code to clean the DO account for capdo (kubernetes-sigs#213)
1 parent 5da0fad commit 0fc0c04

File tree

5 files changed

+185
-9
lines changed

5 files changed

+185
-9
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,3 +507,7 @@ clean-examples: ## Remove all the temporary files generated in the examples fold
507507
rm -rf examples/_out/
508508
rm -f examples/core-components/*-components.yaml
509509
rm -f examples/provider-components/provider-components-*.yaml
510+
511+
.PHONY: do-janitor
512+
do-janitor: ## Cleanup old resources in the DO account
513+
go run hack/do-janitor/do-janitor.go

hack/do-janitor/do-janitor.go

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package main
18+
19+
import (
20+
"context"
21+
"log"
22+
"os"
23+
"time"
24+
25+
"github.com/digitalocean/godo"
26+
)
27+
28+
const timeToCleanInHours = 12
29+
30+
func main() {
31+
log.Println("Starting DO Janitor")
32+
token := os.Getenv("DIGITALOCEAN_ACCESS_TOKEN")
33+
if token == "" {
34+
log.Fatal("missing DO token")
35+
}
36+
37+
ctx := context.Background()
38+
client := godo.NewFromToken(token)
39+
40+
droplets, err := dropletList(ctx, client)
41+
if err != nil {
42+
log.Fatalf("fail to list droplets: %+v", err.Error())
43+
}
44+
45+
for _, droplet := range droplets {
46+
dropletCreated, err := time.Parse(time.RFC3339, droplet.Created)
47+
if err != nil {
48+
log.Fatalf("failt parsing time: %+v", err.Error())
49+
}
50+
51+
hours := time.Since(dropletCreated).Hours()
52+
if hours >= timeToCleanInHours {
53+
log.Printf("%s is older than %d hours will terminate\n", droplet.Name, timeToCleanInHours)
54+
_, err := client.Droplets.Delete(ctx, droplet.ID)
55+
if err != nil {
56+
log.Printf("fail to delete droplet %s: %+v\n", droplet.Name, err.Error())
57+
continue
58+
}
59+
60+
log.Printf("droplet %s terminated\n", droplet.Name)
61+
}
62+
}
63+
64+
lbs, err := lbList(ctx, client)
65+
if err != nil {
66+
log.Fatalf("fail to failed list LoadBalancer: %+v", err.Error())
67+
}
68+
69+
for _, lb := range lbs {
70+
lbCreated, err := time.Parse(time.RFC3339, lb.Created)
71+
if err != nil {
72+
log.Fatalf("failt parsing time: %+v", err.Error())
73+
}
74+
75+
hours := time.Since(lbCreated).Hours()
76+
if hours >= timeToCleanInHours {
77+
log.Printf("%s is older than %d hours will terminate\n", lb.Name, timeToCleanInHours)
78+
_, err := client.LoadBalancers.Delete(ctx, lb.ID)
79+
if err != nil {
80+
log.Printf("fail to delete droplet %s: %+v\n", lb.Name, err.Error())
81+
continue
82+
}
83+
84+
log.Printf("droplet %s terminated\n", lb.Name)
85+
}
86+
}
87+
88+
log.Println("Done DO Janitor")
89+
os.Exit(0)
90+
}
91+
92+
func dropletList(ctx context.Context, client *godo.Client) ([]godo.Droplet, error) {
93+
// create a list to hold our droplets
94+
list := []godo.Droplet{}
95+
96+
// create options. initially, these will be blank
97+
opt := &godo.ListOptions{}
98+
for {
99+
droplets, resp, err := client.Droplets.List(ctx, opt)
100+
if err != nil {
101+
return nil, err
102+
}
103+
104+
list = append(list, droplets...)
105+
106+
if resp.Links == nil || resp.Links.IsLastPage() {
107+
break
108+
}
109+
110+
page, err := resp.Links.CurrentPage()
111+
if err != nil {
112+
return nil, err
113+
}
114+
115+
opt.Page = page + 1
116+
}
117+
118+
return list, nil
119+
}
120+
121+
func lbList(ctx context.Context, client *godo.Client) ([]godo.LoadBalancer, error) {
122+
list := []godo.LoadBalancer{}
123+
124+
opt := &godo.ListOptions{}
125+
for {
126+
lbs, resp, err := client.LoadBalancers.List(ctx, opt)
127+
if err != nil {
128+
return nil, err
129+
}
130+
131+
list = append(list, lbs...)
132+
133+
if resp.Links == nil || resp.Links.IsLastPage() {
134+
break
135+
}
136+
137+
page, err := resp.Links.CurrentPage()
138+
if err != nil {
139+
return nil, err
140+
}
141+
142+
opt.Page = page + 1
143+
}
144+
145+
return list, nil
146+
}

scripts/ci-janitor.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/bin/bash
2+
3+
# Copyright 2020 The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
################################################################################
18+
# usage: ci-janitor.sh
19+
# This program runs the cleanup do account
20+
################################################################################
21+
22+
set -o nounset
23+
set -o pipefail
24+
25+
export PATH=${PWD}/hack/tools/bin:${PATH}
26+
REPO_ROOT=$(git rev-parse --show-toplevel)
27+
28+
# shellcheck source=../hack/ensure-go.sh
29+
source "${REPO_ROOT}/hack/ensure-go.sh"
30+
31+
make do-janitor
32+
test_status="${?}"

test/e2e/clean_resources.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package e2e
1818

1919
import (
2020
"context"
21-
"net/http"
2221
"os"
2322
"strings"
2423

@@ -43,13 +42,10 @@ func CleanDOResources(clusterName string) error {
4342

4443
for _, droplet := range droplets {
4544
if strings.Contains(droplet.Name, clusterName) {
46-
resp, err := client.Droplets.Delete(ctx, droplet.ID)
45+
_, err := client.Droplets.Delete(ctx, droplet.ID)
4746
if err != nil {
4847
return errors.Wrapf(err, "failed delete droplet %d/%s", droplet.ID, droplet.Name)
4948
}
50-
if resp.StatusCode != http.StatusNoContent {
51-
return errors.Wrapf(err, "expected status code 204 got %d", resp.StatusCode)
52-
}
5349
}
5450
}
5551

@@ -60,13 +56,10 @@ func CleanDOResources(clusterName string) error {
6056

6157
for _, lb := range lbs {
6258
if strings.Contains(lb.Name, clusterName) {
63-
resp, err := client.LoadBalancers.Delete(ctx, lb.ID)
59+
_, err := client.LoadBalancers.Delete(ctx, lb.ID)
6460
if err != nil {
6561
return errors.Wrapf(err, "failed delete loadbalancer %s/%s", lb.ID, lb.Name)
6662
}
67-
if resp.StatusCode != http.StatusNoContent {
68-
return errors.Wrapf(err, "expected status code 204 got %d", resp.StatusCode)
69-
}
7063
}
7164
}
7265

test/e2e/common.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ func dumpSpecResourcesAndCleanup(ctx context.Context, specName string, clusterPr
8787
By(fmt.Sprintf("Making sure there is no leftover running for %s", cluster.Name))
8888
Expect(CleanDOResources(clusterName)).ShouldNot(HaveOccurred())
8989
}
90+
9091
cancelWatches()
9192
redactLogs()
9293
}

0 commit comments

Comments
 (0)