There is no such thing as "current namespace".
All namespaces exist at the same time and you can access them all at the same time. The idea of the "current namespace" comes from additional plugins like kubens mostly. The reality is, that it is just a detail to the kube context for the given cluster as explained here where you can for example specify which set of credential/user combination to access a given namespace. As well as a default namespace to execute commands against via kubectl
if you don't specify a namespace at all, as you can read in the documentation. Thus the object of type config
also does not have the capability to hold any information about that as you can read here
With tools like kubens
that allow you to "persist" which namespace you want to execute commands against by default, you get some extra options but they still need to store that state, which they do in state files for each cluster like .kube/kubens/test
.
In the code example you posted, you can also see that a namespace is actually specified via the variable namespace
, that is set to default
here
You can alternatively try to specify the namespace via flag like
func main() {
var kubeconfig *string
var namespace *string
if home := homedir.HomeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
} else {
kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
}
namespace = flag.String("namespace", "default", "namespace to execute commands against")
flag.Parse()
// use the current context in kubeconfig
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err.Error())
}
// create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
for {
pods, err := clientset.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
// Examples for error handling:
// - Use helper functions like e.g. errors.IsNotFound()
// - And/or cast to StatusError and use its properties like e.g. ErrStatus.Message
pod := "example-xxxxx"
_, err = clientset.CoreV1().Pods(*namespace).Get(context.TODO(), pod, metav1.GetOptions{})
if errors.IsNotFound(err) {
fmt.Printf("Pod %s in namespace %s not found\n", pod, *namespace)
} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
fmt.Printf("Error getting pod %s in namespace %s: %v\n",
pod, *namespace, statusError.ErrStatus.Message)
} else if err != nil {
panic(err.Error())
} else {
fmt.Printf("Found pod %s in namespace %s\n", pod, *namespace)
}
time.Sleep(10 * time.Second)
}
}
If you want to replicate a similar behaviour, to what kubens does, you can store the namespace in a file and read it from there, if nothing else is passed as flag, and switch to default
if the files doesn't exist, i.e. you never accessed the cluster:
func main() {
var kubeconfig *string
var namespace *string
if home := homedir.HomeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
} else {
kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
}
namespace = flag.String("namespace", "", "namespace to execute commands against")
flag.Parse()
// use the current context in kubeconfig
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err.Error())
}
// create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
// write to file if namespace is given as flag
if *namespace != "" {
dat := []byte(*namespace)
err := os.WriteFile(config.ServerName, dat, 0644)
if err != nil {
panic(err.Error())
}
}
// read from file if namespace is not given as flag, otherwise use default
if *namespace == "" {
_, doesNotExist := os.Stat(config.ServerName)
if doesNotExist == nil {
dat, err := os.ReadFile(config.ServerName)
if err != nil {
panic(err.Error())
}
*namespace = string(dat)
}
if doesNotExist != nil {
*namespace = "default"
}
}