github.com/jenkins-x/jx/v2@v2.1.155/pkg/kube/namespaces.go (about)

     1  package kube
     2  
     3  import (
     4  	"fmt"
     5  
     6  	v1 "github.com/jenkins-x/jx-api/pkg/apis/jenkins.io/v1"
     7  	"github.com/jenkins-x/jx-api/pkg/client/clientset/versioned"
     8  	"github.com/jenkins-x/jx-logging/pkg/log"
     9  	"github.com/jenkins-x/jx/v2/pkg/kube/naming"
    10  	corev1 "k8s.io/api/core/v1"
    11  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    12  	"k8s.io/client-go/kubernetes"
    13  )
    14  
    15  func EnsureEnvironmentNamespaceSetup(kubeClient kubernetes.Interface, jxClient versioned.Interface, env *v1.Environment, ns string) error {
    16  	// lets create the namespace if we are on the same cluster
    17  	spec := &env.Spec
    18  	if spec.Cluster == "" && spec.Namespace != "" {
    19  		labels := map[string]string{
    20  			LabelTeam:        ns,
    21  			LabelEnvironment: env.Name,
    22  		}
    23  		annotations := map[string]string{}
    24  
    25  		err := EnsureNamespaceCreated(kubeClient, spec.Namespace, labels, annotations)
    26  		if err != nil {
    27  			return err
    28  		}
    29  	}
    30  
    31  	err := EnsureDevNamespaceCreatedWithoutEnvironment(kubeClient, ns)
    32  	if err != nil {
    33  		return err
    34  	}
    35  	_, err = EnsureDevEnvironmentSetup(jxClient, ns)
    36  	return err
    37  }
    38  
    39  // EnsureDevNamespaceCreatedWithoutEnvironment ensures that there is a development namespace created
    40  func EnsureDevNamespaceCreatedWithoutEnvironment(kubeClient kubernetes.Interface, ns string) error {
    41  	// lets annotate the team namespace as being the developer environment
    42  	labels := map[string]string{
    43  		LabelTeam:        ns,
    44  		LabelEnvironment: LabelValueDevEnvironment,
    45  	}
    46  	annotations := map[string]string{}
    47  	// lets check that the current namespace is marked as the dev environment
    48  	err := EnsureNamespaceCreated(kubeClient, ns, labels, annotations)
    49  	return err
    50  }
    51  
    52  // EnsureDevEnvironmentSetup ensures that the Environment is created in the given namespace
    53  func EnsureDevEnvironmentSetup(jxClient versioned.Interface, ns string) (*v1.Environment, error) {
    54  	// lets ensure there is a dev Environment setup so that we can easily switch between all the environments
    55  	env, err := jxClient.JenkinsV1().Environments(ns).Get(LabelValueDevEnvironment, metav1.GetOptions{})
    56  	if err != nil {
    57  		// lets create a dev environment
    58  		env = CreateDefaultDevEnvironment(ns)
    59  		env, err = jxClient.JenkinsV1().Environments(ns).Create(env)
    60  		if err != nil {
    61  			return nil, err
    62  		}
    63  	}
    64  	return env, nil
    65  }
    66  
    67  // CreateDefaultDevEnvironment creates a default development environment
    68  func CreateDefaultDevEnvironment(ns string) *v1.Environment {
    69  	return &v1.Environment{
    70  		ObjectMeta: metav1.ObjectMeta{
    71  			Name:   LabelValueDevEnvironment,
    72  			Labels: map[string]string{LabelTeam: ns, LabelEnvironment: LabelValueDevEnvironment},
    73  		},
    74  		Spec: v1.EnvironmentSpec{
    75  			Namespace:         ns,
    76  			Label:             "Development",
    77  			PromotionStrategy: v1.PromotionStrategyTypeNever,
    78  			Kind:              v1.EnvironmentKindTypeDevelopment,
    79  			TeamSettings: v1.TeamSettings{
    80  				UseGitOps:           true,
    81  				AskOnCreate:         false,
    82  				QuickstartLocations: DefaultQuickstartLocations,
    83  				PromotionEngine:     v1.PromotionEngineJenkins,
    84  				AppsRepository:      DefaultChartMuseumURL,
    85  			},
    86  		},
    87  	}
    88  }
    89  
    90  // GetEnrichedDevEnvironment lazily creates the dev namespace if it does not already exist and
    91  // auto-detects the webhook engine if its not specified
    92  func GetEnrichedDevEnvironment(kubeClient kubernetes.Interface, jxClient versioned.Interface, ns string) (*v1.Environment, error) {
    93  	env, err := EnsureDevEnvironmentSetup(jxClient, ns)
    94  	if err != nil {
    95  		return env, err
    96  	}
    97  	if env.Spec.WebHookEngine == v1.WebHookEngineNone {
    98  		prowEnabled, err := IsProwEnabled(kubeClient, ns)
    99  		if err != nil {
   100  			return env, err
   101  		}
   102  		if prowEnabled {
   103  			env.Spec.WebHookEngine = v1.WebHookEngineProw
   104  		} else {
   105  			env.Spec.WebHookEngine = v1.WebHookEngineJenkins
   106  		}
   107  	}
   108  	return env, nil
   109  }
   110  
   111  // IsProwEnabled returns true if Prow is enabled in the given development namespace
   112  func IsProwEnabled(kubeClient kubernetes.Interface, ns string) (bool, error) {
   113  	// lets try determine if its Jenkins or not via the deployments
   114  	_, err := kubeClient.AppsV1().Deployments(ns).Get(DeploymentProwBuild, metav1.GetOptions{})
   115  	if err != nil {
   116  		if isProwBuildNotFoundError(err) {
   117  			return false, nil
   118  		}
   119  		return false, err
   120  	}
   121  	return true, nil
   122  }
   123  
   124  func isProwBuildNotFoundError(err error) bool {
   125  	return err.Error() == `deployments.apps "prow-build" not found`
   126  }
   127  
   128  // IsTektonEnabled returns true if Build Pipeline is enabled in the given development namespace
   129  func IsTektonEnabled(kubeClient kubernetes.Interface, ns string) (bool, error) {
   130  	// lets try determine if its Jenkins or not via the deployments
   131  	_, err := kubeClient.AppsV1().Deployments(ns).Get(DeploymentTektonController, metav1.GetOptions{})
   132  	if err != nil {
   133  		if isTektonNotFoundError(err) {
   134  			return false, nil
   135  		}
   136  		return false, err
   137  	}
   138  	return true, nil
   139  }
   140  
   141  func isTektonNotFoundError(err error) bool {
   142  	return err.Error() == `deployments.apps "tekton-pipelines-controller" not found`
   143  }
   144  
   145  // EnsureEditEnvironmentSetup ensures that the Environment is created in the given namespace
   146  func EnsureEditEnvironmentSetup(kubeClient kubernetes.Interface, jxClient versioned.Interface, ns string, username string) (*v1.Environment, error) {
   147  	// lets ensure there is a dev Environment setup so that we can easily switch between all the environments
   148  	envList, err := jxClient.JenkinsV1().Environments(ns).List(metav1.ListOptions{})
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  	if envList != nil {
   153  		for _, e := range envList.Items {
   154  			if e.Spec.Kind == v1.EnvironmentKindTypeEdit && e.Spec.PreviewGitSpec.User.Username == username {
   155  				return &e, nil
   156  			}
   157  		}
   158  	}
   159  
   160  	editNS := naming.ToValidName(ns + "-edit-" + username)
   161  	labels := map[string]string{
   162  		LabelTeam:        ns,
   163  		LabelEnvironment: username,
   164  		LabelKind:        ValueKindEditNamespace,
   165  		LabelUsername:    username,
   166  	}
   167  	annotations := map[string]string{}
   168  
   169  	err = EnsureNamespaceCreated(kubeClient, editNS, labels, annotations)
   170  	if err != nil {
   171  		return nil, err
   172  	}
   173  
   174  	cm, err := kubeClient.CoreV1().ConfigMaps(ns).Get(ConfigMapIngressConfig, metav1.GetOptions{})
   175  	if err != nil {
   176  		cm, err := kubeClient.CoreV1().ConfigMaps(ns).Get(ConfigMapExposecontroller, metav1.GetOptions{})
   177  		if err != nil {
   178  			return nil, err
   179  		}
   180  		oldCm, err := kubeClient.CoreV1().ConfigMaps(editNS).Get(ConfigMapExposecontroller, metav1.GetOptions{})
   181  		if oldCm == nil || err != nil {
   182  			cm.Namespace = editNS
   183  			cm.ResourceVersion = ""
   184  			_, err := kubeClient.CoreV1().ConfigMaps(editNS).Create(cm)
   185  			if err != nil {
   186  				return nil, err
   187  			}
   188  		}
   189  	} else {
   190  		oldCm, err := kubeClient.CoreV1().ConfigMaps(editNS).Get(ConfigMapIngressConfig, metav1.GetOptions{})
   191  		if oldCm == nil || err != nil {
   192  			cm.Namespace = editNS
   193  			cm.ResourceVersion = ""
   194  			_, err := kubeClient.CoreV1().ConfigMaps(editNS).Create(cm)
   195  			if err != nil {
   196  				return nil, err
   197  			}
   198  		}
   199  	}
   200  
   201  	env := &v1.Environment{
   202  		ObjectMeta: metav1.ObjectMeta{
   203  			Name: username,
   204  		},
   205  		Spec: v1.EnvironmentSpec{
   206  			Namespace:         editNS,
   207  			Label:             username,
   208  			PromotionStrategy: v1.PromotionStrategyTypeNever,
   209  			Kind:              v1.EnvironmentKindTypeEdit,
   210  			PreviewGitSpec: v1.PreviewGitSpec{
   211  				User: v1.UserSpec{
   212  					Username: username,
   213  				},
   214  			},
   215  			Order: 1,
   216  		},
   217  	}
   218  	_, err = jxClient.JenkinsV1().Environments(ns).Create(env)
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	return env, nil
   223  }
   224  
   225  // Ensure that the namespace exists for the given name
   226  func EnsureNamespaceCreated(kubeClient kubernetes.Interface, name string, labels map[string]string, annotations map[string]string) error {
   227  	n, err := kubeClient.CoreV1().Namespaces().Get(name, metav1.GetOptions{})
   228  	if err == nil {
   229  		// lets check if we have the labels setup
   230  		if n.Annotations == nil {
   231  			n.Annotations = map[string]string{}
   232  		}
   233  		if n.Labels == nil {
   234  			n.Labels = map[string]string{}
   235  		}
   236  		changed := false
   237  		if labels != nil {
   238  			for k, v := range labels {
   239  				if n.Labels[k] != v {
   240  					n.Labels[k] = v
   241  					changed = true
   242  				}
   243  			}
   244  		}
   245  		if annotations != nil {
   246  			for k, v := range annotations {
   247  				if n.Annotations[k] != v {
   248  					n.Annotations[k] = v
   249  					changed = true
   250  				}
   251  			}
   252  		}
   253  		if changed {
   254  			_, err = kubeClient.CoreV1().Namespaces().Update(n)
   255  			if err != nil {
   256  				return fmt.Errorf("Failed to label Namespace %s %s", name, err)
   257  			}
   258  		}
   259  		return nil
   260  	}
   261  
   262  	namespace := &corev1.Namespace{
   263  		ObjectMeta: metav1.ObjectMeta{
   264  			Name:        name,
   265  			Labels:      labels,
   266  			Annotations: annotations,
   267  		},
   268  	}
   269  	_, err = kubeClient.CoreV1().Namespaces().Create(namespace)
   270  	if err != nil {
   271  		return fmt.Errorf("Failed to create Namespace %s %s", name, err)
   272  	} else {
   273  		log.Logger().Infof("Namespace %s created ", name)
   274  	}
   275  	return err
   276  }