From 2e3741bdc418406e676f4f3c4a2e3571ec6134ef Mon Sep 17 00:00:00 2001 From: Anatolii Bazko Date: Thu, 17 Mar 2022 11:13:05 +0200 Subject: [PATCH] chore: add CheCluster v2 Signed-off-by: Anatolii Bazko --- .github/bin/check-resources.sh | 8 +- Makefile | 5 +- PROJECT | 11 + api/conversion_test.go | 1188 +++++++++-------- api/v1/checluster_types.go | 1 - api/v1/conversion.go | 528 ++++++++ api/v2/checluster_types.go | 604 +++++++++ api/v2/checluster_webhook.go | 29 + api/v2/conversion.go | 15 + api/v2/groupversion_info.go | 32 + api/v2/zz_generated.deepcopy.go | 577 ++++++++ api/v2alpha1/checluster_types.go | 1 + .../che-operator.clusterserviceversion.yaml | 150 ++- .../manifests/org_v1_che_crd.yaml | 938 +++++++++++++ .../manifests/webhook-service_v1_service.yaml | 25 + config/certmanager/certificate.yaml | 37 + config/certmanager/kustomization.yaml | 17 + config/certmanager/kustomizeconfig.yaml | 28 + config/crd/bases/org_v1_che_crd.yaml | 926 +++++++++++++ config/crd/kustomization.yaml | 4 +- .../crd/patches/webhook_in_checlusters.yaml | 3 +- config/default/kustomization.yaml | 58 +- config/default/manager_config_patch.yaml | 2 +- config/default/manager_webhook_patch.yaml | 35 + config/default/webhookcainjection_patch.yaml | 27 + .../che-operator.clusterserviceversion.yaml | 121 ++ config/samples/kustomization.yaml | 1 + ...checluster.yaml => org_v2_checluster.yaml} | 5 +- config/webhook/kustomization.yaml | 18 + config/webhook/kustomizeconfig.yaml | 37 + config/webhook/service.yaml | 23 + helmcharts/next/crds/org_v1_che_crd.yaml | 926 +++++++++++++ main.go | 8 + pkg/infrastructure/infrastructure.go | 80 ++ pkg/k8sclient/k8s_client.go | 26 + pkg/util/util.go | 1 - 36 files changed, 5872 insertions(+), 623 deletions(-) create mode 100644 api/v1/conversion.go create mode 100644 api/v2/checluster_types.go create mode 100644 api/v2/checluster_webhook.go create mode 100644 api/v2/conversion.go create mode 100644 api/v2/groupversion_info.go create mode 100644 api/v2/zz_generated.deepcopy.go create mode 100644 bundle/next/eclipse-che-preview-openshift/manifests/webhook-service_v1_service.yaml create mode 100644 config/certmanager/certificate.yaml create mode 100644 config/certmanager/kustomization.yaml create mode 100644 config/certmanager/kustomizeconfig.yaml create mode 100644 config/default/manager_webhook_patch.yaml create mode 100644 config/default/webhookcainjection_patch.yaml rename config/samples/{org_v2alpha1_checluster.yaml => org_v2_checluster.yaml} (86%) create mode 100644 config/webhook/kustomization.yaml create mode 100644 config/webhook/kustomizeconfig.yaml create mode 100644 config/webhook/service.yaml create mode 100644 pkg/infrastructure/infrastructure.go create mode 100644 pkg/k8sclient/k8s_client.go diff --git a/.github/bin/check-resources.sh b/.github/bin/check-resources.sh index 1a272e5bdc..54b9f0af04 100755 --- a/.github/bin/check-resources.sh +++ b/.github/bin/check-resources.sh @@ -53,16 +53,10 @@ checkCRDs() { # files to check local checluster_CRD_V1="config/crd/bases/org_v1_che_crd.yaml" - local chebackupserverconfiguration_CRD_V1="config/crd/bases/org.eclipse.che_chebackupserverconfigurations_crd.yaml" - local checlusterbackup_CRD_V1="config/crd/bases/org.eclipse.che_checlusterbackups_crd.yaml" - local checlusterrestore_CRD_V1="config/crd/bases/org.eclipse.che_checlusterrestores_crd.yaml" changedFiles=($(cd ${ROOT_PROJECT_DIR}; git diff --name-only)) # Check if there are any difference in the crds. If yes, then fail check. - if [[ " ${changedFiles[*]} " =~ $checluster_CRD_V1 ]] || \ - [[ " ${changedFiles[*]} " =~ $chebackupserverconfiguration_CRD_V1 ]] || \ - [[ " ${changedFiles[*]} " =~ $checlusterbackup_CRD_V1 ]] || \ - [[ " ${changedFiles[*]} " =~ $checlusterrestore_CRD_V1 ]] + if [[ " ${changedFiles[*]} " =~ $checluster_CRD_V1 ]] then echo "[ERROR] CRD file is not up to date: ${BASH_REMATCH}" echo "[ERROR] Run 'make update-resources -s' to regenerate CRD files." diff --git a/Makefile b/Makefile index c93507108c..bd3f104d4e 100644 --- a/Makefile +++ b/Makefile @@ -132,7 +132,7 @@ manifests: controller-gen add-license-download ## Generate WebhookConfiguration, rm -rf "$(ECLIPSE_CHE_CRD_V1).bak" # remove v1alphav2 version from crd files - yq -rYi "del(.spec.versions[1])" "$(ECLIPSE_CHE_CRD_V1)" + yq -rYi "del(.spec.versions[2])" "$(ECLIPSE_CHE_CRD_V1)" $(MAKE) add-license $$(find ./config/crd -not -path "./vendor/*" -name "*.yaml") @@ -502,9 +502,8 @@ bundle: generate manifests kustomize ## Generate bundle manifests and metadata, # Example such annotation: +operator-sdk:csv:customresourcedefinitions:order=0 # Let's copy this sorted CRDs to the bundle cluster service version file. BASE_CSV="config/manifests/bases/che-operator.clusterserviceversion.yaml" - CRD_API=$$(yq -c '.spec.customresourcedefinitions.owned' $${BASE_CSV}) + CRD_API=$$(yq '.spec.customresourcedefinitions.owned' $${BASE_CSV} | yq -r 'del(.[] | select(.version == "v2alpha1"))') yq -riSY ".spec.customresourcedefinitions.owned = $$CRD_API" "$${NEW_CSV}" - yq -riSY "del(.spec.customresourcedefinitions.owned[] | select(.version == \"v2alpha1\"))" "$${NEW_CSV}" # Format code. yq -rY "." "$${NEW_CSV}" > "$${NEW_CSV}.old" diff --git a/PROJECT b/PROJECT index 0d58c0f9ee..46d43a027e 100644 --- a/PROJECT +++ b/PROJECT @@ -24,4 +24,15 @@ resources: kind: CheCluster path: github.com/eclipse-che/che-operator/api/v2alpha1 version: v2alpha1 +- api: + crdVersion: v1 + namespaced: true + domain: eclipse.che + group: org + kind: CheCluster + path: github.com/eclipse-che/che-operator/api/v2 + version: v2 + webhooks: + conversion: true + webhookVersion: v1 version: "3" diff --git a/api/conversion_test.go b/api/conversion_test.go index f4db68e5db..bc0fba6bad 100644 --- a/api/conversion_test.go +++ b/api/conversion_test.go @@ -1,5 +1,5 @@ // -// Copyright (c) 2019-2021 Red Hat, Inc. +// Copyright (c) 2019-2022 Red Hat, Inc. // This program and the accompanying materials are made // available under the terms of the Eclipse Public License 2.0 // which is available at https://www.eclipse.org/legal/epl-2.0/ @@ -13,631 +13,671 @@ package org import ( - "encoding/json" - "reflect" "testing" - corev1 "k8s.io/api/core/v1" - - "github.com/stretchr/testify/assert" - - "github.com/che-incubator/kubernetes-image-puller-operator/api/v1alpha1" v1 "github.com/eclipse-che/che-operator/api/v1" - "github.com/eclipse-che/che-operator/api/v2alpha1" - "github.com/eclipse-che/che-operator/pkg/util" - "github.com/google/go-cmp/cmp" + v2 "github.com/eclipse-che/che-operator/api/v2" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" - "k8s.io/utils/pointer" - "sigs.k8s.io/yaml" ) -func TestV1ToV2alpha1(t *testing.T) { - tolerations := []corev1.Toleration{ - { - Key: "a", - Operator: corev1.TolerationOpEqual, - Value: "b", - }, - } - - tolBytes, err := json.Marshal(tolerations) - assert.NoError(t, err) +func TestEmptyCheClusterConvertTo(t *testing.T) { + checlusterv1 := &v1.CheCluster{} + checlusterv2 := &v2.CheCluster{} - tolerationStr := string(tolBytes) + err := checlusterv1.ConvertTo(checlusterv2) + assert.Nil(t, err) +} - v1Obj := v1.CheCluster{ +func TestConvertTo(t *testing.T) { + checlusterv1 := &v1.CheCluster{ ObjectMeta: metav1.ObjectMeta{ - Name: "che-cluster", - Annotations: map[string]string{ - "anno1": "annoValue1", - "anno2": "annoValue2", - }, + Name: "eclipse-che", + Namespace: "eclipse-che", }, Spec: v1.CheClusterSpec{ - Auth: v1.CheClusterSpecAuth{ - IdentityProviderURL: "kachny", + Server: v1.CheClusterSpecServer{ + AirGapContainerRegistryHostname: "AirGapContainerRegistryHostname", + AirGapContainerRegistryOrganization: "AirGapContainerRegistryOrganization", + CheImage: "CheImage", + CheImageTag: "CheImageTag", + CheImagePullPolicy: "Always", + CheHost: "CheHost", + CheHostTLSSecret: "CheHostTLSSecret", + CheLogLevel: "CheLogLevel", + CheDebug: "CheDebug", + CheClusterRoles: "CheClusterRoles_1,CheClusterRoles_2", + CheWorkspaceClusterRole: "CheWorkspaceClusterRole", + WorkspaceNamespaceDefault: "WorkspaceNamespaceDefault", + ServerTrustStoreConfigMapName: "ServerTrustStoreConfigMapName", + GitSelfSignedCert: true, + DashboardImage: "DashboardImage", + DashboardImagePullPolicy: "Always", + DashboardMemoryLimit: "DashboardMemoryLimit", + DashboardMemoryRequest: "DashboardMemoryRequest", + DashboardCpuLimit: "DashboardCpuLimit", + DashboardCpuRequest: "DashboardCpuRequest", + DevfileRegistryImage: "DevfileRegistryImage", + DevfileRegistryPullPolicy: "Always", + DevfileRegistryMemoryLimit: "DevfileRegistryMemoryLimit", + DevfileRegistryMemoryRequest: "DevfileRegistryMemoryRequest", + DevfileRegistryCpuLimit: "DevfileRegistryCpuLimit", + DevfileRegistryCpuRequest: "DevfileRegistryCpuRequest", + ExternalDevfileRegistry: true, + ExternalDevfileRegistries: []v1.ExternalDevfileRegistries{ + { + Url: "ExternalDevfileRegistries_1", + }, + { + Url: "ExternalDevfileRegistries_2", + }, + }, + PluginRegistryUrl: "PluginRegistryUrl", + PluginRegistryImage: "PluginRegistryImage", + PluginRegistryPullPolicy: "Always", + PluginRegistryMemoryLimit: "PluginRegistryMemoryLimit", + PluginRegistryMemoryRequest: "PluginRegistryMemoryRequest", + PluginRegistryCpuLimit: "PluginRegistryCpuLimit", + PluginRegistryCpuRequest: "PluginRegistryCpuRequest", + ExternalPluginRegistry: true, + CustomCheProperties: map[string]string{"a": "b", "c": "d"}, + ProxyURL: "ProxyURL", + ProxyPort: "ProxyPort", + ProxySecret: "ProxySecret", + NonProxyHosts: "NonProxyHosts_1|NonProxyHosts_2", + ServerMemoryRequest: "ServerMemoryRequest", + ServerMemoryLimit: "ServerMemoryLimit", + ServerCpuLimit: "ServerCpuLimit", + ServerCpuRequest: "ServerCpuRequest", + SingleHostGatewayImage: "SingleHostGatewayImage", + SingleHostGatewayConfigSidecarImage: "SingleHostGatewayConfigSidecarImage", + SingleHostGatewayConfigMapLabels: map[string]string{"a": "b", "c": "d"}, + CheServerIngress: v1.IngressCustomSettings{ + Labels: "a=b,c=d", + }, + CheServerRoute: v1.RouteCustomSettings{ + Labels: "a=b,c=d", + Annotations: map[string]string{"a": "b", "c": "d"}, + Domain: "CheServerRoute.Domain", + }, + WorkspacesDefaultPlugins: []v1.WorkspacesDefaultPlugins{ + { + Editor: "Editor", + Plugins: []string{"Plugin_1,Plugin_2"}, + }, + }, + WorkspacePodNodeSelector: map[string]string{"a": "b", "c": "d"}, + WorkspacePodTolerations: []corev1.Toleration{ + { + Key: "Key", + Operator: "Operator", + Value: "Value", + Effect: "Effect", + }, + }, }, Database: v1.CheClusterSpecDB{ - ExternalDb: true, - PostgresImage: "postgres:the-best-version", - }, - DevWorkspace: v1.CheClusterSpecDevWorkspace{}, - ImagePuller: v1.CheClusterSpecImagePuller{ - Spec: v1alpha1.KubernetesImagePullerSpec{ - ConfigMapName: "pulled-kachna", + ExternalDb: true, + ChePostgresHostName: "ChePostgresHostName", + ChePostgresPort: "ChePostgresPort", + ChePostgresDb: "ChePostgresDb", + ChePostgresSecret: "ChePostgresSecret", + PostgresImage: "PostgresImage", + PostgresVersion: "PostgresVersion", + PostgresImagePullPolicy: "Always", + PvcClaimSize: "DatabasePvcClaimSize", + ChePostgresContainerResources: v1.ResourcesCustomSettings{ + Requests: v1.Resources{ + Memory: "DatabaseMemoryRequest", + Cpu: "DatabaseCpuRequest", + }, + Limits: v1.Resources{ + Memory: "DatabaseMemoryLimit", + Cpu: "DatabaseCpuLimit", + }, }, }, - K8s: v1.CheClusterSpecK8SOnly{ - IngressDomain: "ingressDomain", - IngressClass: "traefik", - TlsSecretName: "k8sSecret", + Auth: v1.CheClusterSpecAuth{ + IdentityProviderURL: "IdentityProviderURL", + OAuthClientName: "OAuthClientName", + OAuthSecret: "OAuthSecret", + GatewayAuthenticationSidecarImage: "GatewayAuthenticationSidecarImage", + GatewayAuthorizationSidecarImage: "GatewayAuthorizationSidecarImage", + }, + Storage: v1.CheClusterSpecStorage{ + PvcStrategy: "PvcStrategy", + PvcClaimSize: "WorkspacePvcClaimSize", + PreCreateSubPaths: true, + PvcJobsImage: "PvcJobsImage", + PostgresPVCStorageClassName: "PostgresPVCStorageClassName", + WorkspacePVCStorageClassName: "WorkspacePVCStorageClassName", }, Metrics: v1.CheClusterSpecMetrics{ Enable: true, }, - Server: v1.CheClusterSpecServer{ - CheHost: "cheHost", - CheImage: "teh-che-severe", - SingleHostGatewayImage: "single-host-image-of-the-year", - CheHostTLSSecret: "cheSecret", - SingleHostGatewayConfigMapLabels: labels.Set{ - "a": "b", - "c": "d", - }, - CustomCheProperties: map[string]string{ - "CHE_INFRA_OPENSHIFT_ROUTE_HOST_DOMAIN__SUFFIX": "routeDomain", - "CHE_WORKSPACE_POD_TOLERATIONS__JSON": tolerationStr, - "CHE_WORKSPACE_POD_NODE__SELECTOR": "a=b,c=d", - }, + K8s: v1.CheClusterSpecK8SOnly{ + IngressDomain: "k8s.IngressDomain", + IngressClass: "k8s.IngressClass", + TlsSecretName: "k8s.TlsSecretName", + SecurityContextFsGroup: "SecurityContextFsGroup", + SecurityContextRunAsUser: "SecurityContextRunAsUser", }, - Storage: v1.CheClusterSpecStorage{ - PvcStrategy: "common", + ImagePuller: v1.CheClusterSpecImagePuller{ + Enable: true, + }, + DevWorkspace: v1.CheClusterSpecDevWorkspace{ + Enable: true, + ControllerImage: "ControllerImage", + RunningLimit: "RunningLimit", + }, + Dashboard: v1.CheClusterSpecDashboard{ + Warning: "DashboardWarning", }, }, + Status: v1.CheClusterStatus{ + CheClusterRunning: "Available", + CheVersion: "CheVersion", + CheURL: "CheURL", + Message: "Message", + Reason: "Reason", + HelpLink: "HelpLink", + DevfileRegistryURL: "DevfileRegistryURL", + PluginRegistryURL: "PluginRegistryURL", + }, } - t.Run("origInAnnos", func(t *testing.T) { - v2 := &v2alpha1.CheCluster{} - err := V1ToV2alpha1(&v1Obj, v2) - if err != nil { - t.Error(err) - } - - anno1 := v2.Annotations["anno1"] - anno2 := v2.Annotations["anno2"] - storedV1 := v2.Annotations[v1StorageAnnotation] - - if anno1 != "annoValue1" { - t.Errorf("anno1 not copied") - } - - if anno2 != "annoValue2" { - t.Errorf("anno2 not copied") - } - - if storedV1 == "" { - t.Errorf("v2 should contain v1 data in annnotation") - } - - restoredV1Spec := v1.CheClusterSpec{} - if err = yaml.Unmarshal([]byte(storedV1), &restoredV1Spec); err != nil { - t.Error(err) - } - - if !reflect.DeepEqual(&v1Obj.Spec, &restoredV1Spec) { - t.Errorf("The spec should be restored verbatim from the annotations, but there's a diff %s", cmp.Diff(&v1Obj.Spec, &restoredV1Spec)) - } - }) - - t.Run("Enabled", func(t *testing.T) { - v2 := &v2alpha1.CheCluster{} - err := V1ToV2alpha1(&v1Obj, v2) - if err != nil { - t.Error(err) - } - - if !*v2.Spec.Enabled { - t.Errorf("Unexpected v2.Spec.Enabled: %t", *v2.Spec.Enabled) - } - }) - - t.Run("Host-k8s", func(t *testing.T) { - v2 := &v2alpha1.CheCluster{} - err := V1ToV2alpha1(&v1Obj, v2) - if err != nil { - t.Error(err) - } - - if v2.Spec.Gateway.Host != "cheHost" { - t.Errorf("Unexpected v2.Spec.Host: %s", v2.Spec.Gateway.Host) - } - }) - - t.Run("WorkspaceDomainEndpointsBaseDomain-k8s", func(t *testing.T) { - onFakeKubernetes(func() { - v2 := &v2alpha1.CheCluster{} - err := V1ToV2alpha1(&v1Obj, v2) - if err != nil { - t.Error(err) - } - - if v2.Spec.Workspaces.DomainEndpoints.BaseDomain != "ingressDomain" { - t.Errorf("Unexpected v2.Spec.Workspaces.DomainEndpoints.BaseDomain: %s", v2.Spec.Workspaces.DomainEndpoints.BaseDomain) - } - }) - }) - - t.Run("WorkspaceDomainEndpointsBaseDomain-opensfhit", func(t *testing.T) { - onFakeOpenShift(func() { - v2 := &v2alpha1.CheCluster{} - err := V1ToV2alpha1(&v1Obj, v2) - if err != nil { - t.Error(err) - } - - if v2.Spec.Workspaces.DomainEndpoints.BaseDomain != "routeDomain" { - t.Errorf("Unexpected v2.Spec.Workspaces.DomainEndpoints.BaseDomain: %s", v2.Spec.Workspaces.DomainEndpoints.BaseDomain) - } - }) - }) - - t.Run("WorkspaceDomainEndpointsTlsSecretName_k8s", func(t *testing.T) { - onFakeKubernetes(func() { - v2 := &v2alpha1.CheCluster{} - err := V1ToV2alpha1(&v1Obj, v2) - if err != nil { - t.Error(err) - } - - if v2.Spec.Workspaces.DomainEndpoints.TlsSecretName != "k8sSecret" { - t.Errorf("Unexpected TlsSecretName") - } - }) - }) - - t.Run("WorkspaceDomainEndpointsTlsSecretName_OpenShift", func(t *testing.T) { - onFakeOpenShift(func() { - v2 := &v2alpha1.CheCluster{} - err := V1ToV2alpha1(&v1Obj, v2) - if err != nil { - t.Error(err) - } - - if v2.Spec.Workspaces.DomainEndpoints.TlsSecretName != "" { - t.Errorf("Unexpected TlsSecretName") - } - }) - }) - - t.Run("GatewayEnabled", func(t *testing.T) { - onFakeOpenShift(func() { - v2 := &v2alpha1.CheCluster{} - err := V1ToV2alpha1(&v1Obj, v2) - if err != nil { - t.Error(err) - } - - if v2.Spec.Gateway.Enabled == nil { - t.Logf("The gateway.enabled attribute should be set explicitly after the conversion.") - t.FailNow() - } - - if !*v2.Spec.Gateway.Enabled { - t.Errorf("The default for OpenShift is single") - } - }) - }) - - t.Run("GatewayImage", func(t *testing.T) { - v2 := &v2alpha1.CheCluster{} - err := V1ToV2alpha1(&v1Obj, v2) - if err != nil { - t.Error(err) - } - - if v2.Spec.Gateway.Image != "single-host-image-of-the-year" { - t.Errorf("Unexpected gateway image") - } - }) - - t.Run("GatewayTlsSecretName", func(t *testing.T) { - v2 := &v2alpha1.CheCluster{} - err := V1ToV2alpha1(&v1Obj, v2) - if err != nil { - t.Error(err) - } - - if v2.Spec.Gateway.TlsSecretName != "cheSecret" { - t.Errorf("Unexpected TlsSecretName") - } - }) - - t.Run("GatewayConfigLabels", func(t *testing.T) { - v2 := &v2alpha1.CheCluster{} - err := V1ToV2alpha1(&v1Obj, v2) - if err != nil { - t.Error(err) - } - - if !reflect.DeepEqual(v2.Spec.Gateway.ConfigLabels, v1Obj.Spec.Server.SingleHostGatewayConfigMapLabels) { - t.Errorf("Unexpected Spec.Gateway.ConfigLabels: %v", cmp.Diff(v1Obj.Spec.Server.SingleHostGatewayConfigMapLabels, v2.Spec.Gateway.ConfigLabels)) - } - }) + checlusterv2 := &v2.CheCluster{} + err := checlusterv1.ConvertTo(checlusterv2) + assert.Nil(t, err) + + assert.Equal(t, checlusterv2.ObjectMeta.Name, "eclipse-che") + assert.Equal(t, checlusterv2.ObjectMeta.Namespace, "eclipse-che") + + assert.Equal(t, checlusterv2.Spec.Auth.Gateway.AuthenticationSidecarImage, "GatewayAuthenticationSidecarImage") + assert.Equal(t, checlusterv2.Spec.Auth.Gateway.AuthorizationSidecarImage, "GatewayAuthorizationSidecarImage") + assert.Equal(t, checlusterv2.Spec.Auth.Gateway.ConfigLabels, map[string]string{"a": "b", "c": "d"}) + assert.Equal(t, checlusterv2.Spec.Auth.Gateway.ConfigSidecarImage, "SingleHostGatewayConfigSidecarImage") + assert.Equal(t, checlusterv2.Spec.Auth.Gateway.Image, "SingleHostGatewayImage") + assert.Equal(t, checlusterv2.Spec.Auth.Gateway.Ingress.Annotations, map[string]string{"kubernetes.io/ingress.class": "k8s.IngressClass", "nginx.ingress.kubernetes.io/proxy-connect-timeout": "3600", "nginx.ingress.kubernetes.io/proxy-read-timeout": "3600", "nginx.ingress.kubernetes.io/ssl-redirect": "true"}) + assert.Equal(t, checlusterv2.Spec.Auth.Gateway.Ingress.Domain, "k8s.IngressDomain") + assert.Equal(t, checlusterv2.Spec.Auth.Gateway.Ingress.Host, "CheHost") + assert.Equal(t, checlusterv2.Spec.Auth.Gateway.Ingress.Labels, map[string]string{"a": "b", "c": "d"}) + assert.Equal(t, checlusterv2.Spec.Auth.Gateway.Ingress.TlsSecretRef, "k8s.TlsSecretName") + assert.Equal(t, checlusterv2.Spec.Auth.Gateway.Route.Annotations, map[string]string{"a": "b", "c": "d"}) + assert.Equal(t, checlusterv2.Spec.Auth.Gateway.Route.Domain, "CheServerRoute.Domain") + assert.Equal(t, checlusterv2.Spec.Auth.Gateway.Route.Host, "CheHost") + assert.Equal(t, checlusterv2.Spec.Auth.Gateway.Route.Labels, map[string]string{"a": "b", "c": "d"}) + assert.Equal(t, checlusterv2.Spec.Auth.Gateway.Route.TlsSecretRef, "CheHostTLSSecret") + assert.Equal(t, checlusterv2.Spec.Auth.IdentityProviderURL, "IdentityProviderURL") + assert.Equal(t, checlusterv2.Spec.Auth.OAuthClientName, "OAuthClientName") + assert.Equal(t, checlusterv2.Spec.Auth.OAuthSecret, "OAuthSecret") + + assert.Equal(t, checlusterv2.Spec.Server.AirGapContainerRegistryHostname, "AirGapContainerRegistryHostname") + assert.Equal(t, checlusterv2.Spec.Server.AirGapContainerRegistryOrganization, "AirGapContainerRegistryOrganization") + assert.Equal(t, checlusterv2.Spec.Server.ClusterRoles, []string{"CheClusterRoles_1", "CheClusterRoles_2"}) + assert.Equal(t, checlusterv2.Spec.Server.CustomCheProperties, map[string]string{"a": "b", "c": "d"}) + assert.Equal(t, checlusterv2.Spec.Server.Debug, "CheDebug") + assert.Equal(t, checlusterv2.Spec.Server.Deployment.Container.Image, "CheImage:CheImageTag") + assert.Equal(t, checlusterv2.Spec.Server.Deployment.Container.ImagePullPolicy, corev1.PullPolicy("Always")) + assert.Equal(t, checlusterv2.Spec.Server.Deployment.Container.Resources.Limits.Cpu, "ServerCpuLimit") + assert.Equal(t, checlusterv2.Spec.Server.Deployment.Container.Resources.Limits.Memory, "ServerMemoryLimit") + assert.Equal(t, checlusterv2.Spec.Server.Deployment.Container.Resources.Requests.Cpu, "ServerCpuRequest") + assert.Equal(t, checlusterv2.Spec.Server.Deployment.Container.Resources.Requests.Memory, "ServerMemoryRequest") + assert.Equal(t, checlusterv2.Spec.Server.Deployment.SecurityContext.FsGroup, "SecurityContextFsGroup") + assert.Equal(t, checlusterv2.Spec.Server.Deployment.SecurityContext.RunAsUser, "SecurityContextRunAsUser") + assert.Equal(t, checlusterv2.Spec.Server.GitSelfSignedCert, true) + assert.Equal(t, checlusterv2.Spec.Server.LogLevel, "CheLogLevel") + assert.Equal(t, checlusterv2.Spec.Server.Proxy.CredentialsSecretRef, "ProxySecret") + assert.Equal(t, checlusterv2.Spec.Server.Proxy.NonProxyHosts, []string{"NonProxyHosts_1", "NonProxyHosts_2"}) + assert.Equal(t, checlusterv2.Spec.Server.Proxy.Port, "ProxyPort") + assert.Equal(t, checlusterv2.Spec.Server.Proxy.Url, "ProxyURL") + assert.Equal(t, checlusterv2.Spec.Server.ServerTrustStoreConfigMapName, "ServerTrustStoreConfigMapName") + assert.Equal(t, checlusterv2.Spec.Server.WorkspaceNamespaceName, "WorkspaceNamespaceDefault") + assert.Equal(t, checlusterv2.Spec.Server.WorkspacePodNodeSelector, map[string]string{"a": "b", "c": "d"}) + assert.Equal(t, checlusterv2.Spec.Server.WorkspacePodTolerations, []corev1.Toleration{{ + Key: "Key", + Operator: "Operator", + Value: "Value", + Effect: "Effect", + }}) + assert.Equal(t, checlusterv2.Spec.Server.WorkspaceServiceAccountClusterRole, []string{"CheWorkspaceClusterRole"}) + assert.Equal(t, checlusterv2.Spec.Server.WorkspacesDefaultPlugins, []v2.WorkspacesDefaultPlugins{{ + Editor: "Editor", + Plugins: []string{"Plugin_1,Plugin_2"}, + }}) + + assert.Equal(t, checlusterv2.Spec.Dashboard.Deployment.Container.Image, "DashboardImage") + assert.Equal(t, checlusterv2.Spec.Dashboard.Deployment.Container.ImagePullPolicy, corev1.PullPolicy("Always")) + assert.Equal(t, checlusterv2.Spec.Dashboard.Deployment.Container.Resources.Limits.Cpu, "DashboardCpuLimit") + assert.Equal(t, checlusterv2.Spec.Dashboard.Deployment.Container.Resources.Limits.Memory, "DashboardMemoryLimit") + assert.Equal(t, checlusterv2.Spec.Dashboard.Deployment.Container.Resources.Requests.Cpu, "DashboardCpuRequest") + assert.Equal(t, checlusterv2.Spec.Dashboard.Deployment.Container.Resources.Requests.Memory, "DashboardMemoryRequest") + assert.Equal(t, checlusterv2.Spec.Dashboard.Deployment.SecurityContext.FsGroup, "SecurityContextFsGroup") + assert.Equal(t, checlusterv2.Spec.Dashboard.Deployment.SecurityContext.RunAsUser, "SecurityContextRunAsUser") + assert.Equal(t, checlusterv2.Spec.Dashboard.Warning, "DashboardWarning") + + assert.Equal(t, checlusterv2.Spec.Database.CredentialsSecretRef, "ChePostgresSecret") + assert.Equal(t, checlusterv2.Spec.Database.Deployment.Container.Image, "PostgresImage") + assert.Equal(t, checlusterv2.Spec.Database.Deployment.Container.ImagePullPolicy, corev1.PullPolicy("Always")) + assert.Equal(t, checlusterv2.Spec.Database.Deployment.Container.Resources.Limits.Cpu, "DatabaseCpuLimit") + assert.Equal(t, checlusterv2.Spec.Database.Deployment.Container.Resources.Limits.Memory, "DatabaseMemoryLimit") + assert.Equal(t, checlusterv2.Spec.Database.Deployment.Container.Resources.Requests.Cpu, "DatabaseCpuRequest") + assert.Equal(t, checlusterv2.Spec.Database.Deployment.Container.Resources.Requests.Memory, "DatabaseMemoryRequest") + assert.Equal(t, checlusterv2.Spec.Database.Deployment.SecurityContext.FsGroup, "SecurityContextFsGroup") + assert.Equal(t, checlusterv2.Spec.Database.Deployment.SecurityContext.RunAsUser, "SecurityContextRunAsUser") + assert.Equal(t, checlusterv2.Spec.Database.ExternalDb, true) + assert.Equal(t, checlusterv2.Spec.Database.PostgresDb, "ChePostgresDb") + assert.Equal(t, checlusterv2.Spec.Database.PostgresHostName, "ChePostgresHostName") + assert.Equal(t, checlusterv2.Spec.Database.PostgresPort, "ChePostgresPort") + assert.Equal(t, checlusterv2.Spec.Database.PostgresVersion, "PostgresVersion") + assert.Equal(t, checlusterv2.Spec.Database.Pvc.ClaimSize, "DatabasePvcClaimSize") + assert.Equal(t, checlusterv2.Spec.Database.Pvc.StorageClass, "PostgresPVCStorageClassName") + + assert.Equal(t, checlusterv2.Spec.DevWorkspace.Deployment.Container.Image, "ControllerImage") + assert.Equal(t, checlusterv2.Spec.DevWorkspace.RunningLimit, "RunningLimit") + assert.Equal(t, checlusterv2.Spec.ImagePuller.Enable, true) + assert.Equal(t, checlusterv2.Spec.Metrics.Enable, true) + + assert.Equal(t, checlusterv2.Spec.DevfileRegistry.Deployment.Container.Image, "DevfileRegistryImage") + assert.Equal(t, checlusterv2.Spec.DevfileRegistry.Deployment.Container.ImagePullPolicy, corev1.PullPolicy("Always")) + assert.Equal(t, checlusterv2.Spec.DevfileRegistry.Deployment.Container.Resources.Limits.Cpu, "DevfileRegistryCpuLimit") + assert.Equal(t, checlusterv2.Spec.DevfileRegistry.Deployment.Container.Resources.Limits.Memory, "DevfileRegistryMemoryLimit") + assert.Equal(t, checlusterv2.Spec.DevfileRegistry.Deployment.Container.Resources.Requests.Cpu, "DevfileRegistryCpuRequest") + assert.Equal(t, checlusterv2.Spec.DevfileRegistry.Deployment.Container.Resources.Requests.Memory, "DevfileRegistryMemoryRequest") + assert.Equal(t, checlusterv2.Spec.DevfileRegistry.Deployment.SecurityContext.FsGroup, "SecurityContextFsGroup") + assert.Equal(t, checlusterv2.Spec.DevfileRegistry.Deployment.SecurityContext.RunAsUser, "SecurityContextRunAsUser") + assert.Equal(t, checlusterv2.Spec.DevfileRegistry.DisableInternalRegistry, true) + assert.Equal(t, checlusterv2.Spec.DevfileRegistry.ExternalDevfileRegistries, []v2.ExternalDevfileRegistry{ + { + Url: "ExternalDevfileRegistries_1", + }, + { + Url: "ExternalDevfileRegistries_2", + }}) + + assert.Equal(t, checlusterv2.Spec.PluginRegistry.Deployment.Container.Image, "PluginRegistryImage") + assert.Equal(t, checlusterv2.Spec.PluginRegistry.Deployment.Container.ImagePullPolicy, corev1.PullPolicy("Always")) + assert.Equal(t, checlusterv2.Spec.PluginRegistry.Deployment.Container.Resources.Limits.Cpu, "PluginRegistryCpuLimit") + assert.Equal(t, checlusterv2.Spec.PluginRegistry.Deployment.Container.Resources.Limits.Memory, "PluginRegistryMemoryLimit") + assert.Equal(t, checlusterv2.Spec.PluginRegistry.Deployment.Container.Resources.Requests.Cpu, "PluginRegistryCpuRequest") + assert.Equal(t, checlusterv2.Spec.PluginRegistry.Deployment.Container.Resources.Requests.Memory, "PluginRegistryMemoryRequest") + assert.Equal(t, checlusterv2.Spec.PluginRegistry.Deployment.SecurityContext.FsGroup, "SecurityContextFsGroup") + assert.Equal(t, checlusterv2.Spec.PluginRegistry.Deployment.SecurityContext.RunAsUser, "SecurityContextRunAsUser") + assert.Equal(t, checlusterv2.Spec.PluginRegistry.DisableInternalRegistry, true) + assert.Equal(t, checlusterv2.Spec.PluginRegistry.ExternalPluginRegistries, []v2.ExternalPluginRegistry{{Url: "PluginRegistryUrl"}}) + + assert.Equal(t, checlusterv2.Spec.Storage.PreCreateSubPaths, true) + assert.Equal(t, checlusterv2.Spec.Storage.Pvc.ClaimSize, "WorkspacePvcClaimSize") + assert.Equal(t, checlusterv2.Spec.Storage.Pvc.StorageClass, "WorkspacePVCStorageClassName") + assert.Equal(t, checlusterv2.Spec.Storage.PvcJobsImage, "PvcJobsImage") + assert.Equal(t, checlusterv2.Spec.Storage.PvcStrategy, "PvcStrategy") + + assert.Equal(t, checlusterv2.Status.CheURL, "CheURL") + assert.Equal(t, checlusterv2.Status.CheVersion, "CheVersion") + assert.Equal(t, checlusterv2.Status.DevfileRegistryURL, "DevfileRegistryURL") + assert.Equal(t, checlusterv2.Status.HelpLink, "HelpLink") + assert.Equal(t, checlusterv2.Status.Message, "Message") + assert.Equal(t, checlusterv2.Status.Phase, v2.ClusterPhase("Active")) + assert.Equal(t, checlusterv2.Status.PluginRegistryURL, "PluginRegistryURL") + assert.Equal(t, checlusterv2.Status.Reason, "Reason") +} - t.Run("WorkspacePodSelector", func(t *testing.T) { - v2 := &v2alpha1.CheCluster{} - assert.NoError(t, V1ToV2alpha1(&v1Obj, v2)) - assert.Equal(t, map[string]string{"a": "b", "c": "d"}, v2.Spec.Workspaces.PodNodeSelector) - }) +func TestConvertFromEmptyCheCluster(t *testing.T) { + checlusterv1 := &v1.CheCluster{} + checlusterv2 := &v2.CheCluster{} - t.Run("WorkspacePodTolerations", func(t *testing.T) { - v2 := &v2alpha1.CheCluster{} - assert.NoError(t, V1ToV2alpha1(&v1Obj, v2)) - assert.Equal(t, tolerations, v2.Spec.Workspaces.PodTolerations) - }) + err := checlusterv1.ConvertFrom(checlusterv2) + assert.Nil(t, err) } -func TestV2alpha1ToV1(t *testing.T) { - v2Obj := v2alpha1.CheCluster{ +func TestConvertFrom(t *testing.T) { + checlusterv2 := &v2.CheCluster{ ObjectMeta: metav1.ObjectMeta{ - Name: "che-cluster", - Annotations: map[string]string{ - "anno1": "annoValue1", - "anno2": "annoValue2", - }, + Name: "eclipse-che", + Namespace: "eclipse-che", }, - Spec: v2alpha1.CheClusterSpec{ - Enabled: pointer.BoolPtr(true), - Workspaces: v2alpha1.Workspaces{ - DomainEndpoints: v2alpha1.DomainEndpoints{ - BaseDomain: "baseDomain", - TlsSecretName: "workspaceSecret", + Spec: v2.CheClusterSpec{ + Server: v2.CheClusterSpecServer{ + Deployment: v2.DeploymentCustomSettings{ + Container: v2.ContainerCustomSettings{ + Image: "ServerImage:ServerTag", + ImagePullPolicy: corev1.PullAlways, + Resources: v2.ResourceRequirementsCustomSettings{ + Requests: v2.ResourceListCustomSettings{ + Memory: "ServerMemoryRequest", + Cpu: "ServerCpuRequest", + }, + Limits: v2.ResourceListCustomSettings{ + Memory: "ServerMemoryLimit", + Cpu: "ServerCpuLimit", + }, + }, + }, + SecurityContext: v2.PodSecurityContextCustomSettings{ + RunAsUser: "RunAsUser", + FsGroup: "FsGroup", + }, }, - PodNodeSelector: map[string]string{"a": "b", "c": "d"}, - PodTolerations: []corev1.Toleration{ + AirGapContainerRegistryHostname: "AirGapContainerRegistryHostname", + AirGapContainerRegistryOrganization: "AirGapContainerRegistryOrganization", + LogLevel: "LogLevel", + Debug: "Debug", + ClusterRoles: []string{"ClusterRoles_1", "ClusterRoles_2"}, + WorkspaceServiceAccountClusterRole: []string{"WorkspaceServiceAccountClusterRole"}, + WorkspaceNamespaceName: "WorkspaceNamespaceName", + ServerTrustStoreConfigMapName: "ServerTrustStoreConfigMapName", + GitSelfSignedCert: true, + Proxy: v2.Proxy{ + Url: "ProxyUrl", + Port: "ProxyPort", + NonProxyHosts: []string{"NonProxyHosts_1", "NonProxyHosts_2"}, + CredentialsSecretRef: "ProxyCredentialsSecretRef", + }, + CustomCheProperties: map[string]string{"a": "b", "c": "d"}, + WorkspacesDefaultPlugins: []v2.WorkspacesDefaultPlugins{ { - Key: "a", - Operator: corev1.TolerationOpEqual, - Value: "b", + Editor: "Editor", + Plugins: []string{"Plugins_1", "Plugins_2"}, }, }, + WorkspacePodNodeSelector: map[string]string{"a": "b", "c": "d"}, + WorkspacePodTolerations: []corev1.Toleration{{ + Key: "Key", + Operator: "Operator", + Value: "Value", + Effect: "Effect", + }}, }, - Gateway: v2alpha1.CheGatewaySpec{ - Host: "v2Host", - Enabled: pointer.BoolPtr(true), - Image: "gateway-image", - ConfigurerImage: "configurer-image", - TlsSecretName: "superSecret", - ConfigLabels: labels.Set{ - "a": "b", + Database: v2.CheClusterSpecDB{ + ExternalDb: true, + Deployment: v2.DeploymentCustomSettings{ + Container: v2.ContainerCustomSettings{ + Image: "DatabaseImage", + ImagePullPolicy: corev1.PullAlways, + Resources: v2.ResourceRequirementsCustomSettings{ + Requests: v2.ResourceListCustomSettings{ + Memory: "DatabaseMemoryRequest", + Cpu: "DatabaseCpuRequest", + }, + Limits: v2.ResourceListCustomSettings{ + Memory: "DatabaseMemoryLimit", + Cpu: "DatabaseCpuLimit", + }, + }, + }, + SecurityContext: v2.PodSecurityContextCustomSettings{ + RunAsUser: "RunAsUser", + FsGroup: "FsGroup", + }, }, - }, - K8s: v2alpha1.CheClusterSpecK8s{ - IngressAnnotations: map[string]string{ - "kubernetes.io/ingress.class": "some-other-ingress", - "a": "b", + PostgresHostName: "PostgresHostName", + PostgresPort: "PostgresPort", + PostgresDb: "PostgresDb", + CredentialsSecretRef: "DatabaseCredentialsSecretRef", + PostgresVersion: "PostgresVersion", + Pvc: v2.PVC{ + ClaimSize: "DatabaseClaimSize", + StorageClass: "DatabaseStorageClass", }, }, - }, - } - - t.Run("origInAnnos", func(t *testing.T) { - v1 := &v1.CheCluster{} - err := V2alpha1ToV1(&v2Obj, v1) - if err != nil { - t.Error(err) - } - - anno1 := v1.Annotations["anno1"] - anno2 := v1.Annotations["anno2"] - storedV2 := v1.Annotations[v2alpha1StorageAnnotation] - - if anno1 != "annoValue1" { - t.Errorf("anno1 not copied") - } - - if anno2 != "annoValue2" { - t.Errorf("anno2 not copied") - } - - if storedV2 == "" { - t.Errorf("v1 should contain v2 data in annnotation") - } - - restoredV2Spec := v2alpha1.CheClusterSpec{} - yaml.Unmarshal([]byte(storedV2), &restoredV2Spec) - - if !reflect.DeepEqual(&v2Obj.Spec, &restoredV2Spec) { - t.Errorf("The spec should be restored verbatim from the annotations, but there's a diff %s", cmp.Diff(&v2Obj.Spec, &restoredV2Spec)) - } - }) - - t.Run("Host", func(t *testing.T) { - v1 := &v1.CheCluster{} - err := V2alpha1ToV1(&v2Obj, v1) - if err != nil { - t.Error(err) - } - - if v1.Spec.Server.CheHost != "v2Host" { - t.Errorf("Unexpected v1.Spec.Server.CheHost: %s", v1.Spec.Server.CheHost) - } - }) - - t.Run("WorkspaceDomainEndpointsBaseDomain-k8s", func(t *testing.T) { - onFakeKubernetes(func() { - v1 := &v1.CheCluster{} - err := V2alpha1ToV1(&v2Obj, v1) - if err != nil { - t.Error(err) - } - - if v1.Spec.K8s.IngressDomain != "baseDomain" { - t.Errorf("Unexpected v1.Spec.K8s.IngressDomain: %s", v1.Spec.K8s.IngressDomain) - } - }) - }) - - t.Run("WorkspaceDomainEndpointsBaseDomain-openshift", func(t *testing.T) { - onFakeOpenShift(func() { - v1 := &v1.CheCluster{} - err := V2alpha1ToV1(&v2Obj, v1) - if err != nil { - t.Error(err) - } - - if v1.Spec.Server.CustomCheProperties[routeDomainSuffixPropertyKey] != "baseDomain" { - t.Errorf("Unexpected v1.Spec.Server.CustomCheProperties[%s]: %s", routeDomainSuffixPropertyKey, v1.Spec.Server.CustomCheProperties[routeDomainSuffixPropertyKey]) - } - }) - }) - - t.Run("WorkspaceDomainEndpointsBaseDomain-openshift-should-not-be-set-empty-value", func(t *testing.T) { - onFakeOpenShift(func() { - v1 := &v1.CheCluster{} - v2apha := v2Obj.DeepCopy() - v2apha.Spec.Workspaces.DomainEndpoints.BaseDomain = "" - err := V2alpha1ToV1(v2apha, v1) - if err != nil { - t.Error(err) - } - - if _, ok := v1.Spec.Server.CustomCheProperties[routeDomainSuffixPropertyKey]; ok { - t.Errorf("Unexpected value. We shouldn't set key with empty value for %s custom Che property", routeDomainSuffixPropertyKey) - } - }) - }) - - t.Run("WorkspaceDomainEndpointsTlsSecretName_k8s", func(t *testing.T) { - onFakeKubernetes(func() { - v1 := &v1.CheCluster{} - err := V2alpha1ToV1(&v2Obj, v1) - if err != nil { - t.Error(err) - } - - if v1.Spec.K8s.TlsSecretName != "workspaceSecret" { - t.Errorf("Unexpected TlsSecretName: %s", v1.Spec.K8s.TlsSecretName) - } - }) - }) - - t.Run("WorkspaceDomainEndpointsTlsSecretName_OpenShift", func(t *testing.T) { - onFakeOpenShift(func() { - v1 := &v1.CheCluster{} - err := V2alpha1ToV1(&v2Obj, v1) - if err != nil { - t.Error(err) - } - - if v1.Spec.K8s.TlsSecretName != "" { - t.Errorf("Unexpected TlsSecretName") - } - }) - }) - - t.Run("GatewayEnabled", func(t *testing.T) { - onFakeOpenShift(func() { - v1 := &v1.CheCluster{} - err := V2alpha1ToV1(&v2Obj, v1) - if err != nil { - t.Error(err) - } - }) - }) - - t.Run("GatewayImage", func(t *testing.T) { - v1 := &v1.CheCluster{} - err := V2alpha1ToV1(&v2Obj, v1) - if err != nil { - t.Error(err) - } - - if v1.Spec.Server.SingleHostGatewayImage != "gateway-image" { - t.Errorf("Unexpected gateway image") - } - }) - - t.Run("GatewayTlsSecretName", func(t *testing.T) { - v1 := &v1.CheCluster{} - err := V2alpha1ToV1(&v2Obj, v1) - if err != nil { - t.Error(err) - } - - if v1.Spec.Server.CheHostTLSSecret != "superSecret" { - t.Errorf("Unexpected TlsSecretName: %s", v1.Spec.Server.CheHostTLSSecret) - } - }) - - t.Run("GatewayConfigLabels", func(t *testing.T) { - v1 := &v1.CheCluster{} - err := V2alpha1ToV1(&v2Obj, v1) - if err != nil { - t.Error(err) - } - - if !reflect.DeepEqual(v1.Spec.Server.SingleHostGatewayConfigMapLabels, v2Obj.Spec.Gateway.ConfigLabels) { - t.Errorf("Unexpected SingleHostGatewayConfigMapLabels: %s", v1.Spec.Server.SingleHostGatewayConfigMapLabels) - } - }) - - t.Run("WorkspacePodNodeSelector", func(t *testing.T) { - v1 := &v1.CheCluster{} - assert.NoError(t, V2alpha1ToV1(&v2Obj, v1)) - assert.Equal(t, map[string]string{"a": "b", "c": "d"}, v1.Spec.Server.WorkspacePodNodeSelector) - }) - - t.Run("WorkspacePodTolerations", func(t *testing.T) { - v1 := &v1.CheCluster{} - assert.NoError(t, V2alpha1ToV1(&v2Obj, v1)) - assert.Equal(t, []corev1.Toleration{{ - Key: "a", - Operator: corev1.TolerationOpEqual, - Value: "b", - }}, v1.Spec.Server.WorkspacePodTolerations) - - }) -} - -func TestFullCircleV1(t *testing.T) { - v1Obj := v1.CheCluster{ - ObjectMeta: metav1.ObjectMeta{ - Name: "che-cluster", - Annotations: map[string]string{ - "anno1": "annoValue1", - "anno2": "annoValue2", - }, - }, - Spec: v1.CheClusterSpec{ - Auth: v1.CheClusterSpecAuth{ - IdentityProviderURL: "kachny", - }, - Database: v1.CheClusterSpecDB{ - ExternalDb: true, - PostgresImage: "postgres:the-best-version", - }, - DevWorkspace: v1.CheClusterSpecDevWorkspace{}, - ImagePuller: v1.CheClusterSpecImagePuller{ - Spec: v1alpha1.KubernetesImagePullerSpec{ - ConfigMapName: "pulled-kachna", + Auth: v2.CheClusterSpecAuth{ + IdentityProviderURL: "IdentityProviderURL", + OAuthClientName: "OAuthClientName", + OAuthSecret: "OAuthSecret", + Gateway: v2.GatewayCustomSettings{ + Image: "GatewayImage", + ConfigSidecarImage: "ConfigSidecarImage", + AuthenticationSidecarImage: "AuthenticationSidecarImage", + AuthorizationSidecarImage: "AuthorizationSidecarImage", + ConfigLabels: map[string]string{"a": "b", "c": "d"}, + Ingress: v2.IngressCustomSettings{ + Labels: map[string]string{"a": "b", "c": "d"}, + Annotations: map[string]string{"a": "b", "c": "d", "kubernetes.io/ingress.class": "k8s.IngressClass"}, + Domain: "IngressDomain", + Host: "IngressHost", + TlsSecretRef: "IngressTlsSecretRef", + }, + Route: v2.RouteCustomSettings{ + Labels: map[string]string{"a": "b", "c": "d"}, + Annotations: map[string]string{"a": "b", "c": "d"}, + Domain: "RouteDomain", + Host: "RouteHost", + TlsSecretRef: "RouteTlsSecretRef", + }, }, }, - K8s: v1.CheClusterSpecK8SOnly{ - IngressDomain: "ingressDomain", - IngressClass: "traefik", - TlsSecretName: "k8sSecret", - }, - Metrics: v1.CheClusterSpecMetrics{ - Enable: true, - }, - Server: v1.CheClusterSpecServer{ - CheHost: "cheHost", - CheImage: "teh-che-severe", - SingleHostGatewayImage: "single-host-image-of-the-year", - CheHostTLSSecret: "cheSecret", - SingleHostGatewayConfigMapLabels: labels.Set{ - "a": "b", + PluginRegistry: v2.CheClusterSpecPluginRegistry{ + Deployment: v2.DeploymentCustomSettings{ + Container: v2.ContainerCustomSettings{ + Image: "PluginRegistryImage", + ImagePullPolicy: corev1.PullAlways, + Resources: v2.ResourceRequirementsCustomSettings{ + Requests: v2.ResourceListCustomSettings{ + Memory: "PluginRegistryMemoryRequest", + Cpu: "PluginRegistryCpuRequest", + }, + Limits: v2.ResourceListCustomSettings{ + Memory: "PluginRegistryMemoryLimit", + Cpu: "PluginRegistryCpuLimit", + }, + }, + }, + SecurityContext: v2.PodSecurityContextCustomSettings{ + RunAsUser: "RunAsUser", + FsGroup: "FsGroup", + }, }, - CustomCheProperties: map[string]string{ - "CHE_INFRA_OPENSHIFT_ROUTE_HOST_DOMAIN__SUFFIX": "routeDomain", + DisableInternalRegistry: true, + ExternalPluginRegistries: []v2.ExternalPluginRegistry{ + { + Url: "ExternalPluginRegistries_1", + }, + { + Url: "ExternalPluginRegistries_2", + }, }, }, - Storage: v1.CheClusterSpecStorage{ - PvcStrategy: "common", - }, - }, - } - - v2Obj := v2alpha1.CheCluster{} - assert.NoError(t, V1ToV2alpha1(&v1Obj, &v2Obj)) - - convertedV1 := v1.CheCluster{} - assert.NoError(t, V2alpha1ToV1(&v2Obj, &convertedV1)) - - assert.Empty(t, convertedV1.Annotations[v1StorageAnnotation]) - assert.NotEmpty(t, convertedV1.Annotations[v2alpha1StorageAnnotation]) - - // remove v2 content annotation on the convertedV1 so that it doesn't interfere with the equality. - delete(convertedV1.Annotations, v2alpha1StorageAnnotation) - - assert.Equal(t, &v1Obj, &convertedV1) -} - -func TestFullCircleV2(t *testing.T) { - v2Obj := v2alpha1.CheCluster{ - ObjectMeta: metav1.ObjectMeta{ - Name: "che-cluster", - Annotations: map[string]string{ - "anno1": "annoValue1", - "anno2": "annoValue2", + DevfileRegistry: v2.CheClusterSpecDevfileRegistry{ + Deployment: v2.DeploymentCustomSettings{ + Container: v2.ContainerCustomSettings{ + Image: "DevfileRegistryImage", + ImagePullPolicy: corev1.PullAlways, + Resources: v2.ResourceRequirementsCustomSettings{ + Requests: v2.ResourceListCustomSettings{ + Memory: "DevfileRegistryMemoryRequest", + Cpu: "DevfileRegistryCpuRequest", + }, + Limits: v2.ResourceListCustomSettings{ + Memory: "DevfileRegistryMemoryLimit", + Cpu: "DevfileRegistryCpuLimit", + }, + }, + }, + SecurityContext: v2.PodSecurityContextCustomSettings{ + RunAsUser: "RunAsUser", + FsGroup: "FsGroup", + }, + }, + DisableInternalRegistry: true, + ExternalDevfileRegistries: []v2.ExternalDevfileRegistry{ + { + Url: "ExternalDevfileRegistries", + }, + }, }, - }, - Spec: v2alpha1.CheClusterSpec{ - Enabled: pointer.BoolPtr(true), - Workspaces: v2alpha1.Workspaces{ - DomainEndpoints: v2alpha1.DomainEndpoints{ - BaseDomain: "baseDomain", - TlsSecretName: "workspaceSecret", + Dashboard: v2.CheClusterSpecDashboard{ + Deployment: v2.DeploymentCustomSettings{ + Container: v2.ContainerCustomSettings{ + Image: "DashboardImage", + ImagePullPolicy: corev1.PullAlways, + Resources: v2.ResourceRequirementsCustomSettings{ + Requests: v2.ResourceListCustomSettings{ + Memory: "DashboardMemoryRequest", + Cpu: "DashboardCpuRequest", + }, + Limits: v2.ResourceListCustomSettings{ + Memory: "DashboardMemoryLimit", + Cpu: "DashboardCpuLimit", + }, + }, + }, + SecurityContext: v2.PodSecurityContextCustomSettings{ + RunAsUser: "RunAsUser", + FsGroup: "FsGroup", + }, }, + Warning: "DashboardWarning", }, - Gateway: v2alpha1.CheGatewaySpec{ - Host: "v2Host", - Enabled: pointer.BoolPtr(true), - Image: "gateway-image", - ConfigurerImage: "configurer-image", - TlsSecretName: "superSecret", - ConfigLabels: labels.Set{ - "a": "b", + Storage: v2.CheClusterSpecStorage{ + Pvc: v2.PVC{ + ClaimSize: "StorageClaimSize", + StorageClass: "StorageClass", }, + PvcStrategy: "PvcStrategy", + PreCreateSubPaths: true, + PvcJobsImage: "PvcJobsImage", + }, + Metrics: v2.CheClusterSpecMetrics{ + Enable: true, + }, + ImagePuller: v2.CheClusterSpecImagePuller{ + Enable: true, }, - K8s: v2alpha1.CheClusterSpecK8s{ - IngressAnnotations: map[string]string{ - "kubernetes.io/ingress.class": "some-other-ingress", - "a": "b", + DevWorkspace: v2.CheClusterSpecDevWorkspace{ + Deployment: v2.DeploymentCustomSettings{ + Container: v2.ContainerCustomSettings{ + Image: "DevWorkspaceImage", + }, }, + RunningLimit: "RunningLimit", }, }, + Status: v2.CheClusterStatus{ + CheVersion: "CheVersion", + CheURL: "CheURL", + DevfileRegistryURL: "DevfileRegistryURL", + PluginRegistryURL: "PluginRegistryURL", + Phase: "Active", + Message: "Message", + Reason: "Reason", + HelpLink: "HelpLink", + }, } - v1Obj := v1.CheCluster{} - assert.NoError(t, V2alpha1ToV1(&v2Obj, &v1Obj)) - - convertedV2 := v2alpha1.CheCluster{} - assert.NoError(t, V1ToV2alpha1(&v1Obj, &convertedV2)) - - assert.Empty(t, convertedV2.Annotations[v2alpha1StorageAnnotation]) - assert.NotEmpty(t, convertedV2.Annotations[v1StorageAnnotation]) - - // remove v1 content annotation on the convertedV1 so that it doesn't interfere with the equality. - delete(convertedV2.Annotations, v1StorageAnnotation) - - assert.Equal(t, &v2Obj, &convertedV2) -} - -func onFakeOpenShift(f func()) { - origOpenshift := util.IsOpenShift - origOpenshift4 := util.IsOpenShift4 - - util.IsOpenShift = true - util.IsOpenShift4 = true - - f() - - util.IsOpenShift = origOpenshift - util.IsOpenShift4 = origOpenshift4 -} - -func onFakeKubernetes(f func()) { - origOpenshift := util.IsOpenShift - origOpenshift4 := util.IsOpenShift4 - - util.IsOpenShift = false - util.IsOpenShift4 = false - - f() - - util.IsOpenShift = origOpenshift - util.IsOpenShift4 = origOpenshift4 + checlusterv1 := &v1.CheCluster{} + err := checlusterv1.ConvertFrom(checlusterv2) + assert.Nil(t, err) + + assert.Equal(t, checlusterv1.ObjectMeta.Name, "eclipse-che") + assert.Equal(t, checlusterv1.ObjectMeta.Namespace, "eclipse-che") + + assert.Equal(t, checlusterv1.Status.CheClusterRunning, "Available") + assert.Equal(t, checlusterv1.Status.CheURL, "CheURL") + assert.Equal(t, checlusterv1.Status.CheVersion, "CheVersion") + assert.Equal(t, checlusterv1.Status.DevfileRegistryURL, "DevfileRegistryURL") + assert.Equal(t, checlusterv1.Status.HelpLink, "HelpLink") + assert.Equal(t, checlusterv1.Status.Message, "Message") + assert.Equal(t, checlusterv1.Status.PluginRegistryURL, "PluginRegistryURL") + assert.Equal(t, checlusterv1.Status.Reason, "Reason") + + assert.Equal(t, checlusterv1.Spec.Auth.GatewayAuthenticationSidecarImage, "AuthenticationSidecarImage") + assert.Equal(t, checlusterv1.Spec.Auth.GatewayAuthorizationSidecarImage, "AuthorizationSidecarImage") + assert.Equal(t, checlusterv1.Spec.Auth.IdentityProviderURL, "IdentityProviderURL") + assert.Equal(t, checlusterv1.Spec.Auth.OAuthClientName, "OAuthClientName") + assert.Equal(t, checlusterv1.Spec.Auth.OAuthSecret, "OAuthSecret") + + assert.Equal(t, checlusterv1.Spec.Database.ChePostgresContainerResources.Limits.Cpu, "DatabaseCpuLimit") + assert.Equal(t, checlusterv1.Spec.Database.ChePostgresContainerResources.Limits.Memory, "DatabaseMemoryLimit") + assert.Equal(t, checlusterv1.Spec.Database.ChePostgresContainerResources.Requests.Cpu, "DatabaseCpuRequest") + assert.Equal(t, checlusterv1.Spec.Database.ChePostgresContainerResources.Requests.Memory, "DatabaseMemoryRequest") + assert.Equal(t, checlusterv1.Spec.Database.ChePostgresDb, "PostgresDb") + assert.Equal(t, checlusterv1.Spec.Database.ChePostgresHostName, "PostgresHostName") + assert.Equal(t, checlusterv1.Spec.Database.ChePostgresPort, "PostgresPort") + assert.Equal(t, checlusterv1.Spec.Database.ChePostgresSecret, "DatabaseCredentialsSecretRef") + assert.Equal(t, checlusterv1.Spec.Database.ExternalDb, true) + assert.Equal(t, checlusterv1.Spec.Database.PostgresImage, "DatabaseImage") + assert.Equal(t, checlusterv1.Spec.Database.PostgresImagePullPolicy, corev1.PullAlways) + assert.Equal(t, checlusterv1.Spec.Database.PostgresVersion, "PostgresVersion") + assert.Equal(t, checlusterv1.Spec.Database.PvcClaimSize, "DatabaseClaimSize") + + assert.Equal(t, checlusterv1.Spec.DevWorkspace.ControllerImage, "DevWorkspaceImage") + assert.Equal(t, checlusterv1.Spec.DevWorkspace.RunningLimit, "RunningLimit") + + assert.Equal(t, checlusterv1.Spec.Dashboard.Warning, "DashboardWarning") + + assert.Equal(t, checlusterv1.Spec.ImagePuller.Enable, true) + assert.Equal(t, checlusterv1.Spec.Metrics.Enable, true) + + assert.Equal(t, checlusterv1.Spec.Server.AirGapContainerRegistryHostname, "AirGapContainerRegistryHostname") + assert.Equal(t, checlusterv1.Spec.Server.AirGapContainerRegistryOrganization, "AirGapContainerRegistryOrganization") + assert.Equal(t, checlusterv1.Spec.Server.CheClusterRoles, "ClusterRoles_1,ClusterRoles_2") + assert.Equal(t, checlusterv1.Spec.Server.CheDebug, "Debug") + assert.Equal(t, checlusterv1.Spec.Server.CheHost, "IngressHost") + assert.Equal(t, checlusterv1.Spec.Server.CheHostTLSSecret, "RouteTlsSecretRef") + assert.Equal(t, checlusterv1.Spec.Server.CheImage, "ServerImage") + assert.Equal(t, checlusterv1.Spec.Server.CheImagePullPolicy, corev1.PullPolicy("Always")) + assert.Equal(t, checlusterv1.Spec.Server.CheImageTag, "ServerTag") + assert.Equal(t, checlusterv1.Spec.Server.CheLogLevel, "LogLevel") + assert.Equal(t, checlusterv1.Spec.Server.CheServerIngress.Annotations, map[string]string{"a": "b", "c": "d", "kubernetes.io/ingress.class": "k8s.IngressClass"}) + assert.Equal(t, checlusterv1.Spec.Server.CheServerIngress.Labels, "a=b,c=d") + assert.Equal(t, checlusterv1.Spec.Server.CheServerRoute.Annotations, map[string]string{"a": "b", "c": "d"}) + assert.Equal(t, checlusterv1.Spec.Server.CheServerRoute.Domain, "RouteDomain") + assert.Equal(t, checlusterv1.Spec.Server.CheServerRoute.Labels, "a=b,c=d") + assert.Equal(t, checlusterv1.Spec.Server.CheWorkspaceClusterRole, "WorkspaceServiceAccountClusterRole") + assert.Equal(t, checlusterv1.Spec.Server.CustomCheProperties, map[string]string{"a": "b", "c": "d"}) + assert.Equal(t, checlusterv1.Spec.Server.DashboardCpuLimit, "DashboardCpuLimit") + assert.Equal(t, checlusterv1.Spec.Server.DashboardCpuRequest, "DashboardCpuRequest") + assert.Equal(t, checlusterv1.Spec.Server.DashboardImage, "DashboardImage") + assert.Equal(t, checlusterv1.Spec.Server.DashboardImagePullPolicy, "Always") + assert.Equal(t, checlusterv1.Spec.Server.DashboardMemoryLimit, "DashboardMemoryLimit") + assert.Equal(t, checlusterv1.Spec.Server.DashboardMemoryRequest, "DashboardMemoryRequest") + assert.Equal(t, checlusterv1.Spec.Server.DevfileRegistryCpuLimit, "DevfileRegistryCpuLimit") + assert.Equal(t, checlusterv1.Spec.Server.DevfileRegistryCpuRequest, "DevfileRegistryCpuRequest") + assert.Equal(t, checlusterv1.Spec.Server.DevfileRegistryImage, "DevfileRegistryImage") + assert.Equal(t, checlusterv1.Spec.Server.DevfileRegistryMemoryLimit, "DevfileRegistryMemoryLimit") + assert.Equal(t, checlusterv1.Spec.Server.DevfileRegistryMemoryRequest, "DevfileRegistryMemoryRequest") + assert.Equal(t, checlusterv1.Spec.Server.DevfileRegistryPullPolicy, corev1.PullPolicy("Always")) + assert.Equal(t, checlusterv1.Spec.Server.ExternalDevfileRegistries, []v1.ExternalDevfileRegistries{{Url: "ExternalDevfileRegistries"}}) + assert.Equal(t, checlusterv1.Spec.Server.ExternalDevfileRegistry, true) + assert.Equal(t, checlusterv1.Spec.Server.ExternalPluginRegistry, true) + assert.Equal(t, checlusterv1.Spec.Server.GitSelfSignedCert, true) + assert.Equal(t, checlusterv1.Spec.Server.NonProxyHosts, "NonProxyHosts_1|NonProxyHosts_2") + assert.Equal(t, checlusterv1.Spec.Server.PluginRegistryCpuLimit, "PluginRegistryCpuLimit") + assert.Equal(t, checlusterv1.Spec.Server.PluginRegistryCpuRequest, "PluginRegistryCpuRequest") + assert.Equal(t, checlusterv1.Spec.Server.PluginRegistryImage, "PluginRegistryImage") + assert.Equal(t, checlusterv1.Spec.Server.PluginRegistryMemoryLimit, "PluginRegistryMemoryLimit") + assert.Equal(t, checlusterv1.Spec.Server.PluginRegistryMemoryRequest, "PluginRegistryMemoryRequest") + assert.Equal(t, checlusterv1.Spec.Server.PluginRegistryPullPolicy, corev1.PullPolicy("Always")) + assert.Equal(t, checlusterv1.Spec.Server.PluginRegistryUrl, "ExternalPluginRegistries_1") + assert.Equal(t, checlusterv1.Spec.Server.ProxyPort, "ProxyPort") + assert.Equal(t, checlusterv1.Spec.Server.ProxySecret, "ProxyCredentialsSecretRef") + assert.Equal(t, checlusterv1.Spec.Server.ProxyURL, "ProxyUrl") + assert.Equal(t, checlusterv1.Spec.Server.ServerCpuLimit, "ServerCpuLimit") + assert.Equal(t, checlusterv1.Spec.Server.ServerCpuRequest, "ServerCpuRequest") + assert.Equal(t, checlusterv1.Spec.Server.ServerMemoryLimit, "ServerMemoryLimit") + assert.Equal(t, checlusterv1.Spec.Server.ServerMemoryRequest, "ServerMemoryRequest") + assert.Equal(t, checlusterv1.Spec.Server.ServerTrustStoreConfigMapName, "ServerTrustStoreConfigMapName") + assert.Equal(t, checlusterv1.Spec.Server.SingleHostGatewayConfigMapLabels, labels.Set{"a": "b", "c": "d"}) + assert.Equal(t, checlusterv1.Spec.Server.SingleHostGatewayConfigSidecarImage, "ConfigSidecarImage") + assert.Equal(t, checlusterv1.Spec.Server.SingleHostGatewayImage, "GatewayImage") + assert.Equal(t, checlusterv1.Spec.Server.WorkspaceNamespaceDefault, "WorkspaceNamespaceName") + assert.Equal(t, checlusterv1.Spec.Server.WorkspacePodNodeSelector, map[string]string{"a": "b", "c": "d"}) + assert.Equal(t, checlusterv1.Spec.Server.WorkspacePodTolerations, []corev1.Toleration{ + { + Key: "Key", + Operator: "Operator", + Value: "Value", + Effect: "Effect", + }, + }) + assert.Equal(t, checlusterv1.Spec.Server.WorkspacesDefaultPlugins, []v1.WorkspacesDefaultPlugins{{Editor: "Editor", Plugins: []string{"Plugins_1", "Plugins_2"}}}) + + assert.Equal(t, checlusterv1.Spec.Storage.PostgresPVCStorageClassName, "DatabaseStorageClass") + assert.Equal(t, checlusterv1.Spec.Storage.PreCreateSubPaths, true) + assert.Equal(t, checlusterv1.Spec.Storage.PvcClaimSize, "StorageClaimSize") + assert.Equal(t, checlusterv1.Spec.Storage.PvcJobsImage, "PvcJobsImage") + assert.Equal(t, checlusterv1.Spec.Storage.PvcStrategy, "PvcStrategy") + assert.Equal(t, checlusterv1.Spec.Storage.WorkspacePVCStorageClassName, "StorageClass") } diff --git a/api/v1/checluster_types.go b/api/v1/checluster_types.go index 5e920c0c68..224b4107ac 100644 --- a/api/v1/checluster_types.go +++ b/api/v1/checluster_types.go @@ -803,7 +803,6 @@ type CheClusterStatus struct { // +operator-sdk:csv:customresourcedefinitions:displayName="Eclipse Che instance Specification" // +operator-sdk:csv:customresourcedefinitions:order=0 // +operator-sdk:csv:customresourcedefinitions:resources={{Ingress,v1},{Route,v1},{ConfigMap,v1},{Service,v1},{Secret,v1},{Deployment,apps/v1},{Role,v1},{RoleBinding,v1},{ClusterRole,v1},{ClusterRoleBinding,v1}} -// +kubebuilder:storageversion type CheCluster struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/api/v1/conversion.go b/api/v1/conversion.go new file mode 100644 index 0000000000..1a327b2cae --- /dev/null +++ b/api/v1/conversion.go @@ -0,0 +1,528 @@ +// +// Copyright (c) 2019-2022 Red Hat, Inc. +// This program and the accompanying materials are made +// available under the terms of the Eclipse Public License 2.0 +// which is available at https://www.eclipse.org/legal/epl-2.0/ +// +// SPDX-License-Identifier: EPL-2.0 +// +// Contributors: +// Red Hat, Inc. - initial API and implementation +// + +package v1 + +import ( + "context" + "sort" + "strings" + + chev2 "github.com/eclipse-che/che-operator/api/v2" + "github.com/eclipse-che/che-operator/pkg/infrastructure" + "github.com/eclipse-che/che-operator/pkg/k8sclient" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/conversion" +) + +const ( + defaultV1IngressClass = "nginx" + defaultProxyCredentialsSecret = "proxy-credentials" + defaultPostgresCredentialsSecret = "postgres-credentials" +) + +var ( + defaultIngressAnnotations = map[string]string{ + "kubernetes.io/ingress.class": "nginx", + "nginx.ingress.kubernetes.io/proxy-read-timeout": "3600", + "nginx.ingress.kubernetes.io/proxy-connect-timeout": "3600", + "nginx.ingress.kubernetes.io/ssl-redirect": "true", + } +) + +func (src *CheCluster) ConvertTo(dstRaw conversion.Hub) error { + dst := dstRaw.(*chev2.CheCluster) + dst.ObjectMeta = src.ObjectMeta + + // Server + dst.Spec.Server.AirGapContainerRegistryHostname = src.Spec.Server.AirGapContainerRegistryHostname + dst.Spec.Server.AirGapContainerRegistryOrganization = src.Spec.Server.AirGapContainerRegistryOrganization + dst.Spec.Server.ClusterRoles = strings.Split(src.Spec.Server.CheClusterRoles, ",") + dst.Spec.Server.CustomCheProperties = src.Spec.Server.CustomCheProperties + dst.Spec.Server.Debug = src.Spec.Server.CheDebug + dst.Spec.Server.ServerTrustStoreConfigMapName = src.Spec.Server.ServerTrustStoreConfigMapName + dst.Spec.Server.GitSelfSignedCert = src.Spec.Server.GitSelfSignedCert + dst.Spec.Server.LogLevel = src.Spec.Server.CheLogLevel + dst.Spec.Server.Proxy = chev2.Proxy{ + Url: src.Spec.Server.ProxyURL, + Port: src.Spec.Server.ProxyPort, + NonProxyHosts: strings.Split(src.Spec.Server.NonProxyHosts, "|"), + CredentialsSecretRef: src.Spec.Server.ProxySecret, + } + if src.Spec.Server.ProxySecret == "" && src.Spec.Server.ProxyUser != "" && src.Spec.Server.ProxyPassword != "" { + err := toSecret(src.Spec.Server.ProxyUser, src.Spec.Server.ProxyPassword, defaultProxyCredentialsSecret, src.ObjectMeta.Namespace) + if err != nil { + return err + } + dst.Spec.Server.Proxy.CredentialsSecretRef = defaultProxyCredentialsSecret + } + dst.Spec.Server.WorkspaceNamespaceName = src.Spec.Server.WorkspaceNamespaceDefault + dst.Spec.Server.WorkspacePodNodeSelector = src.Spec.Server.WorkspacePodNodeSelector + dst.Spec.Server.WorkspacePodTolerations = src.Spec.Server.WorkspacePodTolerations + dst.Spec.Server.WorkspaceServiceAccountClusterRole = strings.Split(src.Spec.Server.CheWorkspaceClusterRole, ",") + dst.Spec.Server.WorkspacesDefaultPlugins = make([]chev2.WorkspacesDefaultPlugins, 0) + for _, p := range src.Spec.Server.WorkspacesDefaultPlugins { + dst.Spec.Server.WorkspacesDefaultPlugins = append(dst.Spec.Server.WorkspacesDefaultPlugins, + chev2.WorkspacesDefaultPlugins{ + Editor: p.Editor, + Plugins: p.Plugins, + }) + } + dst.Spec.Server.Deployment = chev2.DeploymentCustomSettings{ + Container: chev2.ContainerCustomSettings{ + Image: src.Spec.Server.CheImage + ":" + src.Spec.Server.CheImageTag, + ImagePullPolicy: src.Spec.Server.CheImagePullPolicy, + Resources: chev2.ResourceRequirementsCustomSettings{ + Requests: chev2.ResourceListCustomSettings{ + Memory: src.Spec.Server.ServerMemoryRequest, + Cpu: src.Spec.Server.ServerCpuRequest, + }, + Limits: chev2.ResourceListCustomSettings{ + Memory: src.Spec.Server.ServerMemoryLimit, + Cpu: src.Spec.Server.ServerCpuLimit, + }, + }, + }, + SecurityContext: chev2.PodSecurityContextCustomSettings{ + RunAsUser: src.Spec.K8s.SecurityContextRunAsUser, + FsGroup: src.Spec.K8s.SecurityContextFsGroup, + }, + } + + // Dashboard + dst.Spec.Dashboard.Deployment = chev2.DeploymentCustomSettings{ + Container: chev2.ContainerCustomSettings{ + Image: src.Spec.Server.DashboardImage, + ImagePullPolicy: corev1.PullPolicy(src.Spec.Server.DashboardImagePullPolicy), + Resources: chev2.ResourceRequirementsCustomSettings{ + Requests: chev2.ResourceListCustomSettings{ + Memory: src.Spec.Server.DashboardMemoryRequest, + Cpu: src.Spec.Server.DashboardCpuRequest, + }, + Limits: chev2.ResourceListCustomSettings{ + Memory: src.Spec.Server.DashboardMemoryLimit, + Cpu: src.Spec.Server.DashboardCpuLimit, + }, + }, + }, + SecurityContext: chev2.PodSecurityContextCustomSettings{ + RunAsUser: src.Spec.K8s.SecurityContextRunAsUser, + FsGroup: src.Spec.K8s.SecurityContextFsGroup, + }, + } + dst.Spec.Dashboard.Warning = src.Spec.Dashboard.Warning + + // Devfile registry + dst.Spec.DevfileRegistry.DisableInternalRegistry = src.Spec.Server.ExternalDevfileRegistry + dst.Spec.DevfileRegistry.ExternalDevfileRegistries = make([]chev2.ExternalDevfileRegistry, 0) + for _, r := range src.Spec.Server.ExternalDevfileRegistries { + dst.Spec.DevfileRegistry.ExternalDevfileRegistries = append(dst.Spec.DevfileRegistry.ExternalDevfileRegistries, + chev2.ExternalDevfileRegistry{ + Url: r.Url, + }) + } + dst.Spec.DevfileRegistry.Deployment = chev2.DeploymentCustomSettings{ + Container: chev2.ContainerCustomSettings{ + Image: src.Spec.Server.DevfileRegistryImage, + ImagePullPolicy: corev1.PullPolicy(src.Spec.Server.DevfileRegistryPullPolicy), + Resources: chev2.ResourceRequirementsCustomSettings{ + Requests: chev2.ResourceListCustomSettings{ + Memory: src.Spec.Server.DevfileRegistryMemoryRequest, + Cpu: src.Spec.Server.DevfileRegistryCpuRequest, + }, + Limits: chev2.ResourceListCustomSettings{ + Memory: src.Spec.Server.DevfileRegistryMemoryLimit, + Cpu: src.Spec.Server.DevfileRegistryCpuLimit, + }, + }, + }, + SecurityContext: chev2.PodSecurityContextCustomSettings{ + RunAsUser: src.Spec.K8s.SecurityContextRunAsUser, + FsGroup: src.Spec.K8s.SecurityContextFsGroup, + }, + } + + // Plugin registry + dst.Spec.PluginRegistry.DisableInternalRegistry = src.Spec.Server.ExternalPluginRegistry + if dst.Spec.PluginRegistry.DisableInternalRegistry { + dst.Spec.PluginRegistry.ExternalPluginRegistries = []chev2.ExternalPluginRegistry{ + { + Url: src.Spec.Server.PluginRegistryUrl, + }, + } + } + dst.Spec.PluginRegistry.Deployment = chev2.DeploymentCustomSettings{ + Container: chev2.ContainerCustomSettings{ + Image: src.Spec.Server.PluginRegistryImage, + ImagePullPolicy: corev1.PullPolicy(src.Spec.Server.PluginRegistryPullPolicy), + Resources: chev2.ResourceRequirementsCustomSettings{ + Requests: chev2.ResourceListCustomSettings{ + Memory: src.Spec.Server.PluginRegistryMemoryRequest, + Cpu: src.Spec.Server.PluginRegistryCpuRequest, + }, + Limits: chev2.ResourceListCustomSettings{ + Memory: src.Spec.Server.PluginRegistryMemoryLimit, + Cpu: src.Spec.Server.PluginRegistryCpuLimit, + }, + }, + }, + SecurityContext: chev2.PodSecurityContextCustomSettings{ + RunAsUser: src.Spec.K8s.SecurityContextRunAsUser, + FsGroup: src.Spec.K8s.SecurityContextFsGroup, + }, + } + + // Auth + dst.Spec.Auth.Gateway.ConfigLabels = src.Spec.Server.SingleHostGatewayConfigMapLabels + dst.Spec.Auth.IdentityProviderURL = src.Spec.Auth.IdentityProviderURL + dst.Spec.Auth.OAuthClientName = src.Spec.Auth.OAuthClientName + dst.Spec.Auth.OAuthSecret = src.Spec.Auth.OAuthSecret + dst.Spec.Auth.Gateway.AuthenticationSidecarImage = src.Spec.Auth.GatewayAuthenticationSidecarImage + dst.Spec.Auth.Gateway.AuthorizationSidecarImage = src.Spec.Auth.GatewayAuthorizationSidecarImage + dst.Spec.Auth.Gateway.Image = src.Spec.Server.SingleHostGatewayImage + dst.Spec.Auth.Gateway.ConfigSidecarImage = src.Spec.Server.SingleHostGatewayConfigSidecarImage + dst.Spec.Auth.Gateway.ConfigLabels = src.Spec.Server.SingleHostGatewayConfigMapLabels + dst.Spec.Auth.Gateway.Ingress = chev2.IngressCustomSettings{ + Labels: asMap(src.Spec.Server.CheServerIngress.Labels), + Domain: src.Spec.K8s.IngressDomain, + Host: src.Spec.Server.CheHost, + TlsSecretRef: src.Spec.K8s.TlsSecretName, + } + dst.Spec.Auth.Gateway.Ingress.Annotations = make(map[string]string) + for k, v := range defaultIngressAnnotations { + dst.Spec.Auth.Gateway.Ingress.Annotations[k] = v + } + if src.Spec.K8s.IngressClass != "" { + dst.Spec.Auth.Gateway.Ingress.Annotations["kubernetes.io/ingress.class"] = src.Spec.K8s.IngressClass + } + for k, v := range src.Spec.Server.CheServerIngress.Annotations { + dst.Spec.Auth.Gateway.Ingress.Annotations[k] = v + } + dst.Spec.Auth.Gateway.Route = chev2.RouteCustomSettings{ + Labels: asMap(src.Spec.Server.CheServerRoute.Labels), + Annotations: src.Spec.Server.CheServerRoute.Annotations, + Host: src.Spec.Server.CheHost, + Domain: src.Spec.Server.CheServerRoute.Domain, + TlsSecretRef: src.Spec.Server.CheHostTLSSecret, + } + + // Database + dst.Spec.Database.CredentialsSecretRef = src.Spec.Database.ChePostgresSecret + if src.Spec.Database.ChePostgresSecret == "" && src.Spec.Database.ChePostgresUser != "" && src.Spec.Database.ChePostgresPassword != "" { + err := toSecret(src.Spec.Database.ChePostgresUser, src.Spec.Database.ChePostgresPassword, defaultPostgresCredentialsSecret, src.ObjectMeta.Namespace) + if err != nil { + return err + } + dst.Spec.Database.CredentialsSecretRef = defaultPostgresCredentialsSecret + } + dst.Spec.Database.Deployment = chev2.DeploymentCustomSettings{ + Container: chev2.ContainerCustomSettings{ + Image: src.Spec.Database.PostgresImage, + ImagePullPolicy: corev1.PullPolicy(src.Spec.Database.PostgresImagePullPolicy), + Resources: chev2.ResourceRequirementsCustomSettings{ + Requests: chev2.ResourceListCustomSettings{ + Memory: src.Spec.Database.ChePostgresContainerResources.Requests.Memory, + Cpu: src.Spec.Database.ChePostgresContainerResources.Requests.Cpu, + }, + Limits: chev2.ResourceListCustomSettings{ + Memory: src.Spec.Database.ChePostgresContainerResources.Limits.Memory, + Cpu: src.Spec.Database.ChePostgresContainerResources.Limits.Cpu, + }, + }, + }, + SecurityContext: chev2.PodSecurityContextCustomSettings{ + RunAsUser: src.Spec.K8s.SecurityContextRunAsUser, + FsGroup: src.Spec.K8s.SecurityContextFsGroup, + }, + } + dst.Spec.Database.ExternalDb = src.Spec.Database.ExternalDb + dst.Spec.Database.PostgresDb = src.Spec.Database.ChePostgresDb + dst.Spec.Database.PostgresHostName = src.Spec.Database.ChePostgresHostName + dst.Spec.Database.PostgresPort = src.Spec.Database.ChePostgresPort + dst.Spec.Database.PostgresVersion = src.Spec.Database.PostgresVersion + dst.Spec.Database.Pvc = chev2.PVC{ + ClaimSize: src.Spec.Database.PvcClaimSize, + StorageClass: src.Spec.Storage.PostgresPVCStorageClassName, + } + + // DevWorkspace + dst.Spec.DevWorkspace.Deployment = chev2.DeploymentCustomSettings{ + Container: chev2.ContainerCustomSettings{ + Image: src.Spec.DevWorkspace.ControllerImage, + }, + } + dst.Spec.DevWorkspace.RunningLimit = src.Spec.DevWorkspace.RunningLimit + + // ImagePuller + dst.Spec.ImagePuller.Enable = src.Spec.ImagePuller.Enable + dst.Spec.ImagePuller.Spec = src.Spec.ImagePuller.Spec + + // Metrics + dst.Spec.Metrics.Enable = src.Spec.Metrics.Enable + + // Storage + dst.Spec.Storage.PreCreateSubPaths = src.Spec.Storage.PreCreateSubPaths + dst.Spec.Storage.Pvc = chev2.PVC{ + ClaimSize: src.Spec.Storage.PvcClaimSize, + StorageClass: src.Spec.Storage.WorkspacePVCStorageClassName, + } + dst.Spec.Storage.PvcJobsImage = src.Spec.Storage.PvcJobsImage + dst.Spec.Storage.PvcStrategy = src.Spec.Storage.PvcStrategy + + // Status + dst.Status.CheURL = src.Status.CheURL + dst.Status.CheVersion = src.Status.CheVersion + dst.Status.DevfileRegistryURL = src.Status.DevfileRegistryURL + dst.Status.PluginRegistryURL = src.Status.PluginRegistryURL + dst.Status.HelpLink = src.Status.HelpLink + dst.Status.Message = src.Status.Message + dst.Status.Reason = src.Status.Reason + switch src.Status.CheClusterRunning { + case "Available": + dst.Status.Phase = chev2.ClusterPhaseActive + case "Unavailable": + dst.Status.Phase = chev2.ClusterPhaseInactive + case "Available, Rolling Update in Progress": + dst.Status.Phase = chev2.RollingUpdate + } + + return nil +} + +func (dst *CheCluster) ConvertFrom(srcRaw conversion.Hub) error { + src := srcRaw.(*chev2.CheCluster) + dst.ObjectMeta = src.ObjectMeta + + // Server + dst.Spec.Server.AirGapContainerRegistryHostname = src.Spec.Server.AirGapContainerRegistryHostname + dst.Spec.Server.AirGapContainerRegistryOrganization = src.Spec.Server.AirGapContainerRegistryOrganization + dst.Spec.Server.CheClusterRoles = strings.Join(src.Spec.Server.ClusterRoles, ",") + dst.Spec.Server.CustomCheProperties = src.Spec.Server.CustomCheProperties + dst.Spec.Server.CheDebug = src.Spec.Server.Debug + dst.Spec.Server.ServerTrustStoreConfigMapName = src.Spec.Server.ServerTrustStoreConfigMapName + dst.Spec.Server.GitSelfSignedCert = src.Spec.Server.GitSelfSignedCert + dst.Spec.Server.CheLogLevel = src.Spec.Server.LogLevel + dst.Spec.Server.ProxyURL = src.Spec.Server.Proxy.Url + dst.Spec.Server.ProxyPort = src.Spec.Server.Proxy.Port + dst.Spec.Server.NonProxyHosts = strings.Join(src.Spec.Server.Proxy.NonProxyHosts, "|") + dst.Spec.Server.ProxySecret = src.Spec.Server.Proxy.CredentialsSecretRef + dst.Spec.Server.WorkspaceNamespaceDefault = src.Spec.Server.WorkspaceNamespaceName + dst.Spec.Server.WorkspacePodNodeSelector = src.Spec.Server.WorkspacePodNodeSelector + dst.Spec.Server.WorkspacePodTolerations = src.Spec.Server.WorkspacePodTolerations + dst.Spec.Server.CheWorkspaceClusterRole = strings.Join(src.Spec.Server.WorkspaceServiceAccountClusterRole, ",") + dst.Spec.Server.WorkspacesDefaultPlugins = make([]WorkspacesDefaultPlugins, 0) + for _, p := range src.Spec.Server.WorkspacesDefaultPlugins { + dst.Spec.Server.WorkspacesDefaultPlugins = append(dst.Spec.Server.WorkspacesDefaultPlugins, + WorkspacesDefaultPlugins{ + Editor: p.Editor, + Plugins: p.Plugins, + }) + } + cheServerImageAndTag := strings.Split(src.Spec.Server.Deployment.Container.Image, ":") + dst.Spec.Server.CheImage = strings.Join(cheServerImageAndTag[0:len(cheServerImageAndTag)-1], ":") + dst.Spec.Server.CheImageTag = cheServerImageAndTag[len(cheServerImageAndTag)-1] + dst.Spec.Server.CheImagePullPolicy = src.Spec.Server.Deployment.Container.ImagePullPolicy + dst.Spec.Server.ServerMemoryRequest = src.Spec.Server.Deployment.Container.Resources.Requests.Memory + dst.Spec.Server.ServerCpuRequest = src.Spec.Server.Deployment.Container.Resources.Requests.Cpu + dst.Spec.Server.ServerMemoryLimit = src.Spec.Server.Deployment.Container.Resources.Limits.Memory + dst.Spec.Server.ServerCpuLimit = src.Spec.Server.Deployment.Container.Resources.Limits.Cpu + dst.Spec.Server.DashboardImage = src.Spec.Dashboard.Deployment.Container.Image + dst.Spec.Server.DashboardImagePullPolicy = string(src.Spec.Dashboard.Deployment.Container.ImagePullPolicy) + dst.Spec.Server.DashboardMemoryRequest = src.Spec.Dashboard.Deployment.Container.Resources.Requests.Memory + dst.Spec.Server.DashboardCpuRequest = src.Spec.Dashboard.Deployment.Container.Resources.Requests.Cpu + dst.Spec.Server.DashboardMemoryLimit = src.Spec.Dashboard.Deployment.Container.Resources.Limits.Memory + dst.Spec.Server.DashboardCpuLimit = src.Spec.Dashboard.Deployment.Container.Resources.Limits.Cpu + dst.Spec.Server.PluginRegistryImage = src.Spec.PluginRegistry.Deployment.Container.Image + dst.Spec.Server.PluginRegistryPullPolicy = src.Spec.PluginRegistry.Deployment.Container.ImagePullPolicy + dst.Spec.Server.PluginRegistryMemoryRequest = src.Spec.PluginRegistry.Deployment.Container.Resources.Requests.Memory + dst.Spec.Server.PluginRegistryCpuRequest = src.Spec.PluginRegistry.Deployment.Container.Resources.Requests.Cpu + dst.Spec.Server.PluginRegistryMemoryLimit = src.Spec.PluginRegistry.Deployment.Container.Resources.Limits.Memory + dst.Spec.Server.PluginRegistryCpuLimit = src.Spec.PluginRegistry.Deployment.Container.Resources.Limits.Cpu + dst.Spec.Server.DevfileRegistryImage = src.Spec.DevfileRegistry.Deployment.Container.Image + dst.Spec.Server.DevfileRegistryPullPolicy = src.Spec.DevfileRegistry.Deployment.Container.ImagePullPolicy + dst.Spec.Server.DevfileRegistryMemoryRequest = src.Spec.DevfileRegistry.Deployment.Container.Resources.Requests.Memory + dst.Spec.Server.DevfileRegistryCpuRequest = src.Spec.DevfileRegistry.Deployment.Container.Resources.Requests.Cpu + dst.Spec.Server.DevfileRegistryMemoryLimit = src.Spec.DevfileRegistry.Deployment.Container.Resources.Limits.Memory + dst.Spec.Server.DevfileRegistryCpuLimit = src.Spec.DevfileRegistry.Deployment.Container.Resources.Limits.Cpu + dst.Spec.Server.ExternalDevfileRegistry = src.Spec.DevfileRegistry.DisableInternalRegistry + dst.Spec.Server.ExternalPluginRegistry = src.Spec.PluginRegistry.DisableInternalRegistry + dst.Spec.Server.ExternalDevfileRegistries = make([]ExternalDevfileRegistries, 0) + for _, r := range src.Spec.DevfileRegistry.ExternalDevfileRegistries { + dst.Spec.Server.ExternalDevfileRegistries = append(dst.Spec.Server.ExternalDevfileRegistries, + ExternalDevfileRegistries{ + Url: r.Url, + }) + } + + // Plugin registry + if src.Spec.PluginRegistry.DisableInternalRegistry { + if len(src.Spec.PluginRegistry.ExternalPluginRegistries) != 0 { + dst.Spec.Server.PluginRegistryUrl = src.Spec.PluginRegistry.ExternalPluginRegistries[0].Url + } + } + dst.Spec.Server.SingleHostGatewayConfigMapLabels = src.Spec.Auth.Gateway.ConfigLabels + dst.Spec.Auth.GatewayAuthenticationSidecarImage = src.Spec.Auth.Gateway.AuthenticationSidecarImage + dst.Spec.Auth.GatewayAuthorizationSidecarImage = src.Spec.Auth.Gateway.AuthorizationSidecarImage + dst.Spec.Server.SingleHostGatewayImage = src.Spec.Auth.Gateway.Image + dst.Spec.Server.SingleHostGatewayConfigSidecarImage = src.Spec.Auth.Gateway.ConfigSidecarImage + dst.Spec.Server.SingleHostGatewayConfigMapLabels = src.Spec.Auth.Gateway.ConfigLabels + if infrastructure.IsOpenShift { + dst.Spec.Server.CheHost = src.Spec.Auth.Gateway.Route.Host + } else { + dst.Spec.Server.CheHost = src.Spec.Auth.Gateway.Ingress.Host + } + dst.Spec.Server.CheServerIngress.Labels = asString(src.Spec.Auth.Gateway.Ingress.Labels) + dst.Spec.Server.CheServerIngress.Annotations = src.Spec.Auth.Gateway.Ingress.Annotations + if len(dst.Spec.Server.CheServerIngress.Annotations) != 0 { + for k, v := range defaultIngressAnnotations { + if dst.Spec.Server.CheServerIngress.Annotations[k] == v { + delete(dst.Spec.Server.CheServerIngress.Annotations, k) + } + } + } + dst.Spec.Server.CheServerRoute.Labels = asString(src.Spec.Auth.Gateway.Route.Labels) + dst.Spec.Server.CheServerRoute.Annotations = src.Spec.Auth.Gateway.Route.Annotations + dst.Spec.Server.CheServerRoute.Domain = src.Spec.Auth.Gateway.Route.Domain + dst.Spec.Server.CheHostTLSSecret = src.Spec.Auth.Gateway.Route.TlsSecretRef + + // K8S + dst.Spec.K8s.SecurityContextRunAsUser = src.Spec.Server.Deployment.SecurityContext.RunAsUser + dst.Spec.K8s.SecurityContextFsGroup = src.Spec.Server.Deployment.SecurityContext.FsGroup + dst.Spec.K8s.IngressDomain = src.Spec.Auth.Gateway.Ingress.Domain + dst.Spec.K8s.TlsSecretName = src.Spec.Auth.Gateway.Ingress.TlsSecretRef + dst.Spec.K8s.IngressClass = src.Spec.Auth.Gateway.Ingress.Annotations["kubernetes.io/ingress.class"] + if dst.Spec.K8s.IngressClass == "" { + dst.Spec.K8s.IngressClass = defaultV1IngressClass + } + + // Auth + dst.Spec.Auth.IdentityProviderURL = src.Spec.Auth.IdentityProviderURL + dst.Spec.Auth.OAuthClientName = src.Spec.Auth.OAuthClientName + dst.Spec.Auth.OAuthSecret = src.Spec.Auth.OAuthSecret + + // Database + dst.Spec.Database.PostgresImage = src.Spec.Database.Deployment.Container.Image + dst.Spec.Database.PostgresImagePullPolicy = src.Spec.Database.Deployment.Container.ImagePullPolicy + dst.Spec.Database.ExternalDb = src.Spec.Database.ExternalDb + dst.Spec.Database.ChePostgresDb = src.Spec.Database.PostgresDb + dst.Spec.Database.ChePostgresHostName = src.Spec.Database.PostgresHostName + dst.Spec.Database.ChePostgresPort = src.Spec.Database.PostgresPort + dst.Spec.Database.PostgresVersion = src.Spec.Database.PostgresVersion + dst.Spec.Database.PvcClaimSize = src.Spec.Database.Pvc.ClaimSize + dst.Spec.Database.ChePostgresSecret = src.Spec.Database.CredentialsSecretRef + dst.Spec.Database.ChePostgresContainerResources.Requests.Memory = src.Spec.Database.Deployment.Container.Resources.Requests.Memory + dst.Spec.Database.ChePostgresContainerResources.Requests.Cpu = src.Spec.Database.Deployment.Container.Resources.Requests.Cpu + dst.Spec.Database.ChePostgresContainerResources.Limits.Memory = src.Spec.Database.Deployment.Container.Resources.Limits.Memory + dst.Spec.Database.ChePostgresContainerResources.Limits.Cpu = src.Spec.Database.Deployment.Container.Resources.Limits.Cpu + + // DevWorkspace + dst.Spec.DevWorkspace.ControllerImage = src.Spec.DevWorkspace.Deployment.Container.Image + dst.Spec.DevWorkspace.RunningLimit = src.Spec.DevWorkspace.RunningLimit + + // ImagePuller + dst.Spec.ImagePuller.Enable = src.Spec.ImagePuller.Enable + dst.Spec.ImagePuller.Spec = src.Spec.ImagePuller.Spec + + // Metrics + dst.Spec.Metrics.Enable = src.Spec.Metrics.Enable + + // Dashboard + dst.Spec.Dashboard.Warning = src.Spec.Dashboard.Warning + + // Storage + dst.Spec.Storage.PostgresPVCStorageClassName = src.Spec.Database.Pvc.StorageClass + dst.Spec.Storage.PreCreateSubPaths = src.Spec.Storage.PreCreateSubPaths + dst.Spec.Storage.PvcClaimSize = src.Spec.Storage.Pvc.ClaimSize + dst.Spec.Storage.WorkspacePVCStorageClassName = src.Spec.Storage.Pvc.StorageClass + dst.Spec.Storage.PvcJobsImage = src.Spec.Storage.PvcJobsImage + dst.Spec.Storage.PvcStrategy = src.Spec.Storage.PvcStrategy + + // Status + dst.Status.CheURL = src.Status.CheURL + dst.Status.CheVersion = src.Status.CheVersion + dst.Status.DevfileRegistryURL = src.Status.DevfileRegistryURL + dst.Status.PluginRegistryURL = src.Status.PluginRegistryURL + dst.Status.HelpLink = src.Status.HelpLink + dst.Status.Message = src.Status.Message + dst.Status.Reason = src.Status.Reason + switch src.Status.Phase { + case chev2.ClusterPhaseActive: + dst.Status.CheClusterRunning = "Available" + case chev2.ClusterPhaseInactive: + dst.Status.CheClusterRunning = chev2.ClusterPhaseInactive + case chev2.RollingUpdate: + dst.Status.CheClusterRunning = "Available, Rolling Update in Progress" + } + + return nil +} + +func asMap(src string) map[string]string { + m := map[string]string{} + for _, item := range strings.Split(src, ",") { + keyValuePair := strings.Split(item, "=") + if len(keyValuePair) == 1 { + continue + } + + key := strings.TrimSpace(keyValuePair[0]) + value := strings.TrimSpace(keyValuePair[1]) + if key != "" && value != "" { + m[keyValuePair[0]] = keyValuePair[1] + } + } + + return m +} + +func asString(m map[string]string) string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + + str := "" + for _, k := range keys { + if len(str) != 0 { + str += "," + } + str += k + "=" + m[k] + } + return str +} + +func toSecret(user string, password string, secretName string, secretNamespace string) error { + secret := &corev1.Secret{ + ObjectMeta: v1.ObjectMeta{ + Name: secretName, + Namespace: secretNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "che.eclipse.org", + }, + }, + Data: map[string][]byte{ + "user": []byte(user), + "password": []byte(password), + }, + } + + clientSet, err := k8sclient.GetK8ClientSet() + if err != nil { + return err + } + + _, err = clientSet.CoreV1().Secrets(secretNamespace).Create(context.TODO(), secret, metav1.CreateOptions{}) + return err +} diff --git a/api/v2/checluster_types.go b/api/v2/checluster_types.go new file mode 100644 index 0000000000..05e4b742da --- /dev/null +++ b/api/v2/checluster_types.go @@ -0,0 +1,604 @@ +// +// Copyright (c) 2019-2021 Red Hat, Inc. +// This program and the accompanying materials are made +// available under the terms of the Eclipse Public License 2.0 +// which is available at https://www.eclipse.org/legal/epl-2.0/ +// +// SPDX-License-Identifier: EPL-2.0 +// +// Contributors: +// Red Hat, Inc. - initial API and implementation +// + +package v2 + +// Important: You must regenerate some generated code after modifying this file. At the root of the project: +// Run `make generate`. It will perform required changes: +// - update `api/v1/zz_generatedxxx` files; +// - update `config/crd/bases/org_v1_checluster_crd.yaml` and `config/crd/bases/org_v1_che_crd-v1beta1.yaml` files; +// - In the updated `config/crd/bases/org_v1_checluster_crd.yaml`: Delete all the `required:` openAPI rules in the CRD OpenApi schema; +// - Rename the new `config/crd/bases/org_v1_checluster_crd.yaml` to `config/crd/bases/org_v1_che_crd.yaml` to override it. +// IMPORTANT These 2 last steps are important to ensure backward compatibility with already existing `CheCluster` CRs that were created when no schema was provided. + +import ( + chev1alpha1 "github.com/che-incubator/kubernetes-image-puller-operator/api/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +k8s:openapi-gen=true +// Desired configuration of the Che installation. +// Based on these settings, the Operator automatically creates and maintains +// several ConfigMaps that will contain the appropriate environment variables +// the various components of the Che installation. +// These generated ConfigMaps must NOT be updated manually. +type CheClusterSpec struct { + // General configuration settings related to the Che server, the plugin and devfile registries + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Che server" + Server CheClusterSpecServer `json:"server"` + // Configuration settings related to the database used by the Che installation. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Database" + Database CheClusterSpecDB `json:"database"` + // Configuration settings related to the Authentication used by the Che installation. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Authentication" + Auth CheClusterSpecAuth `json:"auth"` + // Configuration settings related to the Plugin registry used by the Che installation. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Plugin registry" + PluginRegistry CheClusterSpecPluginRegistry `json:"pluginRegistry"` + // Configuration settings related to the Devfile registry used by the Che installation. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Devfile registry" + DevfileRegistry CheClusterSpecDevfileRegistry `json:"devfileRegistry"` + // Configuration settings related to the Dashboard sed by the Che installation. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Devfile registry" + Dashboard CheClusterSpecDashboard `json:"dashboard"` + // Configuration settings related to the persistent storage used by the Che installation. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Persistent storage" + Storage CheClusterSpecStorage `json:"storage"` + // Configuration settings related to the metrics collection used by the Che installation. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Metrics" + Metrics CheClusterSpecMetrics `json:"metrics"` + // Kubernetes Image Puller configuration + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Kubernetes Image Puller" + ImagePuller CheClusterSpecImagePuller `json:"imagePuller"` + // DevWorkspace operator configuration + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Dev Workspace operator" + DevWorkspace CheClusterSpecDevWorkspace `json:"devWorkspace"` +} + +// +k8s:openapi-gen=true +// General configuration settings related to the Che server, the plugin and devfile registries. +type CheClusterSpecServer struct { + // Deployment override options. + // +optional + Deployment DeploymentCustomSettings `json:"deployment,omitempty"` + // Optional host name, or URL, to an alternate container registry to pull images from. + // This value overrides the container registry host name defined in all the default container images involved in a Che deployment. + // This is particularly useful to install Che in a restricted environment. + // +optional + AirGapContainerRegistryHostname string `json:"airGapContainerRegistryHostname,omitempty"` + // Optional repository name of an alternate container registry to pull images from. + // This value overrides the container registry organization defined in all the default container images involved in a Che deployment. + // This is particularly useful to install Eclipse Che in a restricted environment. + // +optional + AirGapContainerRegistryOrganization string `json:"airGapContainerRegistryOrganization,omitempty"` + // Log level for the Che server: `INFO` or `DEBUG`. + // +optional + // +kubebuilder:default:="INFO" + LogLevel string `json:"logLevel,omitempty"` + // Enables the debug mode for Che server. + // +optional + // +kubebuilder:default:="false" + Debug string `json:"debug,omitempty"` + // ClusterRoles that will be assigned to Che ServiceAccount. + // Each role must have `app.kubernetes.io/part-of=che.eclipse.org` label. + // Be aware that the Che Operator has to already have all permissions in these ClusterRoles to grant them. + // +optional + ClusterRoles []string `json:"clusterRoles,omitempty"` + // Custom cluster role bound to the user for the Che workspaces. + // The role must have `app.kubernetes.io/part-of=che.eclipse.org` label. + // The default roles are used when omitted or left blank. + // +optional + WorkspaceServiceAccountClusterRole []string `json:"workspaceServiceAccountClusterRole,omitempty"` + // Defines Kubernetes default namespace in which user's workspaces are created for a case when a user does not override it. + // It's possible to use ``, `` and `` placeholders, such as che-workspace-. + // In that case, a new namespace will be created for each user or workspace. + // +optional + WorkspaceNamespaceName string `json:"workspaceNamespaceName,omitempty"` + // Name of the ConfigMap with public certificates to add to Java trust store of the Che server. + // This is often required when adding the OpenShift OAuth provider, which has HTTPS endpoint signed with self-signed cert. + // The Che server must be aware of its CA cert to be able to request it. This is disabled by default. + // The Config Map must have `app.kubernetes.io/part-of=che.eclipse.org` label. + // +optional + ServerTrustStoreConfigMapName string `json:"serverTrustStoreConfigMapName,omitempty"` + // When enabled, the certificate from `che-git-self-signed-cert` ConfigMap will be propagated to the Che components and provide particular configuration for Git. + // Note, the `che-git-self-signed-cert` ConfigMap must have `app.kubernetes.io/part-of=che.eclipse.org` label. + // +optional + GitSelfSignedCert bool `json:"gitSelfSignedCert"` + // Proxy server settings. + // +optional + Proxy Proxy `json:"proxy"` + // Map of additional environment variables that will be applied in the generated `che` ConfigMap to be used by the Che server, + // in addition to the values already generated from other fields of the `CheCluster` custom resource (CR). + // When `customCheProperties` contains a property that would be normally generated in `che` ConfigMap from other CR fields, + // the value defined in the `customCheProperties` is used instead. + // +optional + CustomCheProperties map[string]string `json:"customCheProperties,omitempty"` + // Default plug-ins applied to Devworkspaces. + // +optional + WorkspacesDefaultPlugins []WorkspacesDefaultPlugins `json:"workspacesDefaultPlugins,omitempty"` + // The node selector that limits the nodes that can run the workspace pods. + // +optional + WorkspacePodNodeSelector map[string]string `json:"workspacePodNodeSelector,omitempty"` + // The pod tolerations put on the workspace pods to limit where the workspace pods can run. + // +optional + WorkspacePodTolerations []corev1.Toleration `json:"workspacePodTolerations,omitempty"` +} + +// Configuration settings related to the persistent storage used by the Che installation. +// +k8s:openapi-gen=true +type CheClusterSpecStorage struct { + // PVC settings. + // +optional + Pvc PVC `json:"pvc,omitempty"` + // Persistent volume claim strategy for the Che server. This Can be:`common` (all workspaces PVCs in one volume), + // `per-workspace` (one PVC per workspace for all declared volumes) and `unique` (one PVC per declared volume). + // +optional + // +kubebuilder:default:="common" + PvcStrategy string `json:"pvcStrategy,omitempty"` + // Instructs the Che server to start a special Pod to pre-create a sub-path in the Persistent Volumes. + // Defaults to `false`, however it will need to enable it according to the configuration of your Kubernetes cluster. + // +optional + PreCreateSubPaths bool `json:"preCreateSubPaths"` + // Overrides the container image used to create sub-paths in the Persistent Volumes. + // This includes the image tag. Omit it or leave it empty to use the default container image provided by the Operator. See also the `preCreateSubPaths` field. + // +optional + PvcJobsImage string `json:"pvcJobsImage,omitempty"` +} + +// Configuration settings related to the Dashaboard used by the Che installation. +// +k8s:openapi-gen=true +type CheClusterSpecDashboard struct { + // Deployment override options. + // +optional + Deployment DeploymentCustomSettings `json:"deployment,omitempty"` + // Warning message that will be displayed on the User Dashboard + // +optional + Warning string `json:"warning,omitempty"` +} + +// Configuration settings related to the Plugin Registry used by the Che installation. +// +k8s:openapi-gen=true +type CheClusterSpecPluginRegistry struct { + // Deployment override options. + // +optional + Deployment DeploymentCustomSettings `json:"deployment,omitempty"` + // Disables internal Plugin registry. + // +optional + DisableInternalRegistry bool `json:"disableInternalRegistry,omitempty"` + // External plugin registries. + // Configure this in addition to a dedicated plugin registry (when `disableInternalRegistry` is `false`) + // or instead of it (when `disableInternalRegistry` is `true`) + // +optional + ExternalPluginRegistries []ExternalPluginRegistry `json:"externalPluginRegistries,omitempty"` +} + +// Configuration settings related to the Devfile Registry used by the Che installation. +// +k8s:openapi-gen=true +type CheClusterSpecDevfileRegistry struct { + // Deployment override options. + // +optional + Deployment DeploymentCustomSettings `json:"deployment,omitempty"` + // Disables internal Devfile registry. + // +optional + DisableInternalRegistry bool `json:"disableInternalRegistry,omitempty"` + // External devfile registries, that serves sample, ready-to-use devfiles. + // Configure this in addition to a dedicated devfile registry (when `disableInternalRegistry` is `false`) + // or instead of it (when `disableInternalRegistry` is `true`) + // +optional + ExternalDevfileRegistries []ExternalDevfileRegistry `json:"externalDevfileRegistries,omitempty"` +} + +// +k8s:openapi-gen=true +// Configuration settings related to the Authentication used by the Che installation. +type CheClusterSpecAuth struct { + // Public URL of the Identity Provider server. + IdentityProviderURL string `json:"identityProviderURL,omitempty"` + // Name of the OpenShift `OAuthClient` resource used to setup identity federation on the OpenShift side. + OAuthClientName string `json:"oAuthClientName,omitempty"` + // Name of the secret set in the OpenShift `OAuthClient` resource used to setup identity federation on the OpenShift side. + OAuthSecret string `json:"oAuthSecret,omitempty"` + // Gateway settings. + // +optional + Gateway GatewayCustomSettings `json:"gateway,omitempty"` +} + +// Configuration settings related to the database used by the Che installation. +// +k8s:openapi-gen=true +type CheClusterSpecDB struct { + // Instructs the Operator on whether to deploy a dedicated database. + // By default, a dedicated PostgreSQL database is deployed as part of the Che installation. When `externalDb` is `true`, no dedicated database will be deployed by the + // Operator and you will need to provide connection details to the external DB you are about to use. See also all the fields starting with: `chePostgres`. + // +optional + ExternalDb bool `json:"externalDb"` + // Deployment override options. + // +optional + Deployment DeploymentCustomSettings `json:"deployment,omitempty"` + // PostgreSQL Database host name that the Che server uses to connect to. + // Override this value ONLY when using an external database. See field `externalDb`. + // +kubebuilder:default:="postgres" + // +optional + PostgresHostName string `json:"postgresHostName,omitempty"` + // PostgreSQL Database port that the Che server uses to connect to. Defaults to 5432. + // Override this value ONLY when using an external database. See field `externalDb`. In the default case it will be automatically set by the Operator. + // +optional + // +kubebuilder:default:="5432" + PostgresPort string `json:"postgresPort,omitempty"` + // PostgreSQL database name that the Che server uses to connect to the DB. + // +optional + // +kubebuilder:default:="dbche" + PostgresDb string `json:"postgresDb,omitempty"` + // The secret that contains PostgreSQL `user` and `password` that the Che server uses to connect to the DB. + // The secret must have `app.kubernetes.io/part-of=che.eclipse.org` label. + // +optional + // +kubebuilder:default:="che-postgres-secret" + CredentialsSecretRef string `json:"credentialsSecretRef,omitempty"` + // Indicates a PostgreSQL version image to use. Allowed values are: `9.6` and `13.3`. + // Migrate your PostgreSQL database to switch from one version to another. + // +optional + PostgresVersion string `json:"postgresVersion,omitempty"` + // PVC settings for PostgreSQL database. + // +optional + Pvc PVC `json:"pvc,omitempty"` +} + +type CheClusterSpecMetrics struct { + // Enables `metrics` the Che server endpoint. Default to `true`. + // +optional + Enable bool `json:"enable"` +} + +// Configuration settings for installation and configuration of the Kubernetes Image Puller +// See https://github.com/che-incubator/kubernetes-image-puller-operator +// +k8s:openapi-gen=true +type CheClusterSpecImagePuller struct { + // Install and configure the Community Supported Kubernetes Image Puller Operator. When set to `true` and no spec is provided, + // it will create a default KubernetesImagePuller object to be managed by the Operator. + // When set to `false`, the KubernetesImagePuller object will be deleted, and the Operator will be uninstalled, + // regardless of whether a spec is provided. + // If the `spec.images` field is empty, a set of recommended workspace-related images will be automatically detected and + // pre-pulled after installation. + // Note that while this Operator and its behavior is community-supported, its payload may be commercially-supported + // for pulling commercially-supported images. + Enable bool `json:"enable"` + // A KubernetesImagePullerSpec to configure the image puller in the CheCluster + // +optional + Spec chev1alpha1.KubernetesImagePullerSpec `json:"spec"` +} + +// Settings for installation and configuration of the DevWorkspace operator +// See https://github.com/devfile/devworkspace-operator +// +k8s:openapi-gen=true +type CheClusterSpecDevWorkspace struct { + // Deployment override options. + // +optional + Deployment DeploymentCustomSettings `json:"deployment,omitempty"` + // Maximum number of the running workspaces per user. + // +optional + RunningLimit string `json:"runningLimit,omitempty"` +} + +type WorkspacesDefaultPlugins struct { + // The editor id to specify default plug-ins for. + Editor string `json:"editor,omitempty"` + // Default plug-in uris for the specified editor. + Plugins []string `json:"plugins,omitempty"` +} + +// Gateway custom settings. +type GatewayCustomSettings struct { + // The image used for the gateway . Omit it or leave it empty to use the default container image provided by the Operator. + // +optional + Image string `json:"image,omitempty"` + // The image used for the gateway sidecar that provides configuration to the gateway. Omit it or leave it empty to use the default container image provided by the Operator. + // +optional + ConfigSidecarImage string `json:"configSidecarImage,omitempty"` + // Gateway sidecar responsible for authentication. + // See link:https://github.com/oauth2-proxy/oauth2-proxy[oauth2-proxy] or link:https://github.com/openshift/oauth-proxy[openshift/oauth-proxy]. + // +optional + AuthenticationSidecarImage string `json:"authenticationSidecarImage,omitempty"` + // Gateway sidecar responsible for authorization. + // See link:https://github.com/brancz/kube-rbac-proxy[kube-rbac-proxy] or link:https://github.com/openshift/kube-rbac-proxy[openshift/kube-rbac-proxy] + // +optional + AuthorizationSidecarImage string `json:"authorizationSidecarImage,omitempty"` + // The labels that need to be present in the ConfigMaps representing the gateway configuration. + // +optional + ConfigLabels map[string]string `json:"configLabels,omitempty"` + // The Che server ingress custom settings. + // +optional + Ingress IngressCustomSettings `json:"ingress,omitempty"` + // The Che server route custom settings. + // +optional + Route RouteCustomSettings `json:"route,omitempty"` +} + +// Route custom settings. +type RouteCustomSettings struct { + // Comma separated list of labels that can be used to organize and categorize objects by scoping and selecting. + // +optional + Labels map[string]string `json:"labels,omitempty"` + // Unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. + // +optional + Annotations map[string]string `json:"annotations,omitempty"` + // Operator uses the domain to generate a hostname for a route. + // In a conjunction with labels it creates a route, which is served by a non-default Ingress controller. + // The generated host name will follow this pattern: `-.`. + // +optional + Domain string `json:"domain,omitempty"` + // Public host name of the installed Che server. When value is omitted, the value it will be automatically set by the Operator. + // +optional + Host string `json:"host,omitempty"` + // Name of a secret containing certificates to secure route. + // The secret must have `app.kubernetes.io/part-of=che.eclipse.org` label. + // +optional + TlsSecretRef string `json:"tlsSecretRef,omitempty"` +} + +// Ingress custom settings. +type IngressCustomSettings struct { + // Comma separated list of labels that can be used to organize and categorize objects by scoping and selecting. + // +optional + Labels map[string]string `json:"labels,omitempty"` + // Unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. + // When not specified, this defaults to: + // kubernetes.io/ingress.class: "nginx" + // nginx.ingress.kubernetes.io/proxy-read-timeout: "3600", + // nginx.ingress.kubernetes.io/proxy-connect-timeout: "3600", + // nginx.ingress.kubernetes.io/ssl-redirect: "true" + // +optional + Annotations map[string]string `json:"annotations,omitempty"` + // Global ingress domain for a Kubernetes cluster. This MUST be explicitly specified: there are no defaults. + Domain string `json:"domain,omitempty"` + // Public host name of the installed Che server. When value is omitted, the value it will be automatically set by the Operator. + // +optional + Host string `json:"host,omitempty"` + // Name of a secret that will be used to setup ingress TLS termination when. + // When the field is empty string, the default cluster certificate will be used. + // The secret must have `app.kubernetes.io/part-of=che.eclipse.org` label. + // +optional + TlsSecretRef string `json:"tlsSecretRef,omitempty"` +} + +// Proxy server configuration. +type Proxy struct { + // URL (protocol+host name) of the proxy server. + // This drives the appropriate changes in the `JAVA_OPTS` and `https(s)_proxy` variables in the Che server and workspaces containers. + // Only use when configuring a proxy is required. Operator respects OpenShift cluster wide proxy configuration + // and no additional configuration is required, but defining `proxyUrl` in a custom resource leads to overrides the cluster proxy configuration + // with fields `proxyUrl`, `proxyPort`, `proxyUser` and `proxyPassword` from the custom resource. + // See the doc https://docs.openshift.com/container-platform/4.4/networking/enable-cluster-wide-proxy.html. See also the `proxyPort` and `nonProxyHosts` fields. + // +optional + Url string `json:"url,omitempty"` + // Port of the proxy server. + // +optional + Port string `json:"port,omitempty"` + // List of hosts that will be reached directly, bypassing the proxy. + // Specify wild card domain use the following form `.`, for example: + // - localhost + // - my.host.com + // - 123.42.12.32 + // Only use when configuring a proxy is required. Operator respects OpenShift cluster wide proxy configuration and no additional configuration is required, + // but defining `nonProxyHosts` in a custom resource leads to merging non proxy hosts lists from the cluster proxy configuration and ones defined in the custom resources. + // See the doc https://docs.openshift.com/container-platform/4.4/networking/enable-cluster-wide-proxy.html. See also the `proxyURL` fields. + NonProxyHosts []string `json:"nonProxyHosts,omitempty"` + // The secret name that contains `user` and `password` for a proxy server. + // The secret must have `app.kubernetes.io/part-of=che.eclipse.org` label. + // +optional + CredentialsSecretRef string `json:"credentialsSecretRef,omitempty"` +} + +// PersistentVolumeClaim custom settings. +type PVC struct { + // Persistent Volume Claim size. To update the claim size, Storage class that provisions it must support resize. + // +optional + ClaimSize string `json:"claimSize,omitempty"` + // Storage class for the Persistent Volume Claim. When omitted or left blank, a default storage class is used. + // +optional + StorageClass string `json:"storageClass,omitempty"` +} + +// External devfile registries configuration. +type ExternalDevfileRegistry struct { + // Public URL of the devfile registry that serves sample ready-to-use devfiles. + // +optional + Url string `json:"url,omitempty"` +} + +// External plugin registries configuration. +type ExternalPluginRegistry struct { + // Public URL of the plugin registry. + // +optional + Url string `json:"url,omitempty"` +} + +// Deployment custom settings. +type DeploymentCustomSettings struct { + // A single application container. + // +optional + Container ContainerCustomSettings `json:"container,omitempty"` + // Security options the pod should run with. + // +optional + SecurityContext PodSecurityContextCustomSettings `json:"securityContext,omitempty"` +} + +// Container custom settings. +type ContainerCustomSettings struct { + // Container image. Omit it or leave it empty to use the default container image provided by the Operator. + // +optional + Image string `json:"image,omitempty"` + // Image pull policy. Default value is `Always` for `nightly`, `next` or `latest` images, and `IfNotPresent` in other cases. + // +optional + ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"` + // Compute Resources required by this container. + // +optional + Resources ResourceRequirementsCustomSettings `json:"resources,omitempty"` +} + +// Describes the compute resource requirements. +type ResourceRequirementsCustomSettings struct { + // Requests describes the minimum amount of compute resources required. + // +optional + Requests ResourceListCustomSettings `json:"request,omitempty"` + // Limits describes the maximum amount of compute resources allowed. + // +optional + Limits ResourceListCustomSettings `json:"limits,omitempty"` +} + +// List of resources. +type ResourceListCustomSettings struct { + // Memory, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024) + // +optional + Memory string `json:"memory,omitempty"` + // CPU, in cores. (500m = .5 cores) + // +optional + Cpu string `json:"cpu,omitempty"` +} + +// PodSecurityContext holds pod-level security attributes and common container settings. +type PodSecurityContextCustomSettings struct { + // The UID to run the entrypoint of the container process. Default value is `1724`. + // +optional + RunAsUser string `json:"runAsUser,omitempty"` + // A special supplemental group that applies to all containers in a pod. Default value is `1724`. + // +optional + FsGroup string `json:"fsGroup,omitempty"` +} + +// GatewayPhase describes the different phases of the Che gateway lifecycle +type GatewayPhase string + +const ( + GatewayPhaseInitializing = "Initializing" + GatewayPhaseEstablished = "Established" + GatewayPhaseInactive = "Inactive" +) + +// ClusterPhase describes the different phases of the Che cluster lifecycle +type ClusterPhase string + +const ( + ClusterPhaseActive = "Active" + ClusterPhaseInactive = "Inactive" + ClusterPhasePendingDeletion = "PendingDeletion" + RollingUpdate = "RollingUpdate" +) + +// CheClusterStatus defines the observed state of Che installation +type CheClusterStatus struct { + // Current installed Che version. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=status + // +operator-sdk:csv:customresourcedefinitions:type=status,displayName="displayName: Eclipse Che version" + // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors="urn:alm:descriptor:org.w3:link" + CheVersion string `json:"cheVersion"` + // Public URL to the Che server. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=status + // +operator-sdk:csv:customresourcedefinitions:type=status,displayName="Eclipse Che URL" + // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors="urn:alm:descriptor:org.w3:link" + CheURL string `json:"cheURL"` + // Public URL to the devfile registry. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=status + // +operator-sdk:csv:customresourcedefinitions:type=status,displayName="Devfile registry URL" + // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors="urn:alm:descriptor:org.w3:link" + DevfileRegistryURL string `json:"devfileRegistryURL"` + // Public URL to the plugin registry. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=status + // +operator-sdk:csv:customresourcedefinitions:type=status,displayName="Plugin registry URL" + // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors="urn:alm:descriptor:org.w3:link" + PluginRegistryURL string `json:"pluginRegistryURL"` + // Phase is the phase in which the Che cluster as a whole finds itself in. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=status + // +operator-sdk:csv:customresourcedefinitions:type=status,displayName="Phase" + // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors="urn:alm:descriptor:text" + Phase ClusterPhase `json:"phase,omitempty"` + // A human readable message indicating details about why the Pod is in this condition. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=status + // +operator-sdk:csv:customresourcedefinitions:type=status,displayName="Message" + // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors="urn:alm:descriptor:text" + Message string `json:"message,omitempty"` + // A brief CamelCase message indicating details about why the Pod is in this state. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=status + // +operator-sdk:csv:customresourcedefinitions:type=status,displayName="Reason" + // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors="urn:alm:descriptor:text" + Reason string `json:"reason,omitempty"` + // A URL that points to some URL where to find help related to the current Operator status. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=status + // +operator-sdk:csv:customresourcedefinitions:type=status,displayName="Help link" + // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors="urn:alm:descriptor:org.w3:link" + HelpLink string `json:"helpLink,omitempty"` +} + +// The `CheCluster` custom resource allows defining and managing a Che server installation +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +k8s:openapi-gen=true +// +operator-sdk:csv:customresourcedefinitions:displayName="Eclipse Che instance Specification" +// +operator-sdk:csv:customresourcedefinitions:order=0 +// +operator-sdk:csv:customresourcedefinitions:resources={{Ingress,v1},{Route,v1},{ConfigMap,v1},{Service,v1},{Secret,v1},{Deployment,apps/v1},{Role,v1},{RoleBinding,v1},{ClusterRole,v1},{ClusterRoleBinding,v1}} +// +kubebuilder:storageversion +type CheCluster struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Desired configuration of the Che installation. + // Based on these settings, the Operator automatically creates and maintains + // several ConfigMaps that will contain the appropriate environment variables + // the various components of the Che installation. + // These generated ConfigMaps must NOT be updated manually. + Spec CheClusterSpec `json:"spec,omitempty"` + + // CheClusterStatus defines the observed state of Che installation + Status CheClusterStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true +// CheClusterList contains a list of CheCluster +type CheClusterList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CheCluster `json:"items"` +} + +func init() { + SchemeBuilder.Register(&CheCluster{}, &CheClusterList{}) +} + +func (c *CheCluster) IsAirGapMode() bool { + return c.Spec.Server.AirGapContainerRegistryHostname != "" || + c.Spec.Server.AirGapContainerRegistryOrganization != "" +} + +func (c *CheCluster) IsImagePullerSpecEmpty() bool { + return c.Spec.ImagePuller.Spec == (chev1alpha1.KubernetesImagePullerSpec{}) +} + +func (c *CheCluster) IsImagePullerImagesEmpty() bool { + return len(c.Spec.ImagePuller.Spec.Images) == 0 +} diff --git a/api/v2/checluster_webhook.go b/api/v2/checluster_webhook.go new file mode 100644 index 0000000000..7d25d00db9 --- /dev/null +++ b/api/v2/checluster_webhook.go @@ -0,0 +1,29 @@ +// +// Copyright (c) 2019-2022 Red Hat, Inc. +// This program and the accompanying materials are made +// available under the terms of the Eclipse Public License 2.0 +// which is available at https://www.eclipse.org/legal/epl-2.0/ +// +// SPDX-License-Identifier: EPL-2.0 +// +// Contributors: +// Red Hat, Inc. - initial API and implementation +// + +package v2 + +import ( + ctrl "sigs.k8s.io/controller-runtime" + logf "sigs.k8s.io/controller-runtime/pkg/log" +) + +// log is for logging in this package. +var checlusterlog = logf.Log.WithName("checluster-resource") + +func (r *CheCluster) SetupWebhookWithManager(mgr ctrl.Manager) error { + return ctrl.NewWebhookManagedBy(mgr). + For(r). + Complete() +} + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! diff --git a/api/v2/conversion.go b/api/v2/conversion.go new file mode 100644 index 0000000000..f220eede90 --- /dev/null +++ b/api/v2/conversion.go @@ -0,0 +1,15 @@ +// +// Copyright (c) 2019-2022 Red Hat, Inc. +// This program and the accompanying materials are made +// available under the terms of the Eclipse Public License 2.0 +// which is available at https://www.eclipse.org/legal/epl-2.0/ +// +// SPDX-License-Identifier: EPL-2.0 +// +// Contributors: +// Red Hat, Inc. - initial API and implementation +// + +package v2 + +func (*CheCluster) Hub() {} diff --git a/api/v2/groupversion_info.go b/api/v2/groupversion_info.go new file mode 100644 index 0000000000..5ded69324d --- /dev/null +++ b/api/v2/groupversion_info.go @@ -0,0 +1,32 @@ +// +// Copyright (c) 2019-2021 Red Hat, Inc. +// This program and the accompanying materials are made +// available under the terms of the Eclipse Public License 2.0 +// which is available at https://www.eclipse.org/legal/epl-2.0/ +// +// SPDX-License-Identifier: EPL-2.0 +// +// Contributors: +// Red Hat, Inc. - initial API and implementation +// + +// Package v2 contains API Schema definitions for the org v2 API group +//+kubebuilder:object:generate=true +//+groupName=org.eclipse.che +package v2 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "org.eclipse.che", Version: "v2"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/api/v2/zz_generated.deepcopy.go b/api/v2/zz_generated.deepcopy.go new file mode 100644 index 0000000000..b9284d5252 --- /dev/null +++ b/api/v2/zz_generated.deepcopy.go @@ -0,0 +1,577 @@ +// +build !ignore_autogenerated + +// +// Copyright (c) 2019-2021 Red Hat, Inc. +// This program and the accompanying materials are made +// available under the terms of the Eclipse Public License 2.0 +// which is available at https://www.eclipse.org/legal/epl-2.0/ +// +// SPDX-License-Identifier: EPL-2.0 +// +// Contributors: +// Red Hat, Inc. - initial API and implementation +// + +// Code generated by controller-gen. DO NOT EDIT. + +package v2 + +import ( + v1 "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheCluster) DeepCopyInto(out *CheCluster) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheCluster. +func (in *CheCluster) DeepCopy() *CheCluster { + if in == nil { + return nil + } + out := new(CheCluster) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CheCluster) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheClusterList) DeepCopyInto(out *CheClusterList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CheCluster, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterList. +func (in *CheClusterList) DeepCopy() *CheClusterList { + if in == nil { + return nil + } + out := new(CheClusterList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CheClusterList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheClusterSpec) DeepCopyInto(out *CheClusterSpec) { + *out = *in + in.Server.DeepCopyInto(&out.Server) + out.Database = in.Database + in.Auth.DeepCopyInto(&out.Auth) + in.PluginRegistry.DeepCopyInto(&out.PluginRegistry) + in.DevfileRegistry.DeepCopyInto(&out.DevfileRegistry) + out.Dashboard = in.Dashboard + out.Storage = in.Storage + out.Metrics = in.Metrics + out.ImagePuller = in.ImagePuller + out.DevWorkspace = in.DevWorkspace +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterSpec. +func (in *CheClusterSpec) DeepCopy() *CheClusterSpec { + if in == nil { + return nil + } + out := new(CheClusterSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheClusterSpecAuth) DeepCopyInto(out *CheClusterSpecAuth) { + *out = *in + in.Gateway.DeepCopyInto(&out.Gateway) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterSpecAuth. +func (in *CheClusterSpecAuth) DeepCopy() *CheClusterSpecAuth { + if in == nil { + return nil + } + out := new(CheClusterSpecAuth) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheClusterSpecDB) DeepCopyInto(out *CheClusterSpecDB) { + *out = *in + out.Deployment = in.Deployment + out.Pvc = in.Pvc +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterSpecDB. +func (in *CheClusterSpecDB) DeepCopy() *CheClusterSpecDB { + if in == nil { + return nil + } + out := new(CheClusterSpecDB) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheClusterSpecDashboard) DeepCopyInto(out *CheClusterSpecDashboard) { + *out = *in + out.Deployment = in.Deployment +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterSpecDashboard. +func (in *CheClusterSpecDashboard) DeepCopy() *CheClusterSpecDashboard { + if in == nil { + return nil + } + out := new(CheClusterSpecDashboard) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheClusterSpecDevWorkspace) DeepCopyInto(out *CheClusterSpecDevWorkspace) { + *out = *in + out.Deployment = in.Deployment +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterSpecDevWorkspace. +func (in *CheClusterSpecDevWorkspace) DeepCopy() *CheClusterSpecDevWorkspace { + if in == nil { + return nil + } + out := new(CheClusterSpecDevWorkspace) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheClusterSpecDevfileRegistry) DeepCopyInto(out *CheClusterSpecDevfileRegistry) { + *out = *in + out.Deployment = in.Deployment + if in.ExternalDevfileRegistries != nil { + in, out := &in.ExternalDevfileRegistries, &out.ExternalDevfileRegistries + *out = make([]ExternalDevfileRegistry, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterSpecDevfileRegistry. +func (in *CheClusterSpecDevfileRegistry) DeepCopy() *CheClusterSpecDevfileRegistry { + if in == nil { + return nil + } + out := new(CheClusterSpecDevfileRegistry) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheClusterSpecImagePuller) DeepCopyInto(out *CheClusterSpecImagePuller) { + *out = *in + out.Spec = in.Spec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterSpecImagePuller. +func (in *CheClusterSpecImagePuller) DeepCopy() *CheClusterSpecImagePuller { + if in == nil { + return nil + } + out := new(CheClusterSpecImagePuller) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheClusterSpecMetrics) DeepCopyInto(out *CheClusterSpecMetrics) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterSpecMetrics. +func (in *CheClusterSpecMetrics) DeepCopy() *CheClusterSpecMetrics { + if in == nil { + return nil + } + out := new(CheClusterSpecMetrics) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheClusterSpecPluginRegistry) DeepCopyInto(out *CheClusterSpecPluginRegistry) { + *out = *in + out.Deployment = in.Deployment + if in.ExternalPluginRegistries != nil { + in, out := &in.ExternalPluginRegistries, &out.ExternalPluginRegistries + *out = make([]ExternalPluginRegistry, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterSpecPluginRegistry. +func (in *CheClusterSpecPluginRegistry) DeepCopy() *CheClusterSpecPluginRegistry { + if in == nil { + return nil + } + out := new(CheClusterSpecPluginRegistry) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheClusterSpecServer) DeepCopyInto(out *CheClusterSpecServer) { + *out = *in + out.Deployment = in.Deployment + if in.ClusterRoles != nil { + in, out := &in.ClusterRoles, &out.ClusterRoles + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.WorkspaceServiceAccountClusterRole != nil { + in, out := &in.WorkspaceServiceAccountClusterRole, &out.WorkspaceServiceAccountClusterRole + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.Proxy.DeepCopyInto(&out.Proxy) + if in.CustomCheProperties != nil { + in, out := &in.CustomCheProperties, &out.CustomCheProperties + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.WorkspacesDefaultPlugins != nil { + in, out := &in.WorkspacesDefaultPlugins, &out.WorkspacesDefaultPlugins + *out = make([]WorkspacesDefaultPlugins, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.WorkspacePodNodeSelector != nil { + in, out := &in.WorkspacePodNodeSelector, &out.WorkspacePodNodeSelector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.WorkspacePodTolerations != nil { + in, out := &in.WorkspacePodTolerations, &out.WorkspacePodTolerations + *out = make([]v1.Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterSpecServer. +func (in *CheClusterSpecServer) DeepCopy() *CheClusterSpecServer { + if in == nil { + return nil + } + out := new(CheClusterSpecServer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheClusterSpecStorage) DeepCopyInto(out *CheClusterSpecStorage) { + *out = *in + out.Pvc = in.Pvc +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterSpecStorage. +func (in *CheClusterSpecStorage) DeepCopy() *CheClusterSpecStorage { + if in == nil { + return nil + } + out := new(CheClusterSpecStorage) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheClusterStatus) DeepCopyInto(out *CheClusterStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterStatus. +func (in *CheClusterStatus) DeepCopy() *CheClusterStatus { + if in == nil { + return nil + } + out := new(CheClusterStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerCustomSettings) DeepCopyInto(out *ContainerCustomSettings) { + *out = *in + out.Resources = in.Resources +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerCustomSettings. +func (in *ContainerCustomSettings) DeepCopy() *ContainerCustomSettings { + if in == nil { + return nil + } + out := new(ContainerCustomSettings) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeploymentCustomSettings) DeepCopyInto(out *DeploymentCustomSettings) { + *out = *in + out.Container = in.Container + out.SecurityContext = in.SecurityContext +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentCustomSettings. +func (in *DeploymentCustomSettings) DeepCopy() *DeploymentCustomSettings { + if in == nil { + return nil + } + out := new(DeploymentCustomSettings) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExternalDevfileRegistry) DeepCopyInto(out *ExternalDevfileRegistry) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalDevfileRegistry. +func (in *ExternalDevfileRegistry) DeepCopy() *ExternalDevfileRegistry { + if in == nil { + return nil + } + out := new(ExternalDevfileRegistry) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExternalPluginRegistry) DeepCopyInto(out *ExternalPluginRegistry) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalPluginRegistry. +func (in *ExternalPluginRegistry) DeepCopy() *ExternalPluginRegistry { + if in == nil { + return nil + } + out := new(ExternalPluginRegistry) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GatewayCustomSettings) DeepCopyInto(out *GatewayCustomSettings) { + *out = *in + if in.ConfigLabels != nil { + in, out := &in.ConfigLabels, &out.ConfigLabels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + in.Ingress.DeepCopyInto(&out.Ingress) + in.Route.DeepCopyInto(&out.Route) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayCustomSettings. +func (in *GatewayCustomSettings) DeepCopy() *GatewayCustomSettings { + if in == nil { + return nil + } + out := new(GatewayCustomSettings) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IngressCustomSettings) DeepCopyInto(out *IngressCustomSettings) { + *out = *in + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressCustomSettings. +func (in *IngressCustomSettings) DeepCopy() *IngressCustomSettings { + if in == nil { + return nil + } + out := new(IngressCustomSettings) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PVC) DeepCopyInto(out *PVC) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PVC. +func (in *PVC) DeepCopy() *PVC { + if in == nil { + return nil + } + out := new(PVC) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodSecurityContextCustomSettings) DeepCopyInto(out *PodSecurityContextCustomSettings) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodSecurityContextCustomSettings. +func (in *PodSecurityContextCustomSettings) DeepCopy() *PodSecurityContextCustomSettings { + if in == nil { + return nil + } + out := new(PodSecurityContextCustomSettings) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Proxy) DeepCopyInto(out *Proxy) { + *out = *in + if in.NonProxyHosts != nil { + in, out := &in.NonProxyHosts, &out.NonProxyHosts + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Proxy. +func (in *Proxy) DeepCopy() *Proxy { + if in == nil { + return nil + } + out := new(Proxy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceListCustomSettings) DeepCopyInto(out *ResourceListCustomSettings) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceListCustomSettings. +func (in *ResourceListCustomSettings) DeepCopy() *ResourceListCustomSettings { + if in == nil { + return nil + } + out := new(ResourceListCustomSettings) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceRequirementsCustomSettings) DeepCopyInto(out *ResourceRequirementsCustomSettings) { + *out = *in + out.Requests = in.Requests + out.Limits = in.Limits +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceRequirementsCustomSettings. +func (in *ResourceRequirementsCustomSettings) DeepCopy() *ResourceRequirementsCustomSettings { + if in == nil { + return nil + } + out := new(ResourceRequirementsCustomSettings) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouteCustomSettings) DeepCopyInto(out *RouteCustomSettings) { + *out = *in + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteCustomSettings. +func (in *RouteCustomSettings) DeepCopy() *RouteCustomSettings { + if in == nil { + return nil + } + out := new(RouteCustomSettings) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkspacesDefaultPlugins) DeepCopyInto(out *WorkspacesDefaultPlugins) { + *out = *in + if in.Plugins != nil { + in, out := &in.Plugins, &out.Plugins + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspacesDefaultPlugins. +func (in *WorkspacesDefaultPlugins) DeepCopy() *WorkspacesDefaultPlugins { + if in == nil { + return nil + } + out := new(WorkspacesDefaultPlugins) + in.DeepCopyInto(out) + return out +} diff --git a/api/v2alpha1/checluster_types.go b/api/v2alpha1/checluster_types.go index 499eed655c..7efae58078 100644 --- a/api/v2alpha1/checluster_types.go +++ b/api/v2alpha1/checluster_types.go @@ -178,6 +178,7 @@ type CheClusterStatusV2Alpha1 struct { // CheCluster is the configuration of the CheCluster layer of Devworkspace. // +k8s:openapi-gen=true // +kubebuilder:subresource:status +// +kubebuilder:skipversion // +kubebuilder:resource:path=checlusters,scope=Namespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +operator-sdk:csv:customresourcedefinitions:displayName="Eclipse Che Cluster" diff --git a/bundle/next/eclipse-che-preview-openshift/manifests/che-operator.clusterserviceversion.yaml b/bundle/next/eclipse-che-preview-openshift/manifests/che-operator.clusterserviceversion.yaml index ecf31b7953..e0541abefb 100644 --- a/bundle/next/eclipse-che-preview-openshift/manifests/che-operator.clusterserviceversion.yaml +++ b/bundle/next/eclipse-che-preview-openshift/manifests/che-operator.clusterserviceversion.yaml @@ -75,12 +75,133 @@ metadata: operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/eclipse-che/che-operator support: Eclipse Foundation - name: eclipse-che-preview-openshift.v7.45.0-436.next + name: eclipse-che-preview-openshift.v7.45.0-442.next namespace: placeholder spec: apiservicedefinitions: {} customresourcedefinitions: owned: + - description: The `CheCluster` custom resource allows defining and managing + a Che server installation + displayName: Eclipse Che instance Specification + kind: CheCluster + name: checlusters.org.eclipse.che + resources: + - kind: ClusterRole + name: '' + version: v1 + - kind: ClusterRoleBinding + name: '' + version: v1 + - kind: ConfigMap + name: '' + version: v1 + - kind: Deployment + name: '' + version: apps/v1 + - kind: Ingress + name: '' + version: v1 + - kind: Role + name: '' + version: v1 + - kind: RoleBinding + name: '' + version: v1 + - kind: Route + name: '' + version: v1 + - kind: Secret + name: '' + version: v1 + - kind: Service + name: '' + version: v1 + specDescriptors: + - description: Configuration settings related to the Authentication used + by the Che installation. + displayName: Authentication + path: auth + - description: Configuration settings related to the Dashboard sed by the + Che installation. + displayName: Devfile registry + path: dashboard + - description: Configuration settings related to the database used by the + Che installation. + displayName: Database + path: database + - description: DevWorkspace operator configuration + displayName: Dev Workspace operator + path: devWorkspace + - description: Configuration settings related to the Devfile registry used + by the Che installation. + displayName: Devfile registry + path: devfileRegistry + - description: Kubernetes Image Puller configuration + displayName: Kubernetes Image Puller + path: imagePuller + - description: Configuration settings related to the metrics collection + used by the Che installation. + displayName: Metrics + path: metrics + - description: Configuration settings related to the Plugin registry used + by the Che installation. + displayName: Plugin registry + path: pluginRegistry + - description: General configuration settings related to the Che server, + the plugin and devfile registries + displayName: Che server + path: server + - description: Configuration settings related to the persistent storage + used by the Che installation. + displayName: Persistent storage + path: storage + statusDescriptors: + - description: Public URL to the Che server. + displayName: Eclipse Che URL + path: cheURL + x-descriptors: + - urn:alm:descriptor:org.w3:link + - description: Current installed Che version. + displayName: 'displayName: Eclipse Che version' + path: cheVersion + x-descriptors: + - urn:alm:descriptor:org.w3:link + - description: Public URL to the devfile registry. + displayName: Devfile registry URL + path: devfileRegistryURL + x-descriptors: + - urn:alm:descriptor:org.w3:link + - description: A URL that points to some URL where to find help related + to the current Operator status. + displayName: Help link + path: helpLink + x-descriptors: + - urn:alm:descriptor:org.w3:link + - description: A human readable message indicating details about why the + Pod is in this condition. + displayName: Message + path: message + x-descriptors: + - urn:alm:descriptor:text + - description: Phase is the phase in which the Che cluster as a whole finds + itself in. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:text + - description: Public URL to the plugin registry. + displayName: Plugin registry URL + path: pluginRegistryURL + x-descriptors: + - urn:alm:descriptor:org.w3:link + - description: A brief CamelCase message indicating details about why the + Pod is in this state. + displayName: Reason + path: reason + x-descriptors: + - urn:alm:descriptor:text + version: v2 - description: The `CheCluster` custom resource allows defining and managing a Che server installation displayName: Eclipse Che instance Specification @@ -1026,6 +1147,9 @@ spec: timeoutSeconds: 5 name: che-operator ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP - containerPort: 60000 name: metrics readinessProbe: @@ -1052,12 +1176,21 @@ spec: privileged: false readOnlyRootFilesystem: false runAsNonRoot: true + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true hostIPC: false hostNetwork: false hostPID: false restartPolicy: Always serviceAccountName: che-operator terminationGracePeriodSeconds: 20 + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: webhook-server-cert permissions: - rules: - apiGroups: @@ -1284,4 +1417,17 @@ spec: maturity: stable provider: name: Eclipse Foundation - version: 7.45.0-436.next + version: 7.45.0-442.next + webhookdefinitions: + - admissionReviewVersions: + - v1 + - v2 + containerPort: 443 + conversionCRDs: + - checlusters.org.eclipse.che + deploymentName: che-operator + generateName: ccheclusters.kb.io + sideEffects: None + targetPort: 9443 + type: ConversionWebhook + webhookPath: /convert diff --git a/bundle/next/eclipse-che-preview-openshift/manifests/org_v1_che_crd.yaml b/bundle/next/eclipse-che-preview-openshift/manifests/org_v1_che_crd.yaml index 34f3b53377..166d1ee89b 100644 --- a/bundle/next/eclipse-che-preview-openshift/manifests/org_v1_che_crd.yaml +++ b/bundle/next/eclipse-che-preview-openshift/manifests/org_v1_che_crd.yaml @@ -14,6 +14,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: + cert-manager.io/inject-ca-from: eclipse-che/serving-cert controller-gen.kubebuilder.io/version: v0.4.1 creationTimestamp: null labels: @@ -22,6 +23,17 @@ metadata: app.kubernetes.io/name: che name: checlusters.org.eclipse.che spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: webhook-service + namespace: eclipse-che + path: /convert + conversionReviewVersions: + - v1 + - v2 group: org.eclipse.che names: kind: CheCluster @@ -1226,6 +1238,932 @@ spec: type: object type: object served: true + storage: false + subresources: + status: {} + - name: v2 + schema: + openAPIV3Schema: + description: The `CheCluster` custom resource allows defining and managing + a Che server installation + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource + this object represents. Servers may infer this from the endpoint the + client submits requests to. Cannot be updated. In CamelCase. More + info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Desired configuration of the Che installation. Based on + these settings, the Operator automatically creates and maintains + several ConfigMaps that will contain the appropriate environment variables + the various components of the Che installation. These generated ConfigMaps + must NOT be updated manually. + properties: + auth: + description: Configuration settings related to the Authentication + used by the Che installation. + properties: + gateway: + description: Gateway settings. + properties: + authenticationSidecarImage: + description: Gateway sidecar responsible for authentication. + See link:https://github.com/oauth2-proxy/oauth2-proxy[oauth2-proxy] + or link:https://github.com/openshift/oauth-proxy[openshift/oauth-proxy]. + type: string + authorizationSidecarImage: + description: Gateway sidecar responsible for authorization. + See link:https://github.com/brancz/kube-rbac-proxy[kube-rbac-proxy] + or link:https://github.com/openshift/kube-rbac-proxy[openshift/kube-rbac-proxy] + type: string + configLabels: + additionalProperties: + type: string + description: The labels that need to be present in the ConfigMaps + representing the gateway configuration. + type: object + configSidecarImage: + description: The image used for the gateway sidecar that + provides configuration to the gateway. Omit it or leave + it empty to use the default container image provided by + the Operator. + type: string + image: + description: The image used for the gateway . Omit it or + leave it empty to use the default container image provided + by the Operator. + type: string + ingress: + description: The Che server ingress custom settings. + properties: + annotations: + additionalProperties: + type: string + description: 'Unstructured key value map stored with + a resource that may be set by external tools to store + and retrieve arbitrary metadata. When not specified, + this defaults to: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/proxy-read-timeout: "3600", nginx.ingress.kubernetes.io/proxy-connect-timeout: + "3600", nginx.ingress.kubernetes.io/ssl-redirect: "true"' + type: object + domain: + description: 'Global ingress domain for a Kubernetes + cluster. This MUST be explicitly specified: there + are no defaults.' + type: string + host: + description: Public host name of the installed Che server. + When value is omitted, the value it will be automatically + set by the Operator. + type: string + labels: + additionalProperties: + type: string + description: Comma separated list of labels that can + be used to organize and categorize objects by scoping + and selecting. + type: object + tlsSecretRef: + description: Name of a secret that will be used to setup + ingress TLS termination when. When the field is empty + string, the default cluster certificate will be used. + The secret must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: string + type: object + route: + description: The Che server route custom settings. + properties: + annotations: + additionalProperties: + type: string + description: Unstructured key value map stored with + a resource that may be set by external tools to store + and retrieve arbitrary metadata. + type: object + domain: + description: 'Operator uses the domain to generate a + hostname for a route. In a conjunction with labels + it creates a route, which is served by a non-default + Ingress controller. The generated host name will follow + this pattern: `-.`.' + type: string + host: + description: Public host name of the installed Che server. + When value is omitted, the value it will be automatically + set by the Operator. + type: string + labels: + additionalProperties: + type: string + description: Comma separated list of labels that can + be used to organize and categorize objects by scoping + and selecting. + type: object + tlsSecretRef: + description: Name of a secret containing certificates + to secure route. The secret must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: string + type: object + type: object + identityProviderURL: + description: Public URL of the Identity Provider server. + type: string + oAuthClientName: + description: Name of the OpenShift `OAuthClient` resource used + to setup identity federation on the OpenShift side. + type: string + oAuthSecret: + description: Name of the secret set in the OpenShift `OAuthClient` + resource used to setup identity federation on the OpenShift + side. + type: string + type: object + dashboard: + description: Configuration settings related to the Dashboard sed + by the Che installation. + properties: + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + warning: + description: Warning message that will be displayed on the User + Dashboard + type: string + type: object + database: + description: Configuration settings related to the database used + by the Che installation. + properties: + credentialsSecretRef: + default: che-postgres-secret + description: The secret that contains PostgreSQL `user` and + `password` that the Che server uses to connect to the DB. + The secret must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: string + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + externalDb: + description: 'Instructs the Operator on whether to deploy a + dedicated database. By default, a dedicated PostgreSQL database + is deployed as part of the Che installation. When `externalDb` + is `true`, no dedicated database will be deployed by the Operator + and you will need to provide connection details to the external + DB you are about to use. See also all the fields starting + with: `chePostgres`.' + type: boolean + postgresDb: + default: dbche + description: PostgreSQL database name that the Che server uses + to connect to the DB. + type: string + postgresHostName: + default: postgres + description: PostgreSQL Database host name that the Che server + uses to connect to. Override this value ONLY when using an + external database. See field `externalDb`. + type: string + postgresPort: + default: "5432" + description: PostgreSQL Database port that the Che server uses + to connect to. Defaults to 5432. Override this value ONLY + when using an external database. See field `externalDb`. In + the default case it will be automatically set by the Operator. + type: string + postgresVersion: + description: 'Indicates a PostgreSQL version image to use. Allowed + values are: `9.6` and `13.3`. Migrate your PostgreSQL database + to switch from one version to another.' + type: string + pvc: + description: PVC settings for PostgreSQL database. + properties: + claimSize: + description: Persistent Volume Claim size. To update the + claim size, Storage class that provisions it must support + resize. + type: string + storageClass: + description: Storage class for the Persistent Volume Claim. + When omitted or left blank, a default storage class is + used. + type: string + type: object + type: object + devWorkspace: + description: DevWorkspace operator configuration + properties: + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + runningLimit: + description: Maximum number of the running workspaces per user. + type: string + type: object + devfileRegistry: + description: Configuration settings related to the Devfile registry + used by the Che installation. + properties: + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + disableInternalRegistry: + description: Disables internal Devfile registry. + type: boolean + externalDevfileRegistries: + description: External devfile registries, that serves sample, + ready-to-use devfiles. Configure this in addition to a dedicated + devfile registry (when `disableInternalRegistry` is `false`) + or instead of it (when `disableInternalRegistry` is `true`) + items: + description: External devfile registries configuration. + properties: + url: + description: Public URL of the devfile registry that serves + sample ready-to-use devfiles. + type: string + type: object + type: array + type: object + imagePuller: + description: Kubernetes Image Puller configuration + properties: + enable: + description: Install and configure the Community Supported Kubernetes + Image Puller Operator. When set to `true` and no spec is provided, + it will create a default KubernetesImagePuller object to be + managed by the Operator. When set to `false`, the KubernetesImagePuller + object will be deleted, and the Operator will be uninstalled, + regardless of whether a spec is provided. If the `spec.images` + field is empty, a set of recommended workspace-related images + will be automatically detected and pre-pulled after installation. + Note that while this Operator and its behavior is community-supported, + its payload may be commercially-supported for pulling commercially-supported + images. + type: boolean + spec: + description: A KubernetesImagePullerSpec to configure the image + puller in the CheCluster + properties: + affinity: + type: string + cachingCPULimit: + type: string + cachingCPURequest: + type: string + cachingIntervalHours: + type: string + cachingMemoryLimit: + type: string + cachingMemoryRequest: + type: string + configMapName: + type: string + daemonsetName: + type: string + deploymentName: + type: string + imagePullSecrets: + type: string + imagePullerImage: + type: string + images: + type: string + nodeSelector: + type: string + type: object + required: + - enable + type: object + metrics: + description: Configuration settings related to the metrics collection + used by the Che installation. + properties: + enable: + description: Enables `metrics` the Che server endpoint. Default + to `true`. + type: boolean + type: object + pluginRegistry: + description: Configuration settings related to the Plugin registry + used by the Che installation. + properties: + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + disableInternalRegistry: + description: Disables internal Plugin registry. + type: boolean + externalPluginRegistries: + description: External plugin registries. Configure this in addition + to a dedicated plugin registry (when `disableInternalRegistry` + is `false`) or instead of it (when `disableInternalRegistry` + is `true`) + items: + description: External plugin registries configuration. + properties: + url: + description: Public URL of the plugin registry. + type: string + type: object + type: array + type: object + server: + description: General configuration settings related to the Che server, + the plugin and devfile registries + properties: + airGapContainerRegistryHostname: + description: Optional host name, or URL, to an alternate container + registry to pull images from. This value overrides the container + registry host name defined in all the default container images + involved in a Che deployment. This is particularly useful + to install Che in a restricted environment. + type: string + airGapContainerRegistryOrganization: + description: Optional repository name of an alternate container + registry to pull images from. This value overrides the container + registry organization defined in all the default container + images involved in a Che deployment. This is particularly + useful to install Eclipse Che in a restricted environment. + type: string + clusterRoles: + description: ClusterRoles that will be assigned to Che ServiceAccount. + Each role must have `app.kubernetes.io/part-of=che.eclipse.org` + label. Be aware that the Che Operator has to already have + all permissions in these ClusterRoles to grant them. + items: + type: string + type: array + customCheProperties: + additionalProperties: + type: string + description: Map of additional environment variables that will + be applied in the generated `che` ConfigMap to be used by + the Che server, in addition to the values already generated + from other fields of the `CheCluster` custom resource (CR). + When `customCheProperties` contains a property that would + be normally generated in `che` ConfigMap from other CR fields, + the value defined in the `customCheProperties` is used instead. + type: object + debug: + default: "false" + description: Enables the debug mode for Che server. + type: string + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + gitSelfSignedCert: + description: When enabled, the certificate from `che-git-self-signed-cert` + ConfigMap will be propagated to the Che components and provide + particular configuration for Git. Note, the `che-git-self-signed-cert` + ConfigMap must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: boolean + logLevel: + default: INFO + description: 'Log level for the Che server: `INFO` or `DEBUG`.' + type: string + proxy: + description: Proxy server settings. + properties: + credentialsSecretRef: + description: The secret name that contains `user` and `password` + for a proxy server. The secret must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: string + nonProxyHosts: + description: 'List of hosts that will be reached directly, + bypassing the proxy. Specify wild card domain use the + following form `.`, for example: - localhost - + my.host.com - 123.42.12.32 Only use when configuring + a proxy is required. Operator respects OpenShift cluster + wide proxy configuration and no additional configuration + is required, but defining `nonProxyHosts` in a custom + resource leads to merging non proxy hosts lists from the + cluster proxy configuration and ones defined in the custom + resources. See the doc https://docs.openshift.com/container-platform/4.4/networking/enable-cluster-wide-proxy.html. + See also the `proxyURL` fields.' + items: + type: string + type: array + port: + description: Port of the proxy server. + type: string + url: + description: URL (protocol+host name) of the proxy server. + This drives the appropriate changes in the `JAVA_OPTS` + and `https(s)_proxy` variables in the Che server and workspaces + containers. Only use when configuring a proxy is required. + Operator respects OpenShift cluster wide proxy configuration + and no additional configuration is required, but defining + `proxyUrl` in a custom resource leads to overrides the + cluster proxy configuration with fields `proxyUrl`, `proxyPort`, + `proxyUser` and `proxyPassword` from the custom resource. + See the doc https://docs.openshift.com/container-platform/4.4/networking/enable-cluster-wide-proxy.html. + See also the `proxyPort` and `nonProxyHosts` fields. + type: string + type: object + serverTrustStoreConfigMapName: + description: Name of the ConfigMap with public certificates + to add to Java trust store of the Che server. This is often + required when adding the OpenShift OAuth provider, which has + HTTPS endpoint signed with self-signed cert. The Che server + must be aware of its CA cert to be able to request it. This + is disabled by default. The Config Map must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: string + workspaceNamespaceName: + description: Defines Kubernetes default namespace in which user's + workspaces are created for a case when a user does not override + it. It's possible to use ``, `` and `` + placeholders, such as che-workspace-. In that case, + a new namespace will be created for each user or workspace. + type: string + workspacePodNodeSelector: + additionalProperties: + type: string + description: The node selector that limits the nodes that can + run the workspace pods. + type: object + workspacePodTolerations: + description: The pod tolerations put on the workspace pods to + limit where the workspace pods can run. + items: + description: The pod this Toleration is attached to tolerates + any taint that matches the triple using + the matching operator . + properties: + effect: + description: Effect indicates the taint effect to match. + Empty means match all taint effects. When specified, + allowed values are NoSchedule, PreferNoSchedule and + NoExecute. + type: string + key: + description: Key is the taint key that the toleration + applies to. Empty means match all taint keys. If the + key is empty, operator must be Exists; this combination + means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship + to the value. Valid operators are Exists and Equal. + Defaults to Equal. Exists is equivalent to wildcard + for value, so that a pod can tolerate all taints of + a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of + time the toleration (which must be of effect NoExecute, + otherwise this field is ignored) tolerates the taint. + By default, it is not set, which means tolerate the + taint forever (do not evict). Zero and negative values + will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration matches + to. If the operator is Exists, the value should be empty, + otherwise just a regular string. + type: string + type: object + type: array + workspaceServiceAccountClusterRole: + description: Custom cluster role bound to the user for the Che + workspaces. The role must have `app.kubernetes.io/part-of=che.eclipse.org` + label. The default roles are used when omitted or left blank. + items: + type: string + type: array + workspacesDefaultPlugins: + description: Default plug-ins applied to Devworkspaces. + items: + properties: + editor: + description: The editor id to specify default plug-ins + for. + type: string + plugins: + description: Default plug-in uris for the specified editor. + items: + type: string + type: array + type: object + type: array + type: object + storage: + description: Configuration settings related to the persistent storage + used by the Che installation. + properties: + preCreateSubPaths: + description: Instructs the Che server to start a special Pod + to pre-create a sub-path in the Persistent Volumes. Defaults + to `false`, however it will need to enable it according to + the configuration of your Kubernetes cluster. + type: boolean + pvc: + description: PVC settings. + properties: + claimSize: + description: Persistent Volume Claim size. To update the + claim size, Storage class that provisions it must support + resize. + type: string + storageClass: + description: Storage class for the Persistent Volume Claim. + When omitted or left blank, a default storage class is + used. + type: string + type: object + pvcJobsImage: + description: Overrides the container image used to create sub-paths + in the Persistent Volumes. This includes the image tag. Omit + it or leave it empty to use the default container image provided + by the Operator. See also the `preCreateSubPaths` field. + type: string + pvcStrategy: + default: common + description: Persistent volume claim strategy for the Che server. + This Can be:`common` (all workspaces PVCs in one volume), + `per-workspace` (one PVC per workspace for all declared volumes) + and `unique` (one PVC per declared volume). + type: string + type: object + type: object + status: + description: CheClusterStatus defines the observed state of Che installation + properties: + cheURL: + description: Public URL to the Che server. + type: string + cheVersion: + description: Current installed Che version. + type: string + devfileRegistryURL: + description: Public URL to the devfile registry. + type: string + helpLink: + description: A URL that points to some URL where to find help related + to the current Operator status. + type: string + message: + description: A human readable message indicating details about why + the Pod is in this condition. + type: string + phase: + description: Phase is the phase in which the Che cluster as a whole + finds itself in. + type: string + pluginRegistryURL: + description: Public URL to the plugin registry. + type: string + reason: + description: A brief CamelCase message indicating details about + why the Pod is in this state. + type: string + type: object + type: object + served: true storage: true subresources: status: {} diff --git a/bundle/next/eclipse-che-preview-openshift/manifests/webhook-service_v1_service.yaml b/bundle/next/eclipse-che-preview-openshift/manifests/webhook-service_v1_service.yaml new file mode 100644 index 0000000000..f973b97f75 --- /dev/null +++ b/bundle/next/eclipse-che-preview-openshift/manifests/webhook-service_v1_service.yaml @@ -0,0 +1,25 @@ +# +# Copyright (c) 2019-2021 Red Hat, Inc. +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Red Hat, Inc. - initial API and implementation +# + +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: null + name: webhook-service +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + app: che-operator +status: + loadBalancer: {} diff --git a/config/certmanager/certificate.yaml b/config/certmanager/certificate.yaml new file mode 100644 index 0000000000..a96210eeb9 --- /dev/null +++ b/config/certmanager/certificate.yaml @@ -0,0 +1,37 @@ +# +# Copyright (c) 2019-2022 Red Hat, Inc. +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Red Hat, Inc. - initial API and implementation +# + +# The following manifests contain a self-signed issuer CR and a certificate CR. +# More document can be found at https://docs.cert-manager.io +# WARNING: Targets CertManager v1.0. Check https://cert-manager.io/docs/installation/upgrading/ for breaking changes. +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: selfsigned-issuer + namespace: eclipse-che +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml + namespace: eclipse-che +spec: + # $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize + dnsNames: + - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc + - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local + issuerRef: + kind: Issuer + name: selfsigned-issuer + secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize diff --git a/config/certmanager/kustomization.yaml b/config/certmanager/kustomization.yaml new file mode 100644 index 0000000000..d19e8cabb6 --- /dev/null +++ b/config/certmanager/kustomization.yaml @@ -0,0 +1,17 @@ +# +# Copyright (c) 2019-2022 Red Hat, Inc. +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Red Hat, Inc. - initial API and implementation +# + +resources: +- certificate.yaml + +configurations: +- kustomizeconfig.yaml diff --git a/config/certmanager/kustomizeconfig.yaml b/config/certmanager/kustomizeconfig.yaml new file mode 100644 index 0000000000..2adb1ef3fa --- /dev/null +++ b/config/certmanager/kustomizeconfig.yaml @@ -0,0 +1,28 @@ +# +# Copyright (c) 2019-2022 Red Hat, Inc. +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Red Hat, Inc. - initial API and implementation +# + +# This configuration is for teaching kustomize how to update name ref and var substitution +nameReference: +- kind: Issuer + group: cert-manager.io + fieldSpecs: + - kind: Certificate + group: cert-manager.io + path: spec/issuerRef/name + +varReference: +- kind: Certificate + group: cert-manager.io + path: spec/commonName +- kind: Certificate + group: cert-manager.io + path: spec/dnsNames diff --git a/config/crd/bases/org_v1_che_crd.yaml b/config/crd/bases/org_v1_che_crd.yaml index d84b475c14..919a2f0d4a 100644 --- a/config/crd/bases/org_v1_che_crd.yaml +++ b/config/crd/bases/org_v1_che_crd.yaml @@ -1222,6 +1222,932 @@ spec: type: object type: object served: true + storage: false + subresources: + status: {} + - name: v2 + schema: + openAPIV3Schema: + description: The `CheCluster` custom resource allows defining and managing + a Che server installation + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource + this object represents. Servers may infer this from the endpoint the + client submits requests to. Cannot be updated. In CamelCase. More + info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Desired configuration of the Che installation. Based on + these settings, the Operator automatically creates and maintains + several ConfigMaps that will contain the appropriate environment variables + the various components of the Che installation. These generated ConfigMaps + must NOT be updated manually. + properties: + auth: + description: Configuration settings related to the Authentication + used by the Che installation. + properties: + gateway: + description: Gateway settings. + properties: + authenticationSidecarImage: + description: Gateway sidecar responsible for authentication. + See link:https://github.com/oauth2-proxy/oauth2-proxy[oauth2-proxy] + or link:https://github.com/openshift/oauth-proxy[openshift/oauth-proxy]. + type: string + authorizationSidecarImage: + description: Gateway sidecar responsible for authorization. + See link:https://github.com/brancz/kube-rbac-proxy[kube-rbac-proxy] + or link:https://github.com/openshift/kube-rbac-proxy[openshift/kube-rbac-proxy] + type: string + configLabels: + additionalProperties: + type: string + description: The labels that need to be present in the ConfigMaps + representing the gateway configuration. + type: object + configSidecarImage: + description: The image used for the gateway sidecar that + provides configuration to the gateway. Omit it or leave + it empty to use the default container image provided by + the Operator. + type: string + image: + description: The image used for the gateway . Omit it or + leave it empty to use the default container image provided + by the Operator. + type: string + ingress: + description: The Che server ingress custom settings. + properties: + annotations: + additionalProperties: + type: string + description: 'Unstructured key value map stored with + a resource that may be set by external tools to store + and retrieve arbitrary metadata. When not specified, + this defaults to: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/proxy-read-timeout: "3600", nginx.ingress.kubernetes.io/proxy-connect-timeout: + "3600", nginx.ingress.kubernetes.io/ssl-redirect: "true"' + type: object + domain: + description: 'Global ingress domain for a Kubernetes + cluster. This MUST be explicitly specified: there + are no defaults.' + type: string + host: + description: Public host name of the installed Che server. + When value is omitted, the value it will be automatically + set by the Operator. + type: string + labels: + additionalProperties: + type: string + description: Comma separated list of labels that can + be used to organize and categorize objects by scoping + and selecting. + type: object + tlsSecretRef: + description: Name of a secret that will be used to setup + ingress TLS termination when. When the field is empty + string, the default cluster certificate will be used. + The secret must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: string + type: object + route: + description: The Che server route custom settings. + properties: + annotations: + additionalProperties: + type: string + description: Unstructured key value map stored with + a resource that may be set by external tools to store + and retrieve arbitrary metadata. + type: object + domain: + description: 'Operator uses the domain to generate a + hostname for a route. In a conjunction with labels + it creates a route, which is served by a non-default + Ingress controller. The generated host name will follow + this pattern: `-.`.' + type: string + host: + description: Public host name of the installed Che server. + When value is omitted, the value it will be automatically + set by the Operator. + type: string + labels: + additionalProperties: + type: string + description: Comma separated list of labels that can + be used to organize and categorize objects by scoping + and selecting. + type: object + tlsSecretRef: + description: Name of a secret containing certificates + to secure route. The secret must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: string + type: object + type: object + identityProviderURL: + description: Public URL of the Identity Provider server. + type: string + oAuthClientName: + description: Name of the OpenShift `OAuthClient` resource used + to setup identity federation on the OpenShift side. + type: string + oAuthSecret: + description: Name of the secret set in the OpenShift `OAuthClient` + resource used to setup identity federation on the OpenShift + side. + type: string + type: object + dashboard: + description: Configuration settings related to the Dashboard sed + by the Che installation. + properties: + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + warning: + description: Warning message that will be displayed on the User + Dashboard + type: string + type: object + database: + description: Configuration settings related to the database used + by the Che installation. + properties: + credentialsSecretRef: + default: che-postgres-secret + description: The secret that contains PostgreSQL `user` and + `password` that the Che server uses to connect to the DB. + The secret must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: string + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + externalDb: + description: 'Instructs the Operator on whether to deploy a + dedicated database. By default, a dedicated PostgreSQL database + is deployed as part of the Che installation. When `externalDb` + is `true`, no dedicated database will be deployed by the Operator + and you will need to provide connection details to the external + DB you are about to use. See also all the fields starting + with: `chePostgres`.' + type: boolean + postgresDb: + default: dbche + description: PostgreSQL database name that the Che server uses + to connect to the DB. + type: string + postgresHostName: + default: postgres + description: PostgreSQL Database host name that the Che server + uses to connect to. Override this value ONLY when using an + external database. See field `externalDb`. + type: string + postgresPort: + default: "5432" + description: PostgreSQL Database port that the Che server uses + to connect to. Defaults to 5432. Override this value ONLY + when using an external database. See field `externalDb`. In + the default case it will be automatically set by the Operator. + type: string + postgresVersion: + description: 'Indicates a PostgreSQL version image to use. Allowed + values are: `9.6` and `13.3`. Migrate your PostgreSQL database + to switch from one version to another.' + type: string + pvc: + description: PVC settings for PostgreSQL database. + properties: + claimSize: + description: Persistent Volume Claim size. To update the + claim size, Storage class that provisions it must support + resize. + type: string + storageClass: + description: Storage class for the Persistent Volume Claim. + When omitted or left blank, a default storage class is + used. + type: string + type: object + type: object + devWorkspace: + description: DevWorkspace operator configuration + properties: + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + runningLimit: + description: Maximum number of the running workspaces per user. + type: string + type: object + devfileRegistry: + description: Configuration settings related to the Devfile registry + used by the Che installation. + properties: + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + disableInternalRegistry: + description: Disables internal Devfile registry. + type: boolean + externalDevfileRegistries: + description: External devfile registries, that serves sample, + ready-to-use devfiles. Configure this in addition to a dedicated + devfile registry (when `disableInternalRegistry` is `false`) + or instead of it (when `disableInternalRegistry` is `true`) + items: + description: External devfile registries configuration. + properties: + url: + description: Public URL of the devfile registry that serves + sample ready-to-use devfiles. + type: string + type: object + type: array + type: object + imagePuller: + description: Kubernetes Image Puller configuration + properties: + enable: + description: Install and configure the Community Supported Kubernetes + Image Puller Operator. When set to `true` and no spec is provided, + it will create a default KubernetesImagePuller object to be + managed by the Operator. When set to `false`, the KubernetesImagePuller + object will be deleted, and the Operator will be uninstalled, + regardless of whether a spec is provided. If the `spec.images` + field is empty, a set of recommended workspace-related images + will be automatically detected and pre-pulled after installation. + Note that while this Operator and its behavior is community-supported, + its payload may be commercially-supported for pulling commercially-supported + images. + type: boolean + spec: + description: A KubernetesImagePullerSpec to configure the image + puller in the CheCluster + properties: + affinity: + type: string + cachingCPULimit: + type: string + cachingCPURequest: + type: string + cachingIntervalHours: + type: string + cachingMemoryLimit: + type: string + cachingMemoryRequest: + type: string + configMapName: + type: string + daemonsetName: + type: string + deploymentName: + type: string + imagePullSecrets: + type: string + imagePullerImage: + type: string + images: + type: string + nodeSelector: + type: string + type: object + required: + - enable + type: object + metrics: + description: Configuration settings related to the metrics collection + used by the Che installation. + properties: + enable: + description: Enables `metrics` the Che server endpoint. Default + to `true`. + type: boolean + type: object + pluginRegistry: + description: Configuration settings related to the Plugin registry + used by the Che installation. + properties: + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + disableInternalRegistry: + description: Disables internal Plugin registry. + type: boolean + externalPluginRegistries: + description: External plugin registries. Configure this in addition + to a dedicated plugin registry (when `disableInternalRegistry` + is `false`) or instead of it (when `disableInternalRegistry` + is `true`) + items: + description: External plugin registries configuration. + properties: + url: + description: Public URL of the plugin registry. + type: string + type: object + type: array + type: object + server: + description: General configuration settings related to the Che server, + the plugin and devfile registries + properties: + airGapContainerRegistryHostname: + description: Optional host name, or URL, to an alternate container + registry to pull images from. This value overrides the container + registry host name defined in all the default container images + involved in a Che deployment. This is particularly useful + to install Che in a restricted environment. + type: string + airGapContainerRegistryOrganization: + description: Optional repository name of an alternate container + registry to pull images from. This value overrides the container + registry organization defined in all the default container + images involved in a Che deployment. This is particularly + useful to install Eclipse Che in a restricted environment. + type: string + clusterRoles: + description: ClusterRoles that will be assigned to Che ServiceAccount. + Each role must have `app.kubernetes.io/part-of=che.eclipse.org` + label. Be aware that the Che Operator has to already have + all permissions in these ClusterRoles to grant them. + items: + type: string + type: array + customCheProperties: + additionalProperties: + type: string + description: Map of additional environment variables that will + be applied in the generated `che` ConfigMap to be used by + the Che server, in addition to the values already generated + from other fields of the `CheCluster` custom resource (CR). + When `customCheProperties` contains a property that would + be normally generated in `che` ConfigMap from other CR fields, + the value defined in the `customCheProperties` is used instead. + type: object + debug: + default: "false" + description: Enables the debug mode for Che server. + type: string + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + gitSelfSignedCert: + description: When enabled, the certificate from `che-git-self-signed-cert` + ConfigMap will be propagated to the Che components and provide + particular configuration for Git. Note, the `che-git-self-signed-cert` + ConfigMap must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: boolean + logLevel: + default: INFO + description: 'Log level for the Che server: `INFO` or `DEBUG`.' + type: string + proxy: + description: Proxy server settings. + properties: + credentialsSecretRef: + description: The secret name that contains `user` and `password` + for a proxy server. The secret must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: string + nonProxyHosts: + description: 'List of hosts that will be reached directly, + bypassing the proxy. Specify wild card domain use the + following form `.`, for example: - localhost - + my.host.com - 123.42.12.32 Only use when configuring + a proxy is required. Operator respects OpenShift cluster + wide proxy configuration and no additional configuration + is required, but defining `nonProxyHosts` in a custom + resource leads to merging non proxy hosts lists from the + cluster proxy configuration and ones defined in the custom + resources. See the doc https://docs.openshift.com/container-platform/4.4/networking/enable-cluster-wide-proxy.html. + See also the `proxyURL` fields.' + items: + type: string + type: array + port: + description: Port of the proxy server. + type: string + url: + description: URL (protocol+host name) of the proxy server. + This drives the appropriate changes in the `JAVA_OPTS` + and `https(s)_proxy` variables in the Che server and workspaces + containers. Only use when configuring a proxy is required. + Operator respects OpenShift cluster wide proxy configuration + and no additional configuration is required, but defining + `proxyUrl` in a custom resource leads to overrides the + cluster proxy configuration with fields `proxyUrl`, `proxyPort`, + `proxyUser` and `proxyPassword` from the custom resource. + See the doc https://docs.openshift.com/container-platform/4.4/networking/enable-cluster-wide-proxy.html. + See also the `proxyPort` and `nonProxyHosts` fields. + type: string + type: object + serverTrustStoreConfigMapName: + description: Name of the ConfigMap with public certificates + to add to Java trust store of the Che server. This is often + required when adding the OpenShift OAuth provider, which has + HTTPS endpoint signed with self-signed cert. The Che server + must be aware of its CA cert to be able to request it. This + is disabled by default. The Config Map must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: string + workspaceNamespaceName: + description: Defines Kubernetes default namespace in which user's + workspaces are created for a case when a user does not override + it. It's possible to use ``, `` and `` + placeholders, such as che-workspace-. In that case, + a new namespace will be created for each user or workspace. + type: string + workspacePodNodeSelector: + additionalProperties: + type: string + description: The node selector that limits the nodes that can + run the workspace pods. + type: object + workspacePodTolerations: + description: The pod tolerations put on the workspace pods to + limit where the workspace pods can run. + items: + description: The pod this Toleration is attached to tolerates + any taint that matches the triple using + the matching operator . + properties: + effect: + description: Effect indicates the taint effect to match. + Empty means match all taint effects. When specified, + allowed values are NoSchedule, PreferNoSchedule and + NoExecute. + type: string + key: + description: Key is the taint key that the toleration + applies to. Empty means match all taint keys. If the + key is empty, operator must be Exists; this combination + means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship + to the value. Valid operators are Exists and Equal. + Defaults to Equal. Exists is equivalent to wildcard + for value, so that a pod can tolerate all taints of + a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of + time the toleration (which must be of effect NoExecute, + otherwise this field is ignored) tolerates the taint. + By default, it is not set, which means tolerate the + taint forever (do not evict). Zero and negative values + will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration matches + to. If the operator is Exists, the value should be empty, + otherwise just a regular string. + type: string + type: object + type: array + workspaceServiceAccountClusterRole: + description: Custom cluster role bound to the user for the Che + workspaces. The role must have `app.kubernetes.io/part-of=che.eclipse.org` + label. The default roles are used when omitted or left blank. + items: + type: string + type: array + workspacesDefaultPlugins: + description: Default plug-ins applied to Devworkspaces. + items: + properties: + editor: + description: The editor id to specify default plug-ins + for. + type: string + plugins: + description: Default plug-in uris for the specified editor. + items: + type: string + type: array + type: object + type: array + type: object + storage: + description: Configuration settings related to the persistent storage + used by the Che installation. + properties: + preCreateSubPaths: + description: Instructs the Che server to start a special Pod + to pre-create a sub-path in the Persistent Volumes. Defaults + to `false`, however it will need to enable it according to + the configuration of your Kubernetes cluster. + type: boolean + pvc: + description: PVC settings. + properties: + claimSize: + description: Persistent Volume Claim size. To update the + claim size, Storage class that provisions it must support + resize. + type: string + storageClass: + description: Storage class for the Persistent Volume Claim. + When omitted or left blank, a default storage class is + used. + type: string + type: object + pvcJobsImage: + description: Overrides the container image used to create sub-paths + in the Persistent Volumes. This includes the image tag. Omit + it or leave it empty to use the default container image provided + by the Operator. See also the `preCreateSubPaths` field. + type: string + pvcStrategy: + default: common + description: Persistent volume claim strategy for the Che server. + This Can be:`common` (all workspaces PVCs in one volume), + `per-workspace` (one PVC per workspace for all declared volumes) + and `unique` (one PVC per declared volume). + type: string + type: object + type: object + status: + description: CheClusterStatus defines the observed state of Che installation + properties: + cheURL: + description: Public URL to the Che server. + type: string + cheVersion: + description: Current installed Che version. + type: string + devfileRegistryURL: + description: Public URL to the devfile registry. + type: string + helpLink: + description: A URL that points to some URL where to find help related + to the current Operator status. + type: string + message: + description: A human readable message indicating details about why + the Pod is in this condition. + type: string + phase: + description: Phase is the phase in which the Che cluster as a whole + finds itself in. + type: string + pluginRegistryURL: + description: Public URL to the plugin registry. + type: string + reason: + description: A brief CamelCase message indicating details about + why the Pod is in this state. + type: string + type: object + type: object + served: true storage: true subresources: status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 7b9757af34..df72a93d12 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -21,12 +21,12 @@ resources: patchesStrategicMerge: # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. # patches here are for enabling the conversion webhook for each CRD -#- patches/webhook_in_checlusters.yaml +- patches/webhook_in_checlusters.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. # patches here are for enabling the CA injection for each CRD -#- patches/cainjection_in_checlusters.yaml +- patches/cainjection_in_checlusters.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # [LABELS] extra labels patches diff --git a/config/crd/patches/webhook_in_checlusters.yaml b/config/crd/patches/webhook_in_checlusters.yaml index 990b1da441..d94f45f431 100644 --- a/config/crd/patches/webhook_in_checlusters.yaml +++ b/config/crd/patches/webhook_in_checlusters.yaml @@ -19,8 +19,9 @@ spec: conversion: strategy: Webhook webhook: + conversionReviewVersions: ["v1", "v2"] clientConfig: service: - namespace: system + namespace: eclipse-che name: webhook-service path: /convert diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml index b333f2cba5..f4fc8e6570 100644 --- a/config/default/kustomization.yaml +++ b/config/default/kustomization.yaml @@ -30,9 +30,9 @@ bases: - ../manager # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in # crd/kustomization.yaml -#- ../webhook +- ../webhook # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. -#- ../certmanager +- ../certmanager # [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. #- ../prometheus @@ -49,7 +49,7 @@ patchesStrategicMerge: # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in # crd/kustomization.yaml -#- manager_webhook_patch.yaml +- manager_webhook_patch.yaml # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. # Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. @@ -59,29 +59,29 @@ patchesStrategicMerge: # the following config is for teaching kustomize how to do var substitution vars: # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. -#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR -# objref: -# kind: Certificate -# group: cert-manager.io -# version: v1 -# name: serving-cert # this name should match the one in certificate.yaml -# fieldref: -# fieldpath: metadata.namespace -#- name: CERTIFICATE_NAME -# objref: -# kind: Certificate -# group: cert-manager.io -# version: v1 -# name: serving-cert # this name should match the one in certificate.yaml -#- name: SERVICE_NAMESPACE # namespace of the service -# objref: -# kind: Service -# version: v1 -# name: webhook-service -# fieldref: -# fieldpath: metadata.namespace -#- name: SERVICE_NAME -# objref: -# kind: Service -# version: v1 -# name: webhook-service +- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR + objref: + kind: Certificate + group: cert-manager.io + version: v1 + name: serving-cert # this name should match the one in certificate.yaml + fieldref: + fieldpath: metadata.namespace +- name: CERTIFICATE_NAME + objref: + kind: Certificate + group: cert-manager.io + version: v1 + name: serving-cert # this name should match the one in certificate.yaml +- name: SERVICE_NAMESPACE # namespace of the service + objref: + kind: Service + version: v1 + name: webhook-service + fieldref: + fieldpath: metadata.namespace +- name: SERVICE_NAME + objref: + kind: Service + version: v1 + name: webhook-service diff --git a/config/default/manager_config_patch.yaml b/config/default/manager_config_patch.yaml index b68f8fb409..7534a33377 100644 --- a/config/default/manager_config_patch.yaml +++ b/config/default/manager_config_patch.yaml @@ -14,7 +14,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: che-operator - namespace: system + namespace: eclipse-che spec: template: spec: diff --git a/config/default/manager_webhook_patch.yaml b/config/default/manager_webhook_patch.yaml new file mode 100644 index 0000000000..84f29bb89a --- /dev/null +++ b/config/default/manager_webhook_patch.yaml @@ -0,0 +1,35 @@ +# +# Copyright (c) 2019-2021 Red Hat, Inc. +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Red Hat, Inc. - initial API and implementation +# + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: che-operator + namespace: eclipse-che +spec: + template: + spec: + containers: + - name: che-operator + ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: webhook-server-cert diff --git a/config/default/webhookcainjection_patch.yaml b/config/default/webhookcainjection_patch.yaml new file mode 100644 index 0000000000..05226b8c6d --- /dev/null +++ b/config/default/webhookcainjection_patch.yaml @@ -0,0 +1,27 @@ +# +# Copyright (c) 2019-2021 Red Hat, Inc. +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Red Hat, Inc. - initial API and implementation +# + +# This patch add annotation to admission webhook config and +# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize. +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: mutating-webhook-configuration + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: validating-webhook-configuration + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) diff --git a/config/manifests/bases/che-operator.clusterserviceversion.yaml b/config/manifests/bases/che-operator.clusterserviceversion.yaml index de93c6bccd..1c0d51639e 100644 --- a/config/manifests/bases/che-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/che-operator.clusterserviceversion.yaml @@ -33,6 +33,127 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: + - description: The `CheCluster` custom resource allows defining and managing a + Che server installation + displayName: Eclipse Che instance Specification + kind: CheCluster + name: checlusters.org.eclipse.che + resources: + - kind: ClusterRole + name: "" + version: v1 + - kind: ClusterRoleBinding + name: "" + version: v1 + - kind: ConfigMap + name: "" + version: v1 + - kind: Deployment + name: "" + version: apps/v1 + - kind: Ingress + name: "" + version: v1 + - kind: Role + name: "" + version: v1 + - kind: RoleBinding + name: "" + version: v1 + - kind: Route + name: "" + version: v1 + - kind: Secret + name: "" + version: v1 + - kind: Service + name: "" + version: v1 + specDescriptors: + - description: Configuration settings related to the Authentication used by + the Che installation. + displayName: Authentication + path: auth + - description: Configuration settings related to the Dashboard sed by the Che + installation. + displayName: Devfile registry + path: dashboard + - description: Configuration settings related to the database used by the Che + installation. + displayName: Database + path: database + - description: DevWorkspace operator configuration + displayName: Dev Workspace operator + path: devWorkspace + - description: Configuration settings related to the Devfile registry used by + the Che installation. + displayName: Devfile registry + path: devfileRegistry + - description: Kubernetes Image Puller configuration + displayName: Kubernetes Image Puller + path: imagePuller + - description: Configuration settings related to the metrics collection used + by the Che installation. + displayName: Metrics + path: metrics + - description: Configuration settings related to the Plugin registry used by + the Che installation. + displayName: Plugin registry + path: pluginRegistry + - description: General configuration settings related to the Che server, the + plugin and devfile registries + displayName: Che server + path: server + - description: Configuration settings related to the persistent storage used + by the Che installation. + displayName: Persistent storage + path: storage + statusDescriptors: + - description: Public URL to the Che server. + displayName: Eclipse Che URL + path: cheURL + x-descriptors: + - urn:alm:descriptor:org.w3:link + - description: Current installed Che version. + displayName: 'displayName: Eclipse Che version' + path: cheVersion + x-descriptors: + - urn:alm:descriptor:org.w3:link + - description: Public URL to the devfile registry. + displayName: Devfile registry URL + path: devfileRegistryURL + x-descriptors: + - urn:alm:descriptor:org.w3:link + - description: A URL that points to some URL where to find help related to the + current Operator status. + displayName: Help link + path: helpLink + x-descriptors: + - urn:alm:descriptor:org.w3:link + - description: A human readable message indicating details about why the Pod + is in this condition. + displayName: Message + path: message + x-descriptors: + - urn:alm:descriptor:text + - description: Phase is the phase in which the Che cluster as a whole finds + itself in. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:text + - description: Public URL to the plugin registry. + displayName: Plugin registry URL + path: pluginRegistryURL + x-descriptors: + - urn:alm:descriptor:org.w3:link + - description: A brief CamelCase message indicating details about why the Pod + is in this state. + displayName: Reason + path: reason + x-descriptors: + - urn:alm:descriptor:text + version: v2 - description: The `CheCluster` custom resource allows defining and managing a Che server installation displayName: Eclipse Che instance Specification diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index 11ff951ae3..51e5264f19 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -17,4 +17,5 @@ resources: # - org_v2alpha1_checluster.yaml # Uncomment to enable a devworkspace sample # - devworkspace_flattened_theia-nodejs.yaml +# - org_v2_checluster.yaml #+kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/samples/org_v2alpha1_checluster.yaml b/config/samples/org_v2_checluster.yaml similarity index 86% rename from config/samples/org_v2alpha1_checluster.yaml rename to config/samples/org_v2_checluster.yaml index 4952c9a4ff..ab0897c786 100644 --- a/config/samples/org_v2alpha1_checluster.yaml +++ b/config/samples/org_v2_checluster.yaml @@ -10,9 +10,10 @@ # Red Hat, Inc. - initial API and implementation # -apiVersion: org.eclipse.che/v2alpha1 +apiVersion: org.eclipse.che/v2 kind: CheCluster metadata: name: eclipse-che spec: - # Add fields here + server: {} + database: {} diff --git a/config/webhook/kustomization.yaml b/config/webhook/kustomization.yaml new file mode 100644 index 0000000000..0fb3d60169 --- /dev/null +++ b/config/webhook/kustomization.yaml @@ -0,0 +1,18 @@ +# +# Copyright (c) 2019-2021 Red Hat, Inc. +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Red Hat, Inc. - initial API and implementation +# + +resources: +# - manifests.yaml +- service.yaml + +configurations: +- kustomizeconfig.yaml diff --git a/config/webhook/kustomizeconfig.yaml b/config/webhook/kustomizeconfig.yaml new file mode 100644 index 0000000000..7a1d750bcb --- /dev/null +++ b/config/webhook/kustomizeconfig.yaml @@ -0,0 +1,37 @@ +# +# Copyright (c) 2019-2021 Red Hat, Inc. +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Red Hat, Inc. - initial API and implementation +# + +# the following config is for teaching kustomize where to look at when substituting vars. +# It requires kustomize v2.1.0 or newer to work properly. +nameReference: +- kind: Service + version: v1 + fieldSpecs: + - kind: MutatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/name + - kind: ValidatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/name + +namespace: +- kind: MutatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/namespace + create: true +- kind: ValidatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/namespace + create: true + +varReference: +- path: metadata/annotations diff --git a/config/webhook/service.yaml b/config/webhook/service.yaml new file mode 100644 index 0000000000..5a801c8570 --- /dev/null +++ b/config/webhook/service.yaml @@ -0,0 +1,23 @@ +# +# Copyright (c) 2019-2022 Red Hat, Inc. +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Red Hat, Inc. - initial API and implementation +# + +apiVersion: v1 +kind: Service +metadata: + name: webhook-service + namespace: eclipse-che +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + app: che-operator diff --git a/helmcharts/next/crds/org_v1_che_crd.yaml b/helmcharts/next/crds/org_v1_che_crd.yaml index d84b475c14..919a2f0d4a 100644 --- a/helmcharts/next/crds/org_v1_che_crd.yaml +++ b/helmcharts/next/crds/org_v1_che_crd.yaml @@ -1222,6 +1222,932 @@ spec: type: object type: object served: true + storage: false + subresources: + status: {} + - name: v2 + schema: + openAPIV3Schema: + description: The `CheCluster` custom resource allows defining and managing + a Che server installation + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource + this object represents. Servers may infer this from the endpoint the + client submits requests to. Cannot be updated. In CamelCase. More + info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Desired configuration of the Che installation. Based on + these settings, the Operator automatically creates and maintains + several ConfigMaps that will contain the appropriate environment variables + the various components of the Che installation. These generated ConfigMaps + must NOT be updated manually. + properties: + auth: + description: Configuration settings related to the Authentication + used by the Che installation. + properties: + gateway: + description: Gateway settings. + properties: + authenticationSidecarImage: + description: Gateway sidecar responsible for authentication. + See link:https://github.com/oauth2-proxy/oauth2-proxy[oauth2-proxy] + or link:https://github.com/openshift/oauth-proxy[openshift/oauth-proxy]. + type: string + authorizationSidecarImage: + description: Gateway sidecar responsible for authorization. + See link:https://github.com/brancz/kube-rbac-proxy[kube-rbac-proxy] + or link:https://github.com/openshift/kube-rbac-proxy[openshift/kube-rbac-proxy] + type: string + configLabels: + additionalProperties: + type: string + description: The labels that need to be present in the ConfigMaps + representing the gateway configuration. + type: object + configSidecarImage: + description: The image used for the gateway sidecar that + provides configuration to the gateway. Omit it or leave + it empty to use the default container image provided by + the Operator. + type: string + image: + description: The image used for the gateway . Omit it or + leave it empty to use the default container image provided + by the Operator. + type: string + ingress: + description: The Che server ingress custom settings. + properties: + annotations: + additionalProperties: + type: string + description: 'Unstructured key value map stored with + a resource that may be set by external tools to store + and retrieve arbitrary metadata. When not specified, + this defaults to: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/proxy-read-timeout: "3600", nginx.ingress.kubernetes.io/proxy-connect-timeout: + "3600", nginx.ingress.kubernetes.io/ssl-redirect: "true"' + type: object + domain: + description: 'Global ingress domain for a Kubernetes + cluster. This MUST be explicitly specified: there + are no defaults.' + type: string + host: + description: Public host name of the installed Che server. + When value is omitted, the value it will be automatically + set by the Operator. + type: string + labels: + additionalProperties: + type: string + description: Comma separated list of labels that can + be used to organize and categorize objects by scoping + and selecting. + type: object + tlsSecretRef: + description: Name of a secret that will be used to setup + ingress TLS termination when. When the field is empty + string, the default cluster certificate will be used. + The secret must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: string + type: object + route: + description: The Che server route custom settings. + properties: + annotations: + additionalProperties: + type: string + description: Unstructured key value map stored with + a resource that may be set by external tools to store + and retrieve arbitrary metadata. + type: object + domain: + description: 'Operator uses the domain to generate a + hostname for a route. In a conjunction with labels + it creates a route, which is served by a non-default + Ingress controller. The generated host name will follow + this pattern: `-.`.' + type: string + host: + description: Public host name of the installed Che server. + When value is omitted, the value it will be automatically + set by the Operator. + type: string + labels: + additionalProperties: + type: string + description: Comma separated list of labels that can + be used to organize and categorize objects by scoping + and selecting. + type: object + tlsSecretRef: + description: Name of a secret containing certificates + to secure route. The secret must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: string + type: object + type: object + identityProviderURL: + description: Public URL of the Identity Provider server. + type: string + oAuthClientName: + description: Name of the OpenShift `OAuthClient` resource used + to setup identity federation on the OpenShift side. + type: string + oAuthSecret: + description: Name of the secret set in the OpenShift `OAuthClient` + resource used to setup identity federation on the OpenShift + side. + type: string + type: object + dashboard: + description: Configuration settings related to the Dashboard sed + by the Che installation. + properties: + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + warning: + description: Warning message that will be displayed on the User + Dashboard + type: string + type: object + database: + description: Configuration settings related to the database used + by the Che installation. + properties: + credentialsSecretRef: + default: che-postgres-secret + description: The secret that contains PostgreSQL `user` and + `password` that the Che server uses to connect to the DB. + The secret must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: string + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + externalDb: + description: 'Instructs the Operator on whether to deploy a + dedicated database. By default, a dedicated PostgreSQL database + is deployed as part of the Che installation. When `externalDb` + is `true`, no dedicated database will be deployed by the Operator + and you will need to provide connection details to the external + DB you are about to use. See also all the fields starting + with: `chePostgres`.' + type: boolean + postgresDb: + default: dbche + description: PostgreSQL database name that the Che server uses + to connect to the DB. + type: string + postgresHostName: + default: postgres + description: PostgreSQL Database host name that the Che server + uses to connect to. Override this value ONLY when using an + external database. See field `externalDb`. + type: string + postgresPort: + default: "5432" + description: PostgreSQL Database port that the Che server uses + to connect to. Defaults to 5432. Override this value ONLY + when using an external database. See field `externalDb`. In + the default case it will be automatically set by the Operator. + type: string + postgresVersion: + description: 'Indicates a PostgreSQL version image to use. Allowed + values are: `9.6` and `13.3`. Migrate your PostgreSQL database + to switch from one version to another.' + type: string + pvc: + description: PVC settings for PostgreSQL database. + properties: + claimSize: + description: Persistent Volume Claim size. To update the + claim size, Storage class that provisions it must support + resize. + type: string + storageClass: + description: Storage class for the Persistent Volume Claim. + When omitted or left blank, a default storage class is + used. + type: string + type: object + type: object + devWorkspace: + description: DevWorkspace operator configuration + properties: + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + runningLimit: + description: Maximum number of the running workspaces per user. + type: string + type: object + devfileRegistry: + description: Configuration settings related to the Devfile registry + used by the Che installation. + properties: + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + disableInternalRegistry: + description: Disables internal Devfile registry. + type: boolean + externalDevfileRegistries: + description: External devfile registries, that serves sample, + ready-to-use devfiles. Configure this in addition to a dedicated + devfile registry (when `disableInternalRegistry` is `false`) + or instead of it (when `disableInternalRegistry` is `true`) + items: + description: External devfile registries configuration. + properties: + url: + description: Public URL of the devfile registry that serves + sample ready-to-use devfiles. + type: string + type: object + type: array + type: object + imagePuller: + description: Kubernetes Image Puller configuration + properties: + enable: + description: Install and configure the Community Supported Kubernetes + Image Puller Operator. When set to `true` and no spec is provided, + it will create a default KubernetesImagePuller object to be + managed by the Operator. When set to `false`, the KubernetesImagePuller + object will be deleted, and the Operator will be uninstalled, + regardless of whether a spec is provided. If the `spec.images` + field is empty, a set of recommended workspace-related images + will be automatically detected and pre-pulled after installation. + Note that while this Operator and its behavior is community-supported, + its payload may be commercially-supported for pulling commercially-supported + images. + type: boolean + spec: + description: A KubernetesImagePullerSpec to configure the image + puller in the CheCluster + properties: + affinity: + type: string + cachingCPULimit: + type: string + cachingCPURequest: + type: string + cachingIntervalHours: + type: string + cachingMemoryLimit: + type: string + cachingMemoryRequest: + type: string + configMapName: + type: string + daemonsetName: + type: string + deploymentName: + type: string + imagePullSecrets: + type: string + imagePullerImage: + type: string + images: + type: string + nodeSelector: + type: string + type: object + required: + - enable + type: object + metrics: + description: Configuration settings related to the metrics collection + used by the Che installation. + properties: + enable: + description: Enables `metrics` the Che server endpoint. Default + to `true`. + type: boolean + type: object + pluginRegistry: + description: Configuration settings related to the Plugin registry + used by the Che installation. + properties: + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + disableInternalRegistry: + description: Disables internal Plugin registry. + type: boolean + externalPluginRegistries: + description: External plugin registries. Configure this in addition + to a dedicated plugin registry (when `disableInternalRegistry` + is `false`) or instead of it (when `disableInternalRegistry` + is `true`) + items: + description: External plugin registries configuration. + properties: + url: + description: Public URL of the plugin registry. + type: string + type: object + type: array + type: object + server: + description: General configuration settings related to the Che server, + the plugin and devfile registries + properties: + airGapContainerRegistryHostname: + description: Optional host name, or URL, to an alternate container + registry to pull images from. This value overrides the container + registry host name defined in all the default container images + involved in a Che deployment. This is particularly useful + to install Che in a restricted environment. + type: string + airGapContainerRegistryOrganization: + description: Optional repository name of an alternate container + registry to pull images from. This value overrides the container + registry organization defined in all the default container + images involved in a Che deployment. This is particularly + useful to install Eclipse Che in a restricted environment. + type: string + clusterRoles: + description: ClusterRoles that will be assigned to Che ServiceAccount. + Each role must have `app.kubernetes.io/part-of=che.eclipse.org` + label. Be aware that the Che Operator has to already have + all permissions in these ClusterRoles to grant them. + items: + type: string + type: array + customCheProperties: + additionalProperties: + type: string + description: Map of additional environment variables that will + be applied in the generated `che` ConfigMap to be used by + the Che server, in addition to the values already generated + from other fields of the `CheCluster` custom resource (CR). + When `customCheProperties` contains a property that would + be normally generated in `che` ConfigMap from other CR fields, + the value defined in the `customCheProperties` is used instead. + type: object + debug: + default: "false" + description: Enables the debug mode for Che server. + type: string + deployment: + description: Deployment override options. + properties: + container: + description: A single application container. + properties: + image: + description: Container image. Omit it or leave it empty + to use the default container image provided by the + Operator. + type: string + imagePullPolicy: + description: Image pull policy. Default value is `Always` + for `nightly`, `next` or `latest` images, and `IfNotPresent` + in other cases. + type: string + resources: + description: Compute Resources required by this container. + properties: + limits: + description: Limits describes the maximum amount + of compute resources allowed. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + request: + description: Requests describes the minimum amount + of compute resources required. + properties: + cpu: + description: CPU, in cores. (500m = .5 cores) + type: string + memory: + description: Memory, in bytes. (500Gi = 500GiB + = 500 * 1024 * 1024 * 1024) + type: string + type: object + type: object + type: object + securityContext: + description: Security options the pod should run with. + properties: + fsGroup: + description: A special supplemental group that applies + to all containers in a pod. Default value is `1724`. + type: string + runAsUser: + description: The UID to run the entrypoint of the container + process. Default value is `1724`. + type: string + type: object + type: object + gitSelfSignedCert: + description: When enabled, the certificate from `che-git-self-signed-cert` + ConfigMap will be propagated to the Che components and provide + particular configuration for Git. Note, the `che-git-self-signed-cert` + ConfigMap must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: boolean + logLevel: + default: INFO + description: 'Log level for the Che server: `INFO` or `DEBUG`.' + type: string + proxy: + description: Proxy server settings. + properties: + credentialsSecretRef: + description: The secret name that contains `user` and `password` + for a proxy server. The secret must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: string + nonProxyHosts: + description: 'List of hosts that will be reached directly, + bypassing the proxy. Specify wild card domain use the + following form `.`, for example: - localhost - + my.host.com - 123.42.12.32 Only use when configuring + a proxy is required. Operator respects OpenShift cluster + wide proxy configuration and no additional configuration + is required, but defining `nonProxyHosts` in a custom + resource leads to merging non proxy hosts lists from the + cluster proxy configuration and ones defined in the custom + resources. See the doc https://docs.openshift.com/container-platform/4.4/networking/enable-cluster-wide-proxy.html. + See also the `proxyURL` fields.' + items: + type: string + type: array + port: + description: Port of the proxy server. + type: string + url: + description: URL (protocol+host name) of the proxy server. + This drives the appropriate changes in the `JAVA_OPTS` + and `https(s)_proxy` variables in the Che server and workspaces + containers. Only use when configuring a proxy is required. + Operator respects OpenShift cluster wide proxy configuration + and no additional configuration is required, but defining + `proxyUrl` in a custom resource leads to overrides the + cluster proxy configuration with fields `proxyUrl`, `proxyPort`, + `proxyUser` and `proxyPassword` from the custom resource. + See the doc https://docs.openshift.com/container-platform/4.4/networking/enable-cluster-wide-proxy.html. + See also the `proxyPort` and `nonProxyHosts` fields. + type: string + type: object + serverTrustStoreConfigMapName: + description: Name of the ConfigMap with public certificates + to add to Java trust store of the Che server. This is often + required when adding the OpenShift OAuth provider, which has + HTTPS endpoint signed with self-signed cert. The Che server + must be aware of its CA cert to be able to request it. This + is disabled by default. The Config Map must have `app.kubernetes.io/part-of=che.eclipse.org` + label. + type: string + workspaceNamespaceName: + description: Defines Kubernetes default namespace in which user's + workspaces are created for a case when a user does not override + it. It's possible to use ``, `` and `` + placeholders, such as che-workspace-. In that case, + a new namespace will be created for each user or workspace. + type: string + workspacePodNodeSelector: + additionalProperties: + type: string + description: The node selector that limits the nodes that can + run the workspace pods. + type: object + workspacePodTolerations: + description: The pod tolerations put on the workspace pods to + limit where the workspace pods can run. + items: + description: The pod this Toleration is attached to tolerates + any taint that matches the triple using + the matching operator . + properties: + effect: + description: Effect indicates the taint effect to match. + Empty means match all taint effects. When specified, + allowed values are NoSchedule, PreferNoSchedule and + NoExecute. + type: string + key: + description: Key is the taint key that the toleration + applies to. Empty means match all taint keys. If the + key is empty, operator must be Exists; this combination + means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship + to the value. Valid operators are Exists and Equal. + Defaults to Equal. Exists is equivalent to wildcard + for value, so that a pod can tolerate all taints of + a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of + time the toleration (which must be of effect NoExecute, + otherwise this field is ignored) tolerates the taint. + By default, it is not set, which means tolerate the + taint forever (do not evict). Zero and negative values + will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration matches + to. If the operator is Exists, the value should be empty, + otherwise just a regular string. + type: string + type: object + type: array + workspaceServiceAccountClusterRole: + description: Custom cluster role bound to the user for the Che + workspaces. The role must have `app.kubernetes.io/part-of=che.eclipse.org` + label. The default roles are used when omitted or left blank. + items: + type: string + type: array + workspacesDefaultPlugins: + description: Default plug-ins applied to Devworkspaces. + items: + properties: + editor: + description: The editor id to specify default plug-ins + for. + type: string + plugins: + description: Default plug-in uris for the specified editor. + items: + type: string + type: array + type: object + type: array + type: object + storage: + description: Configuration settings related to the persistent storage + used by the Che installation. + properties: + preCreateSubPaths: + description: Instructs the Che server to start a special Pod + to pre-create a sub-path in the Persistent Volumes. Defaults + to `false`, however it will need to enable it according to + the configuration of your Kubernetes cluster. + type: boolean + pvc: + description: PVC settings. + properties: + claimSize: + description: Persistent Volume Claim size. To update the + claim size, Storage class that provisions it must support + resize. + type: string + storageClass: + description: Storage class for the Persistent Volume Claim. + When omitted or left blank, a default storage class is + used. + type: string + type: object + pvcJobsImage: + description: Overrides the container image used to create sub-paths + in the Persistent Volumes. This includes the image tag. Omit + it or leave it empty to use the default container image provided + by the Operator. See also the `preCreateSubPaths` field. + type: string + pvcStrategy: + default: common + description: Persistent volume claim strategy for the Che server. + This Can be:`common` (all workspaces PVCs in one volume), + `per-workspace` (one PVC per workspace for all declared volumes) + and `unique` (one PVC per declared volume). + type: string + type: object + type: object + status: + description: CheClusterStatus defines the observed state of Che installation + properties: + cheURL: + description: Public URL to the Che server. + type: string + cheVersion: + description: Current installed Che version. + type: string + devfileRegistryURL: + description: Public URL to the devfile registry. + type: string + helpLink: + description: A URL that points to some URL where to find help related + to the current Operator status. + type: string + message: + description: A human readable message indicating details about why + the Pod is in this condition. + type: string + phase: + description: Phase is the phase in which the Che cluster as a whole + finds itself in. + type: string + pluginRegistryURL: + description: Public URL to the plugin registry. + type: string + reason: + description: A brief CamelCase message indicating details about + why the Pod is in this state. + type: string + type: object + type: object + served: true storage: true subresources: status: {} diff --git a/main.go b/main.go index a49981de8e..cee9ded79a 100644 --- a/main.go +++ b/main.go @@ -22,6 +22,7 @@ import ( dwoApi "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1" dwr "github.com/devfile/devworkspace-operator/controllers/controller/devworkspacerouting" + "github.com/eclipse-che/che-operator/controllers/devworkspace" "github.com/eclipse-che/che-operator/controllers/devworkspace/solver" @@ -76,6 +77,7 @@ import ( networkingv1 "k8s.io/api/networking/v1" rbacv1 "k8s.io/api/rbac/v1" + orgv2 "github.com/eclipse-che/che-operator/api/v2" orgv2alpha1 "github.com/eclipse-che/che-operator/api/v2alpha1" //+kubebuilder:scaffold:imports ) @@ -127,6 +129,7 @@ func init() { // utilruntime.Must(orgv2alpha1.AddToScheme(scheme)) utilruntime.Must(orgv2alpha1.AddToScheme(scheme)) + utilruntime.Must(orgv2.AddToScheme(scheme)) //+kubebuilder:scaffold:scheme utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(admissionregistrationv1.AddToScheme(scheme)) @@ -316,6 +319,11 @@ func main() { }) } + if err = (&orgv2.CheCluster{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", "webhook", "CheCluster") + os.Exit(1) + } + // +kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { setupLog.Error(err, "unable to set up health check") diff --git a/pkg/infrastructure/infrastructure.go b/pkg/infrastructure/infrastructure.go new file mode 100644 index 0000000000..5d80480330 --- /dev/null +++ b/pkg/infrastructure/infrastructure.go @@ -0,0 +1,80 @@ +// +// Copyright (c) 2019-2021 Red Hat, Inc. +// This program and the accompanying materials are made +// available under the terms of the Eclipse Public License 2.0 +// which is available at https://www.eclipse.org/legal/epl-2.0/ +// +// SPDX-License-Identifier: EPL-2.0 +// +// Contributors: +// Red Hat, Inc. - initial API and implementation +// +package infrastructure + +import ( + "os" + "strconv" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/discovery" + "sigs.k8s.io/controller-runtime/pkg/client/config" +) + +var ( + IsOpenShift, IsOpenShift4, _ = DetectOpenShift() +) + +func DetectOpenShift() (isOpenshift bool, isOpenshift4 bool, anError error) { + tests := IsTestMode() + if tests { + openshiftVersionEnv := os.Getenv("OPENSHIFT_VERSION") + openshiftVersion, err := strconv.ParseInt(openshiftVersionEnv, 0, 64) + if err == nil && openshiftVersion == 4 { + return true, true, nil + } + return true, false, nil + } + + apiGroups, err := getApiList() + if err != nil { + return false, false, err + } + for _, apiGroup := range apiGroups { + if apiGroup.Name == "route.openshift.io" { + isOpenshift = true + } + if apiGroup.Name == "config.openshift.io" { + isOpenshift4 = true + } + } + + return isOpenshift, isOpenshift4, nil +} + +func getDiscoveryClient() (*discovery.DiscoveryClient, error) { + kubeconfig, err := config.GetConfig() + if err != nil { + return nil, err + } + return discovery.NewDiscoveryClientForConfig(kubeconfig) +} + +func getApiList() ([]metav1.APIGroup, error) { + discoveryClient, err := getDiscoveryClient() + if err != nil { + return nil, err + } + apiList, err := discoveryClient.ServerGroups() + if err != nil { + return nil, err + } + return apiList.Groups, nil +} + +func IsTestMode() (isTesting bool) { + testMode := os.Getenv("MOCK_API") + if len(testMode) == 0 { + return false + } + return true +} diff --git a/pkg/k8sclient/k8s_client.go b/pkg/k8sclient/k8s_client.go new file mode 100644 index 0000000000..b3f6eac974 --- /dev/null +++ b/pkg/k8sclient/k8s_client.go @@ -0,0 +1,26 @@ +// +// Copyright (c) 2019-2021 Red Hat, Inc. +// This program and the accompanying materials are made +// available under the terms of the Eclipse Public License 2.0 +// which is available at https://www.eclipse.org/legal/epl-2.0/ +// +// SPDX-License-Identifier: EPL-2.0 +// +// Contributors: +// Red Hat, Inc. - initial API and implementation +// +package k8sclient + +import ( + "k8s.io/client-go/kubernetes" + "sigs.k8s.io/controller-runtime/pkg/client/config" +) + +func GetK8ClientSet() (*kubernetes.Clientset, error) { + cfg, err := config.GetConfig() + if err != nil { + return nil, err + } + + return kubernetes.NewForConfig(cfg) +} diff --git a/pkg/util/util.go b/pkg/util/util.go index fd64f7a63b..72224aa91d 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -44,7 +44,6 @@ import ( ) var ( - k8sclient = GetK8Client() IsOpenShift, IsOpenShift4, _ = DetectOpenShift() )