github.com/Racer159/jackal@v0.32.7-0.20240401174413-0bd2339e4f2e/src/pkg/k8s/namespace.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // SPDX-FileCopyrightText: 2021-Present The Jackal Authors
     3  
     4  // Package k8s provides a client for interacting with a Kubernetes cluster.
     5  package k8s
     6  
     7  import (
     8  	"context"
     9  	"time"
    10  
    11  	"cuelang.org/go/pkg/strings"
    12  	"github.com/defenseunicorns/pkg/helpers"
    13  	corev1 "k8s.io/api/core/v1"
    14  	"k8s.io/apimachinery/pkg/api/errors"
    15  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    16  )
    17  
    18  // GetNamespaces returns a list of namespaces in the cluster.
    19  func (k *K8s) GetNamespaces() (*corev1.NamespaceList, error) {
    20  	metaOptions := metav1.ListOptions{}
    21  	return k.Clientset.CoreV1().Namespaces().List(context.TODO(), metaOptions)
    22  }
    23  
    24  // UpdateNamespace updates the given namespace in the cluster.
    25  func (k *K8s) UpdateNamespace(namespace *corev1.Namespace) (*corev1.Namespace, error) {
    26  	updateOptions := metav1.UpdateOptions{}
    27  	return k.Clientset.CoreV1().Namespaces().Update(context.TODO(), namespace, updateOptions)
    28  }
    29  
    30  // CreateNamespace creates the given namespace or returns it if it already exists in the cluster.
    31  func (k *K8s) CreateNamespace(namespace *corev1.Namespace) (*corev1.Namespace, error) {
    32  	metaOptions := metav1.GetOptions{}
    33  	createOptions := metav1.CreateOptions{}
    34  
    35  	match, err := k.Clientset.CoreV1().Namespaces().Get(context.TODO(), namespace.Name, metaOptions)
    36  
    37  	if err != nil || match.Name != namespace.Name {
    38  		return k.Clientset.CoreV1().Namespaces().Create(context.TODO(), namespace, createOptions)
    39  	}
    40  
    41  	return match, err
    42  }
    43  
    44  // DeleteNamespace deletes the given namespace from the cluster.
    45  func (k *K8s) DeleteNamespace(ctx context.Context, name string) error {
    46  	// Attempt to delete the namespace immediately
    47  	gracePeriod := int64(0)
    48  	err := k.Clientset.CoreV1().Namespaces().Delete(ctx, name, metav1.DeleteOptions{GracePeriodSeconds: &gracePeriod})
    49  	// If an error besides "not found" is returned, return it
    50  	if err != nil && !errors.IsNotFound(err) {
    51  		return err
    52  	}
    53  
    54  	// Indefinitely wait for the namespace to be deleted, use context.WithTimeout to limit this
    55  	for {
    56  		// Keep checking for the namespace to be deleted
    57  		_, err := k.Clientset.CoreV1().Namespaces().Get(ctx, name, metav1.GetOptions{})
    58  		if errors.IsNotFound(err) {
    59  			return nil
    60  		}
    61  		time.Sleep(1 * time.Second)
    62  	}
    63  }
    64  
    65  // NewJackalManagedNamespace returns a corev1.Namespace with Jackal-managed labels
    66  func (k *K8s) NewJackalManagedNamespace(name string) *corev1.Namespace {
    67  	namespace := &corev1.Namespace{
    68  		TypeMeta: metav1.TypeMeta{
    69  			APIVersion: corev1.SchemeGroupVersion.String(),
    70  			Kind:       "Namespace",
    71  		},
    72  		ObjectMeta: metav1.ObjectMeta{
    73  			Name: name,
    74  		},
    75  	}
    76  
    77  	// Merge in common labels so that later modifications to the namespace can't mutate them
    78  	namespace.ObjectMeta.Labels = helpers.MergeMap[string](k.Labels, namespace.ObjectMeta.Labels)
    79  
    80  	return namespace
    81  }
    82  
    83  // IsInitialNamespace returns true if the given namespace name is an initial k8s namespace: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/#initial-namespaces
    84  func (k *K8s) IsInitialNamespace(name string) bool {
    85  	if name == "default" {
    86  		return true
    87  	} else if strings.HasPrefix(name, "kube-") {
    88  		return true
    89  	}
    90  
    91  	return false
    92  }