Skip to content

Commit a9c23e2

Browse files
authored
feat: cleanup deployment (#5)
Closes #4.
1 parent 5dc6af9 commit a9c23e2

File tree

13 files changed

+544
-36
lines changed

13 files changed

+544
-36
lines changed

pkg/cmd/cleanupdeployment.go

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package cmd
2+
3+
import (
4+
"bufio"
5+
"context"
6+
"fmt"
7+
"os"
8+
"strings"
9+
10+
"github.com/SwissDataScienceCenter/renku-dev-utils/pkg/github"
11+
"github.com/SwissDataScienceCenter/renku-dev-utils/pkg/helm"
12+
"github.com/SwissDataScienceCenter/renku-dev-utils/pkg/k8s"
13+
ns "github.com/SwissDataScienceCenter/renku-dev-utils/pkg/namespace"
14+
"github.com/spf13/cobra"
15+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16+
)
17+
18+
var cleanupDeploymentCmd = &cobra.Command{
19+
Use: "cleanup-deployment",
20+
Short: "Cleanup a renku deployment",
21+
Run: cleanupDeployment,
22+
}
23+
24+
func cleanupDeployment(cmd *cobra.Command, args []string) {
25+
ctx := context.Background()
26+
27+
if namespace == "" {
28+
cli, err := github.NewGitHubCLI("")
29+
if err != nil {
30+
fmt.Println(err)
31+
os.Exit(1)
32+
}
33+
namespace, err = ns.FindCurrentNamespace(ctx, cli)
34+
if err != nil {
35+
fmt.Println(err)
36+
os.Exit(1)
37+
}
38+
}
39+
40+
clients, err := k8s.GetClientset()
41+
if err != nil {
42+
fmt.Println(err)
43+
os.Exit(1)
44+
}
45+
46+
client, err := k8s.GetDynamicClient()
47+
if err != nil {
48+
fmt.Println(err)
49+
os.Exit(1)
50+
}
51+
52+
// Ask for confirmation
53+
fmt.Printf("This command will perform the following actions in the namespace '%s':\n", namespace)
54+
fmt.Println(" 1. Delete all sessions")
55+
fmt.Println(" 2. Uninstall all helm releases")
56+
fmt.Println(" 3. Delete all jobs")
57+
fmt.Println(" 4. Delete all PVCs")
58+
fmt.Println(" 5. Forcibly delete all sessions")
59+
if deleteNamespace {
60+
fmt.Printf(" 6. Delete the namespace '%s'\n", namespace)
61+
}
62+
proceed, err := askForConfirmation("Proceed?")
63+
if err != nil {
64+
fmt.Println(err)
65+
os.Exit(1)
66+
}
67+
if !proceed {
68+
os.Exit(0)
69+
}
70+
71+
// 1. Delete all sessions
72+
fmt.Println("1. Delete all sessions")
73+
err = k8s.DeleteAllSessions(ctx, client, namespace, k8s.DeleteAllSessionsOptions{})
74+
if err != nil {
75+
fmt.Println(err)
76+
os.Exit(1)
77+
}
78+
79+
// 2. Uninstall all helm releases
80+
fmt.Println("2. Uninstall all helm releases")
81+
helm, err := helm.NewHelmCLI("")
82+
if err != nil {
83+
fmt.Println(err)
84+
os.Exit(1)
85+
}
86+
err = helm.UninstallAllReleases(ctx, namespace)
87+
if err != nil {
88+
fmt.Println(err)
89+
os.Exit(1)
90+
}
91+
92+
// 3. Delete all jobs
93+
fmt.Println("3. Delete all jobs")
94+
propagation := metav1.DeletePropagationForeground
95+
err = clients.BatchV1().Jobs(namespace).DeleteCollection(ctx, metav1.DeleteOptions{PropagationPolicy: &propagation}, metav1.ListOptions{})
96+
if err != nil {
97+
fmt.Println(err)
98+
os.Exit(1)
99+
}
100+
101+
// 4. Delete all PVCs
102+
fmt.Println("4. Delete all PVCs")
103+
err = clients.CoreV1().PersistentVolumeClaims(namespace).DeleteCollection(ctx, metav1.DeleteOptions{PropagationPolicy: &propagation}, metav1.ListOptions{})
104+
if err != nil {
105+
fmt.Println(err)
106+
os.Exit(1)
107+
}
108+
109+
// 5. Forcibly delete all sessions
110+
fmt.Println("5. Forcibly delete all sessions")
111+
err = k8s.ForciblyDeleteAllSessions(ctx, client, namespace, k8s.DeleteAllSessionsOptions{})
112+
if err != nil {
113+
fmt.Println(err)
114+
os.Exit(1)
115+
}
116+
117+
// 6. Delete the namespace
118+
if deleteNamespace {
119+
fmt.Printf("6. Delete the namespace '%s'\n", namespace)
120+
err = clients.CoreV1().Namespaces().Delete(ctx, namespace, metav1.DeleteOptions{PropagationPolicy: &propagation})
121+
if err != nil {
122+
fmt.Println(err)
123+
os.Exit(1)
124+
}
125+
}
126+
}
127+
128+
func init() {
129+
cleanupDeploymentCmd.Flags().StringVarP(&namespace, "namespace", "n", "", "k8s namespace")
130+
cleanupDeploymentCmd.Flags().BoolVar(&deleteNamespace, "delete-namespace", false, "if set, the namespace will be deleted")
131+
}
132+
133+
func askForConfirmation(question string) (response bool, err error) {
134+
reader := bufio.NewReader(os.Stdin)
135+
fmt.Printf("%s (yes/no): ", question)
136+
res, err := reader.ReadString('\n')
137+
if err != nil {
138+
return false, err
139+
}
140+
res = strings.ToLower(strings.TrimSpace(res))
141+
if res == "yes" {
142+
return true, nil
143+
} else if res == "no" {
144+
return false, nil
145+
}
146+
return false, fmt.Errorf("Invalid answer, aborting.")
147+
}

pkg/cmd/copykeycloakadminpassword.go

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,12 @@ import (
77

88
"github.com/SwissDataScienceCenter/renku-dev-utils/pkg/github"
99
"github.com/SwissDataScienceCenter/renku-dev-utils/pkg/k8s"
10+
ns "github.com/SwissDataScienceCenter/renku-dev-utils/pkg/namespace"
1011
"github.com/spf13/cobra"
1112
"golang.design/x/clipboard"
12-
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1314
)
1415

15-
// Flags
16-
17-
var namespace string
18-
var secretName string
19-
var secretKey string
20-
2116
var copyKeycloakAdminPasswordCmd = &cobra.Command{
2217
Use: "copy-keycloak-admin-password",
2318
Aliases: []string{"ckap"},
@@ -34,30 +29,11 @@ func runCopyKeycloakAdminPassword(cmd *cobra.Command, args []string) {
3429
fmt.Println(err)
3530
os.Exit(1)
3631
}
37-
38-
repo, err := cli.GetCurrentRepository()
39-
if err != nil {
40-
fmt.Println(err)
41-
os.Exit(1)
42-
}
43-
fmt.Printf("Repo: %s", repo)
44-
fmt.Println()
45-
46-
prNumber, err := cli.GetCurrentPullRequest()
47-
if err != nil {
48-
fmt.Println(err)
49-
os.Exit(1)
50-
}
51-
fmt.Printf("Pull request: %d", prNumber)
52-
fmt.Println()
53-
54-
namespace, err = github.DeriveK8sNamespace(repo, prNumber)
32+
namespace, err = ns.FindCurrentNamespace(ctx, cli)
5533
if err != nil {
5634
fmt.Println(err)
5735
os.Exit(1)
5836
}
59-
fmt.Printf("Derived namespace: %s", namespace)
60-
fmt.Println()
6137
}
6238

6339
clients, err := k8s.GetClientset()
@@ -66,7 +42,7 @@ func runCopyKeycloakAdminPassword(cmd *cobra.Command, args []string) {
6642
os.Exit(1)
6743
}
6844

69-
secret, err := clients.CoreV1().Secrets(namespace).Get(ctx, secretName, v1.GetOptions{})
45+
secret, err := clients.CoreV1().Secrets(namespace).Get(ctx, secretName, metav1.GetOptions{})
7046
if err != nil {
7147
fmt.Println(err)
7248
os.Exit(1)

pkg/cmd/root.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ import (
66
"github.com/spf13/cobra"
77
)
88

9+
// Flags
10+
11+
var deleteNamespace bool
12+
var namespace string
13+
var secretName string
14+
var secretKey string
15+
916
var rootCmd = &cobra.Command{
1017
Use: "rdu",
1118
Short: "renku-dev-utils is a dev utility CLI",
@@ -21,6 +28,7 @@ func runRoot(cmd *cobra.Command, args []string) error {
2128
}
2229

2330
func init() {
31+
rootCmd.AddCommand(cleanupDeploymentCmd)
2432
rootCmd.AddCommand(copyKeycloakAdminPasswordCmd)
2533
rootCmd.AddCommand(versionCmd)
2634
}

pkg/github/cli.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package github
22

33
import (
4+
"context"
45
"fmt"
56
"os/exec"
67
)
@@ -24,7 +25,7 @@ func NewGitHubCLI(gh string) (*GitHubCLI, error) {
2425
return &GitHubCLI{gh: gh}, nil
2526
}
2627

27-
func (cli *GitHubCLI) RunCmd(arg ...string) ([]byte, error) {
28-
cmd := exec.Command(cli.gh, arg...)
28+
func (cli *GitHubCLI) RunCmd(ctx context.Context, arg ...string) ([]byte, error) {
29+
cmd := exec.CommandContext(ctx, cli.gh, arg...)
2930
return cmd.Output()
3031
}

pkg/github/pullrequest.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package github
22

3-
import "encoding/json"
3+
import (
4+
"context"
5+
"encoding/json"
6+
)
47

5-
func (cli *GitHubCLI) GetCurrentPullRequest() (int, error) {
6-
out, err := cli.RunCmd("pr", "view", "--json", "number")
8+
func (cli *GitHubCLI) GetCurrentPullRequest(ctx context.Context) (int, error) {
9+
out, err := cli.RunCmd(ctx, "pr", "view", "--json", "number")
710
if err != nil {
811
return 0, err
912
}

pkg/github/repository.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package github
22

3-
import "encoding/json"
3+
import (
4+
"context"
5+
"encoding/json"
6+
)
47

5-
func (cli *GitHubCLI) GetCurrentRepository() (string, error) {
6-
out, err := cli.RunCmd("repo", "view", "--json", "nameWithOwner")
8+
func (cli *GitHubCLI) GetCurrentRepository(ctx context.Context) (string, error) {
9+
out, err := cli.RunCmd(ctx, "repo", "view", "--json", "nameWithOwner")
710
if err != nil {
811
return "", err
912
}

pkg/helm/cli.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package helm
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os/exec"
7+
)
8+
9+
type HelmCLI struct {
10+
helm string
11+
}
12+
13+
func NewHelmCLI(helm string) (cli *HelmCLI, err error) {
14+
if helm == "" {
15+
helm = "helm"
16+
}
17+
18+
path, err := exec.LookPath(helm)
19+
if err != nil {
20+
return nil, err
21+
}
22+
23+
fmt.Printf("Found Helm CLI: %s", path)
24+
fmt.Println()
25+
return &HelmCLI{helm: helm}, nil
26+
}
27+
28+
func (cli *HelmCLI) RunCmd(ctx context.Context, arg ...string) ([]byte, error) {
29+
cmd := exec.CommandContext(ctx, cli.helm, arg...)
30+
return cmd.Output()
31+
}

pkg/helm/release.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package helm
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
)
8+
9+
func (cli *HelmCLI) ListReleases(ctx context.Context, namespace string) (releases []string, err error) {
10+
out, err := cli.RunCmd(ctx, "list", "--namespace", namespace, "--all", "--output", "json")
11+
if err != nil {
12+
return nil, err
13+
}
14+
15+
var res []helmListOutput
16+
err = json.Unmarshal(out, &res)
17+
if err != nil {
18+
return nil, err
19+
}
20+
21+
for _, release := range res {
22+
releases = append(releases, release.Name)
23+
}
24+
return releases, nil
25+
}
26+
27+
type helmListOutput struct {
28+
Name string
29+
}
30+
31+
func (cli *HelmCLI) UninstallReleases(ctx context.Context, namespace string, releases []string) error {
32+
args := []string{"uninstall", "--wait", "--namespace", namespace}
33+
for _, release := range releases {
34+
args = append(args, release)
35+
}
36+
37+
out, err := cli.RunCmd(ctx, args...)
38+
if err != nil {
39+
return err
40+
}
41+
42+
fmt.Println(string(out))
43+
44+
return nil
45+
}
46+
47+
func (cli *HelmCLI) UninstallAllReleases(ctx context.Context, namespace string) error {
48+
releases, err := cli.ListReleases(ctx, namespace)
49+
if err != nil {
50+
return err
51+
}
52+
if len(releases) == 0 {
53+
return nil
54+
}
55+
return cli.UninstallReleases(ctx, namespace, releases)
56+
}

0 commit comments

Comments
 (0)