Files
kubectx/cmd/kubens/switch.go
Ahmet Alp Balkan cd1849d8df query namespace exists with GET Namespace
More efficient ns switches with kubens by querying only the namespace (instead
of listing all namespaces).

Signed-off-by: Ahmet Alp Balkan <ahmetb@google.com>
2020-05-31 15:23:02 -07:00

98 lines
2.5 KiB
Go

package main
import (
"io"
"os"
"github.com/pkg/errors"
errors2 "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/ahmetb/kubectx/internal/cmdutil"
"github.com/ahmetb/kubectx/internal/kubeconfig"
"github.com/ahmetb/kubectx/internal/printer"
)
type SwitchOp struct {
Target string // '-' for back and forth, or NAME
}
func (s SwitchOp) Run(_, stderr io.Writer) error {
kc := new(kubeconfig.Kubeconfig).WithLoader(cmdutil.DefaultLoader)
defer kc.Close()
if err := kc.Parse(); err != nil {
return errors.Wrap(err, "kubeconfig error")
}
toNS, err := switchNamespace(kc, s.Target)
if err != nil {
return err
}
err = printer.Success(stderr, "Active namespace is %q", toNS)
return err
}
func switchNamespace(kc *kubeconfig.Kubeconfig, ns string) (string, error) {
ctx := kc.GetCurrentContext()
if ctx == "" {
return "", errors.New("current-context is not set")
}
curNS, err := kc.NamespaceOfContext(ctx)
if ctx == "" {
return "", errors.New("failed to get current namespace")
}
f := NewNSFile(ctx)
prev, err := f.Load()
if err != nil {
return "", errors.Wrap(err, "failed to load previous namespace from file")
}
if ns == "-" {
if prev == "" {
return "", errors.Errorf("No previous namespace found for current context (%s)", ctx)
}
ns = prev
}
ok, err := namespaceExists(kc, ns)
if err != nil {
return "", errors.Wrap(err, "failed to query if namespace exists (is cluster accessible?)")
}
if !ok {
return "", errors.Errorf("no namespace exists with name %q", ns)
}
if err := kc.SetNamespace(ctx, ns); err != nil {
return "", errors.Wrapf(err, "failed to change to namespace %q", ns)
}
if err := kc.Save(); err != nil {
return "", errors.Wrap(err, "failed to save kubeconfig file")
}
if curNS != ns {
if err := f.Save(curNS); err != nil {
return "", errors.Wrap(err, "failed to save the previous namespace to file")
}
}
return ns, nil
}
func namespaceExists(kc *kubeconfig.Kubeconfig, ns string) (bool, error) {
// for tests
if os.Getenv("_MOCK_NAMESPACES") != "" {
return ns == "ns1" || ns == "ns2", nil
}
clientset, err := newKubernetesClientSet(kc)
if err != nil {
return false, errors.Wrap(err, "failed to initialize k8s REST client")
}
namespace, err := clientset.CoreV1().Namespaces().Get(ns, metav1.GetOptions{})
if errors2.IsNotFound(err) {
return false, nil
}
return namespace != nil, errors.Wrapf(err, "failed to query "+
"namespace %q from k8s API", ns)
}