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 }