Skip to content

Commit

Permalink
Vcluster delete --ignore-not-found
Browse files Browse the repository at this point in the history
Added a new flag --ignore-not-found, which ignores the resource if the flag is mentioned instead of throwing and error and exiting

Signed-off-by: Kartik-Garg <[email protected]>
  • Loading branch information
Kartik-Garg committed Apr 10, 2023
1 parent 74e1195 commit 2452565
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 45 deletions.
117 changes: 76 additions & 41 deletions cmd/vclusterctl/cmd/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ package cmd
import (
"context"
"fmt"
"github.com/loft-sh/vcluster/pkg/util/translate"
"os/exec"

"github.com/loft-sh/vcluster/pkg/util/translate"

"github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/app/localkubernetes"
"github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/find"
"k8s.io/client-go/rest"
Expand All @@ -31,10 +32,11 @@ type DeleteCmd struct {
DeleteNamespace bool
AutoDeleteNamespace bool

rawConfig *clientcmdapi.Config
restConfig *rest.Config
kubeClient *kubernetes.Clientset
log log.Logger
ignoreNotFound bool
rawConfig *clientcmdapi.Config
restConfig *rest.Config
kubeClient *kubernetes.Clientset
log log.Logger
}

// NewDeleteCmd creates a new command
Expand Down Expand Up @@ -68,6 +70,7 @@ vcluster delete test --namespace test
cobraCmd.Flags().BoolVar(&cmd.KeepPVC, "keep-pvc", false, "If enabled, vcluster will not delete the persistent volume claim of the vcluster")
cobraCmd.Flags().BoolVar(&cmd.DeleteNamespace, "delete-namespace", false, "If enabled, vcluster will delete the namespace of the vcluster. In the case of multi-namespace mode, will also delete all other namespaces created by vcluster")
cobraCmd.Flags().BoolVar(&cmd.AutoDeleteNamespace, "auto-delete-namespace", true, "If enabled, vcluster will delete the namespace of the vcluster if it was created by vclusterctl. In the case of multi-namespace mode, will also delete all other namespaces created by vcluster")
cobraCmd.Flags().BoolVar(&cmd.ignoreNotFound, "ignore-not-found", false, "If enabled, vcluster will not error out in case vcluster does not exists")
return cobraCmd
}

Expand All @@ -90,7 +93,12 @@ func (cmd *DeleteCmd) Run(cobraCmd *cobra.Command, args []string) error {
// prepare client
err = cmd.prepare(args[0])
if err != nil {
return err
var errorVclusterNotFound *find.ErrorNotFoundVcluster
if cmd.ignoreNotFound && errors.As(err, &errorVclusterNotFound) {
cmd.log.Donef("vcluster %s not found in namespace %s, ignoring since --ignore-not-found flag is set", args[0], cmd.Namespace)
} else {
return err
}
}

// check if namespace
Expand All @@ -107,9 +115,15 @@ func (cmd *DeleteCmd) Run(cobraCmd *cobra.Command, args []string) error {
cmd.log.Infof("Delete vcluster %s...", args[0])
err = helm.NewClient(cmd.rawConfig, cmd.log, helmBinaryPath).Delete(args[0], cmd.Namespace)
if err != nil {
return err
var errorHelmNotFound *helm.ErrorNotFoundHelm
if cmd.ignoreNotFound && errors.As(err, &errorHelmNotFound) {
cmd.log.Donef("vcluster %s not found in namespace %s, ignoring since --ignore-not-found flag is set", args[0], cmd.Namespace)
} else {
return err
}
} else {
cmd.log.Donef("Successfully deleted virtual cluster %s in namespace %s", args[0], cmd.Namespace)
}
cmd.log.Donef("Successfully deleted virtual cluster %s in namespace %s", args[0], cmd.Namespace)

// try to delete the pvc
if !cmd.KeepPVC && !cmd.DeleteNamespace {
Expand Down Expand Up @@ -182,45 +196,66 @@ func (cmd *DeleteCmd) Run(cobraCmd *cobra.Command, args []string) error {
}

func (cmd *DeleteCmd) prepare(vClusterName string) error {
vCluster, err := find.GetVCluster(cmd.Context, vClusterName, cmd.Namespace)
if err != nil {
return err
}
if cmd.ignoreNotFound {
restConfig, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(clientcmd.NewDefaultClientConfigLoadingRules(), &clientcmd.ConfigOverrides{}).ClientConfig()
if err != nil {
return err
}
kubeClient, err := kubernetes.NewForConfig(restConfig)
if err != nil {
return err
}

// load the raw config
rawConfig, err := vCluster.ClientFactory.RawConfig()
if err != nil {
return fmt.Errorf("there is an error loading your current kube config (%v), please make sure you have access to a kubernetes cluster and the command `kubectl get namespaces` is working", err)
}
err = deleteContext(&rawConfig, find.VClusterContextName(vCluster.Name, vCluster.Namespace, vCluster.Context), vCluster.Context)
if err != nil {
return errors.Wrap(err, "delete kube context")
}
rawConfig, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(clientcmd.NewDefaultClientConfigLoadingRules(), &clientcmd.ConfigOverrides{}).RawConfig()
if err != nil {
return err
}

rawConfig.CurrentContext = vCluster.Context
restConfig, err := vCluster.ClientFactory.ClientConfig()
if err != nil {
return err
}
cmd.rawConfig = &rawConfig
cmd.kubeClient = kubeClient
cmd.restConfig = restConfig

err = localkubernetes.CleanupLocal(vClusterName, vCluster.Namespace, &rawConfig, cmd.log)
if err != nil {
cmd.log.Warnf("error cleaning up: %v", err)
}
} else {
vCluster, err := find.GetVCluster(cmd.Context, vClusterName, cmd.Namespace)
if err != nil {
return err
}

// construct proxy name
proxyName := find.VClusterConnectBackgroundProxyName(vClusterName, vCluster.Namespace, rawConfig.CurrentContext)
_ = localkubernetes.CleanupBackgroundProxy(proxyName, cmd.log)
// load the raw config
rawConfig, err := vCluster.ClientFactory.RawConfig()
if err != nil {
return fmt.Errorf("there is an error loading your current kube config (%v), please make sure you have access to a kubernetes cluster and the command `kubectl get namespaces` is working", err)
}
err = deleteContext(&rawConfig, find.VClusterContextName(vCluster.Name, vCluster.Namespace, vCluster.Context), vCluster.Context)
if err != nil {
return errors.Wrap(err, "delete kube context")
}

kubeClient, err := kubernetes.NewForConfig(restConfig)
if err != nil {
return err
}
rawConfig.CurrentContext = vCluster.Context
restConfig, err := vCluster.ClientFactory.ClientConfig()
if err != nil {
return err
}

err = localkubernetes.CleanupLocal(vClusterName, vCluster.Namespace, &rawConfig, cmd.log)
if err != nil {
cmd.log.Warnf("error cleaning up: %v", err)
}

cmd.Namespace = vCluster.Namespace
cmd.rawConfig = &rawConfig
cmd.restConfig = restConfig
cmd.kubeClient = kubeClient
// construct proxy name
proxyName := find.VClusterConnectBackgroundProxyName(vClusterName, vCluster.Namespace, rawConfig.CurrentContext)
_ = localkubernetes.CleanupBackgroundProxy(proxyName, cmd.log)

kubeClient, err := kubernetes.NewForConfig(restConfig)
if err != nil {
return err
}

cmd.Namespace = vCluster.Namespace
cmd.rawConfig = &rawConfig
cmd.restConfig = restConfig
cmd.kubeClient = kubeClient
}
return nil
}

Expand Down
13 changes: 11 additions & 2 deletions cmd/vclusterctl/cmd/find/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package find
import (
"context"
"fmt"
"github.com/loft-sh/vcluster/cmd/vclusterctl/log"
"strings"
"time"

"github.com/loft-sh/vcluster/cmd/vclusterctl/log"

"github.com/loft-sh/vcluster/pkg/constants"
"github.com/pkg/errors"
appsv1 "k8s.io/api/apps/v1"
Expand Down Expand Up @@ -57,14 +58,22 @@ func GetVCluster(context, name, namespace string) (*VCluster, error) {
if err != nil {
return nil, err
} else if len(vclusters) == 0 {
return nil, fmt.Errorf("couldn't find vcluster %s", name)
return nil, &ErrorNotFoundVcluster{Name: name}
} else if len(vclusters) == 1 {
return &vclusters[0], nil
}

return nil, fmt.Errorf("multiple vclusters with name %s found, please specify a namespace via -n", name)
}

type ErrorNotFoundVcluster struct {
Name string
}

func (e *ErrorNotFoundVcluster) Error() string {
return fmt.Sprintf("couldn't find vcluster %s", e.Name)
}

func ListVClusters(context, name, namespace string) ([]VCluster, error) {
if context == "" {
var err error
Expand Down
12 changes: 10 additions & 2 deletions pkg/helm/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,15 +220,23 @@ func (c *client) Delete(name, namespace string) error {
output, err := exec.Command(c.helmPath, args...).CombinedOutput()
if err != nil {
if strings.Contains(string(output), "release: not found") {
return fmt.Errorf("release '%s' was not found in namespace '%s'", name, namespace)
return &ErrorNotFoundHelm{Name: name, Namespace: namespace}
}

return fmt.Errorf("error executing helm delete: %s", string(output))
}

return nil
}

type ErrorNotFoundHelm struct {
Name string
Namespace string
}

func (e *ErrorNotFoundHelm) Error() string {
return fmt.Sprintf("release '%s' was not found in namespace '%s'", e.Name, e.Namespace)
}

func (c *client) Exists(name, namespace string) (bool, error) {
kubeConfig, err := WriteKubeConfig(c.config)
if err != nil {
Expand Down

0 comments on commit 2452565

Please sign in to comment.