Skip to content

Commit

Permalink
Added flags to delete all dependent resources and configurations with…
Browse files Browse the repository at this point in the history
… deleting a cluster, addressing issue civo#406
  • Loading branch information
harsh082ip committed Jul 8, 2024
1 parent 1b4aa90 commit 82af8de
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 29 deletions.
5 changes: 5 additions & 0 deletions cmd/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ func init() {
kubernetesNodePoolInstanceListCmd.Flags().StringVarP(&nodePoolID, "node-pool-id", "p", "", "the ID of the node pool.")

kubernetesNodePoolCmd.AddCommand(kubernetesNodePoolListCmd)

// Define the flags for the kubernetesRemoveCmd
kubernetesRemoveCmd.Flags().BoolVar(&deleteVolumes, "delete-volumes", false, "Delete dependent volumes")
kubernetesRemoveCmd.Flags().BoolVar(&keepFirewalls, "keep-firewalls", false, "Keep dependent firewalls")
kubernetesRemoveCmd.Flags().BoolVar(&keepKubeconfig, "keep-kubeconfig", false, "Keep kubeconfig")
}

func getKubernetesList(value string) []string {
Expand Down
127 changes: 98 additions & 29 deletions cmd/kubernetes/kubernetes_remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,15 @@ import (
"github.com/spf13/cobra"
)

var kuberneteList []utility.ObjecteList
var (
deleteVolumes bool // Flag to delete dependent volumes
keepFirewalls bool // Flag to keep dependent firewalls
keepKubeconfig bool // Flag to keep kubeconfig
)

var kuberneteList []utility.ObjecteList // List to store the Kubernetes clusters to be deleted

// Command definition for removing a Kubernetes cluster
var kubernetesRemoveCmd = &cobra.Command{
Use: "remove",
Aliases: []string{"rm", "delete", "destroy"},
Expand All @@ -30,6 +38,7 @@ var kubernetesRemoveCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
utility.EnsureCurrentRegion()

// Create a client to interact with the Civo API
client, err := config.CivoAPIClient()
if common.RegionSet != "" {
client.Region = common.RegionSet
Expand All @@ -39,11 +48,12 @@ var kubernetesRemoveCmd = &cobra.Command{
os.Exit(1)
}

if len(args) == 1 {
kubernetesCluster, err := client.FindKubernetesCluster(args[0])
// Find and store the Kubernetes clusters to be deleted
for _, clusterName := range args {
kubernetesCluster, err := client.FindKubernetesCluster(clusterName)
if err != nil {
if errors.Is(err, civogo.ZeroMatchesError) {
utility.Error("sorry there is no %s Kubernetes cluster in your account", utility.Red(args[0]))
utility.Error("sorry there is no %s Kubernetes cluster in your account", utility.Red(clusterName))
os.Exit(1)
}
if errors.Is(err, civogo.MultipleMatchesError) {
Expand All @@ -52,53 +62,112 @@ var kubernetesRemoveCmd = &cobra.Command{
}
}
kuberneteList = append(kuberneteList, utility.ObjecteList{ID: kubernetesCluster.ID, Name: kubernetesCluster.Name})
} else {
for _, v := range args {
kubernetesCluster, err := client.FindKubernetesCluster(v)
if err == nil {
kuberneteList = append(kuberneteList, utility.ObjecteList{ID: kubernetesCluster.ID, Name: kubernetesCluster.Name})
}
}
}

// Collect names of the clusters to be deleted for confirmation message
kubernetesNameList := []string{}
for _, v := range kuberneteList {
kubernetesNameList = append(kubernetesNameList, v.Name)
}

var volsNameList []string
for _, v := range kuberneteList {
vols, err := client.ListVolumesForCluster(v.ID)
if err != nil {
utility.Error("error getting the list of dangling volumes: %s", err)
os.Exit(1)
}
for _, v := range vols {
volsNameList = append(volsNameList, v.Name)
}
if vols != nil {
utility.YellowConfirm("There are volume(s) attached to this cluster. Consider deleting or detaching these before deleting the cluster:\n%s\n", utility.Green(strings.Join(volsNameList, "\n")))
}
}

// Confirm the deletion with the user
if utility.UserConfirmedDeletion(fmt.Sprintf("Kubernetes %s", pluralize.Pluralize(len(kuberneteList), "cluster")), common.DefaultYes, strings.Join(kubernetesNameList, ", ")) {

for _, v := range kuberneteList {
_, err = client.DeleteKubernetesCluster(v.ID)

// Delete the Kubernetes cluster
_, err := client.DeleteKubernetesCluster(v.ID)
if err != nil {
utility.Error("error deleting the kubernetes cluster: %s", err)
os.Exit(1)
}

/* Poll for the deletion status
This is required because, if we try to delete other things like firewalls before
the cluster is completely deleted, we will encounter errors like "database_firewall_inuse_by_cluster".
*/
for {
_, err := client.FindKubernetesCluster(v.Name)
if err != nil {
if errors.Is(err, civogo.ZeroMatchesError) {
break // Cluster is deleted
}
}
}

// Delete volumes if --delete-volumes flag is set
if deleteVolumes {
volumes, err := client.ListVolumesForCluster(v.ID)
if err != nil {
if !errors.Is(err, civogo.ZeroMatchesError) {
utility.Error("Error listing volumes for cluster %s: %s", v.Name, err)
}
} else {
for _, volume := range volumes {
_, err := client.DeleteVolume(volume.ID)
if err != nil {
utility.Error("Error deleting volume %s: %s", volume.Name, err)
}
fmt.Printf("%s volume deleted", volume.ID)
}
}
}

// Output volumes left behind if deleteVolumes flag is not set
if !deleteVolumes {
volumes, err := client.ListVolumesForCluster(v.ID)
if err != nil {
if !errors.Is(err, civogo.ZeroMatchesError) {
utility.Error("Error listing volumes for cluster %s: %s", v.Name, err)
}
} else if len(volumes) > 0 {
fmt.Fprintf(os.Stderr, "Volumes left behind for Kubernetes cluster %s:\n", v.Name)
for _, volume := range volumes {
fmt.Fprintf(os.Stderr, "- %s\n", volume.ID)
}
fmt.Fprintf(os.Stderr, "Consider using '--delete-volumes' flag next time to delete them automatically.\n")
}
}

// Delete firewalls if --keep-firewalls flag is not set
if !keepFirewalls {
firewall, err := client.FindFirewall(v.Name)
if err != nil {
if errors.Is(err, civogo.MultipleMatchesError) {
utility.Error("Error deleting the firewall: %v. Please delete the firewall manually by visiting: https://dashboard.civo.com/firewalls", err)
} else {
utility.Error("Error finding the firewall: %v", err)
}
} else if firewall.ClusterCount == 0 {
_, err := client.DeleteFirewall(firewall.ID)
if err != nil {
utility.Error("Error deleting firewall %s: %v", firewall.Name, err)
} else {
fmt.Fprintf(os.Stderr, "Firewall %s deleted. If you want to keep the firewall in the future, please use '--keep-firewalls' flag.\n", firewall.ID)
}
}
}

// Delete kubeconfig if --keep-kubeconfig flag is not set
if !keepKubeconfig {
kubeconfigPath := fmt.Sprintf("%s/.kube/config", os.Getenv("HOME"))
err := os.Remove(kubeconfigPath)
if err != nil && !os.IsNotExist(err) {
utility.Error("Error deleting kubeconfig: %s", err)
} else {
fmt.Fprintf(os.Stderr, "Kubeconfig file deleted. If you want to keep the kubeconfig in the future, please use '--keep-kubeconfig' flag.\n")
}
}
}

// Output the result of the deletion
ow := utility.NewOutputWriter()

for _, v := range kuberneteList {
ow.StartLine()
ow.AppendDataWithLabel("id", v.ID, "ID")
ow.AppendDataWithLabel("name", v.Name, "Name")
}

// Format the output based on the selected format
switch common.OutputFormat {
case "json":
if len(kuberneteList) == 1 {
Expand Down

0 comments on commit 82af8de

Please sign in to comment.