diff --git a/deploy/crds/org_v1_che_crd-v1beta1.yaml b/deploy/crds/org_v1_che_crd-v1beta1.yaml index 846f643dd..033eb267c 100644 --- a/deploy/crds/org_v1_che_crd-v1beta1.yaml +++ b/deploy/crds/org_v1_che_crd-v1beta1.yaml @@ -358,16 +358,17 @@ spec: description: Kubernetes Image Puller configuration properties: enable: - description: "Install and configure the Community Supported Kubernetes + 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. - Note that while this - the Operator and its behavior is community-supported, its payload - may be commercially-supported for pulling commercially-supported - images." + 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 @@ -390,6 +391,9 @@ spec: deploymentName: type: string images: + description: If empty, a set of recommended workspace-related + images will be automatically detected and pre-pulled after + installation. type: string nodeSelector: type: string diff --git a/deploy/crds/org_v1_che_crd.yaml b/deploy/crds/org_v1_che_crd.yaml index fa350cf29..dd216febd 100644 --- a/deploy/crds/org_v1_che_crd.yaml +++ b/deploy/crds/org_v1_che_crd.yaml @@ -364,16 +364,17 @@ spec: description: Kubernetes Image Puller configuration properties: enable: - description: "Install and configure the Community Supported Kubernetes + 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. - Note that while - this the Operator and its behavior is community-supported, its - payload may be commercially-supported for pulling commercially-supported - images." + 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 @@ -396,6 +397,9 @@ spec: deploymentName: type: string images: + description: If empty, a set of recommended workspace-related + images will be automatically detected and pre-pulled after + installation. type: string nodeSelector: type: string diff --git a/deploy/olm-catalog/nightly/eclipse-che-preview-kubernetes/manifests/che-operator.clusterserviceversion.yaml b/deploy/olm-catalog/nightly/eclipse-che-preview-kubernetes/manifests/che-operator.clusterserviceversion.yaml index 579fafff9..fc7f48122 100644 --- a/deploy/olm-catalog/nightly/eclipse-che-preview-kubernetes/manifests/che-operator.clusterserviceversion.yaml +++ b/deploy/olm-catalog/nightly/eclipse-che-preview-kubernetes/manifests/che-operator.clusterserviceversion.yaml @@ -86,13 +86,13 @@ metadata: categories: Developer Tools certified: "false" containerImage: quay.io/eclipse/che-operator:next - createdAt: "2021-07-07T09:30:36Z" + createdAt: "2021-07-12T13:17:30Z" description: A Kube-native development solution that delivers portable and collaborative developer workspaces. operatorframework.io/suggested-namespace: eclipse-che repository: https://github.com/eclipse-che/che-operator support: Eclipse Foundation - name: eclipse-che-preview-kubernetes.v7.33.0-250.nightly + name: eclipse-che-preview-kubernetes.v7.33.0-252.nightly namespace: placeholder spec: apiservicedefinitions: {} @@ -1241,4 +1241,4 @@ spec: maturity: stable provider: name: Eclipse Foundation - version: 7.33.0-250.nightly + version: 7.33.0-252.nightly diff --git a/deploy/olm-catalog/nightly/eclipse-che-preview-kubernetes/manifests/org_v1_che_crd.yaml b/deploy/olm-catalog/nightly/eclipse-che-preview-kubernetes/manifests/org_v1_che_crd.yaml index fa350cf29..dd216febd 100644 --- a/deploy/olm-catalog/nightly/eclipse-che-preview-kubernetes/manifests/org_v1_che_crd.yaml +++ b/deploy/olm-catalog/nightly/eclipse-che-preview-kubernetes/manifests/org_v1_che_crd.yaml @@ -364,16 +364,17 @@ spec: description: Kubernetes Image Puller configuration properties: enable: - description: "Install and configure the Community Supported Kubernetes + 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. - Note that while - this the Operator and its behavior is community-supported, its - payload may be commercially-supported for pulling commercially-supported - images." + 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 @@ -396,6 +397,9 @@ spec: deploymentName: type: string images: + description: If empty, a set of recommended workspace-related + images will be automatically detected and pre-pulled after + installation. type: string nodeSelector: type: string diff --git a/deploy/olm-catalog/nightly/eclipse-che-preview-openshift/manifests/che-operator.clusterserviceversion.yaml b/deploy/olm-catalog/nightly/eclipse-che-preview-openshift/manifests/che-operator.clusterserviceversion.yaml index fc2342371..b6479fd30 100644 --- a/deploy/olm-catalog/nightly/eclipse-che-preview-openshift/manifests/che-operator.clusterserviceversion.yaml +++ b/deploy/olm-catalog/nightly/eclipse-che-preview-openshift/manifests/che-operator.clusterserviceversion.yaml @@ -77,13 +77,13 @@ metadata: categories: Developer Tools, OpenShift Optional certified: "false" containerImage: quay.io/eclipse/che-operator:next - createdAt: "2021-07-07T09:30:48Z" + createdAt: "2021-07-12T13:17:47Z" description: A Kube-native development solution that delivers portable and collaborative developer workspaces in OpenShift. operatorframework.io/suggested-namespace: eclipse-che repository: https://github.com/eclipse-che/che-operator support: Eclipse Foundation - name: eclipse-che-preview-openshift.v7.33.0-250.nightly + name: eclipse-che-preview-openshift.v7.33.0-252.nightly namespace: placeholder spec: apiservicedefinitions: {} @@ -1318,4 +1318,4 @@ spec: maturity: stable provider: name: Eclipse Foundation - version: 7.33.0-250.nightly + version: 7.33.0-252.nightly diff --git a/deploy/olm-catalog/nightly/eclipse-che-preview-openshift/manifests/org_v1_che_crd.yaml b/deploy/olm-catalog/nightly/eclipse-che-preview-openshift/manifests/org_v1_che_crd.yaml index 594128667..d89703e09 100644 --- a/deploy/olm-catalog/nightly/eclipse-che-preview-openshift/manifests/org_v1_che_crd.yaml +++ b/deploy/olm-catalog/nightly/eclipse-che-preview-openshift/manifests/org_v1_che_crd.yaml @@ -370,15 +370,17 @@ spec: 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. Note that while this the Operator and its behavior\ - \ is community-supported, its payload may be commercially-supported\ - \ for pulling commercially-supported images." + 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 @@ -401,6 +403,9 @@ spec: deploymentName: type: string images: + description: If empty, a set of recommended workspace-related + images will be automatically detected and pre-pulled after + installation. type: string nodeSelector: type: string diff --git a/pkg/apis/org/v1/che_types.go b/pkg/apis/org/v1/che_types.go index a287168d6..3e745295f 100644 --- a/pkg/apis/org/v1/che_types.go +++ b/pkg/apis/org/v1/che_types.go @@ -592,8 +592,9 @@ type CheClusterSpecImagePuller struct { // 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. - // - // Note that while this the Operator and its behavior is community-supported, its payload may be commercially-supported + // 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 @@ -748,3 +749,7 @@ func (c *CheCluster) IsAirGapMode() bool { 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/pkg/controller/che/che_controller_test.go b/pkg/controller/che/che_controller_test.go index 60a757514..ca5aebdb7 100644 --- a/pkg/controller/che/che_controller_test.go +++ b/pkg/controller/che/che_controller_test.go @@ -148,6 +148,7 @@ var ( Spec: chev1alpha1.KubernetesImagePullerSpec{ DeploymentName: "kubernetes-image-puller", ConfigMapName: "k8s-image-puller", + Images: "che-workspace-plugin-broker-metadata=quay.io/eclipse/che-plugin-metadata-broker:v3.4.0;che-workspace-plugin-broker-artifacts=quay.io/eclipse/che-plugin-artifacts-broker:v3.4.0;", }, } clusterServiceVersion = &operatorsv1alpha1.ClusterServiceVersion{ @@ -731,6 +732,45 @@ func TestImagePullerConfiguration(t *testing.T) { }, expectedImagePuller: defaultImagePuller, }, + { + name: "image puller enabled, user images set, subscription exists, should create a KubernetesImagePuller with user images", + initCR: InitCheCRWithImagePullerEnabledAndImagesSet(), + initObjects: []runtime.Object{ + packageManifest, + operatorGroup, + subscription, + }, + expectedImagePuller: &chev1alpha1.KubernetesImagePuller{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "che.eclipse.org/v1alpha1", + Kind: "KubernetesImagePuller", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "eclipse-che-image-puller", + Namespace: namespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": name, + "app": "che", + "component": "kubernetes-image-puller", + }, + ResourceVersion: "1", + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "org.eclipse.che/v1", + Kind: "CheCluster", + Controller: &valueTrue, + BlockOwnerDeletion: &valueTrue, + Name: "eclipse-che", + }, + }, + }, + Spec: chev1alpha1.KubernetesImagePullerSpec{ + DeploymentName: "kubernetes-image-puller", + ConfigMapName: "k8s-image-puller", + Images: "image=image_url", + }, + }, + }, { name: "image puller enabled, KubernetesImagePuller created and spec in CheCluster is different, should update the KubernetesImagePuller", initCR: InitCheCRWithImagePullerEnabledAndNewValuesSet(), @@ -1541,6 +1581,31 @@ func InitCheCRWithImagePullerEnabledAndDefaultValuesSet() *orgv1.CheCluster { } } +func InitCheCRWithImagePullerEnabledAndImagesSet() *orgv1.CheCluster { + return &orgv1.CheCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Finalizers: []string{ + "kubernetesimagepullers.finalizers.che.eclipse.org", + }, + }, + Spec: orgv1.CheClusterSpec{ + ImagePuller: orgv1.CheClusterSpecImagePuller{ + Enable: true, + Spec: chev1alpha1.KubernetesImagePullerSpec{ + DeploymentName: "kubernetes-image-puller", + ConfigMapName: "k8s-image-puller", + Images: "image=image_url", + }, + }, + Auth: orgv1.CheClusterSpecAuth{ + OpenShiftoAuth: util.NewBoolPointer(false), + }, + }, + } +} + func InitCheCRWithImagePullerEnabledAndNewValuesSet() *orgv1.CheCluster { return &orgv1.CheCluster{ ObjectMeta: metav1.ObjectMeta{ diff --git a/pkg/deploy/kubernetes_image_puller.go b/pkg/deploy/kubernetes_image_puller.go index 251697d2a..95948dd04 100644 --- a/pkg/deploy/kubernetes_image_puller.go +++ b/pkg/deploy/kubernetes_image_puller.go @@ -13,6 +13,8 @@ package deploy import ( "context" + goerror "errors" + "strings" "time" chev1alpha1 "github.com/che-incubator/kubernetes-image-puller-operator/pkg/apis/che/v1alpha1" @@ -22,9 +24,11 @@ import ( operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" packagesv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" "github.com/sirupsen/logrus" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/validation" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" ) @@ -127,6 +131,13 @@ func ReconcileImagePuller(ctx *DeployContext) (reconcile.Result, error) { return reconcile.Result{Requeue: true}, nil } + if ctx.CheCluster.IsImagePullerImagesEmpty() { + if err = AddDefaultImages(ctx); err != nil { + logrus.Error(err) + return reconcile.Result{}, err + } + } + logrus.Infof("Creating KubernetesImagePuller for CheCluster %v", ctx.CheCluster.Name) createdImagePuller, err := CreateKubernetesImagePuller(ctx) if err != nil { @@ -386,6 +397,83 @@ func UpdateImagePullerSpecIfEmpty(ctx *DeployContext) (orgv1.CheClusterSpecImage return ctx.CheCluster.Spec.ImagePuller, nil } +func AddDefaultImages(ctx *DeployContext) error { + defaultImageVars := GetDefaultImagesEnvVars() + if len(defaultImageVars) == 0 { + return nil + } + + defaultImages := "" + for _, envVar := range defaultImageVars { + defaultImages += envVar.Name + "=" + envVar.Value + ";" + } + ctx.CheCluster.Spec.ImagePuller.Spec.Images = defaultImages + return UpdateCheCRSpec(ctx, "Kubernetes Image Puller default images", defaultImages) +} + +func GetDefaultImagesEnvVars() []v1.EnvVar { + imagePatterns := [...]string{ + "^RELATED_IMAGE_.*_plugin_java8$", + "^RELATED_IMAGE_.*_plugin_java11$", + "^RELATED_IMAGE_.*_plugin_kubernetes$", + "^RELATED_IMAGE_.*_plugin_openshift$", + "^RELATED_IMAGE_.*_plugin_broker.*", + "^RELATED_IMAGE_.*_theia.*", + "^RELATED_IMAGE_.*_stacks_cpp$", + "^RELATED_IMAGE_.*_stacks_dotnet$", + "^RELATED_IMAGE_.*_stacks_golang$", + "^RELATED_IMAGE_.*_stacks_php$", + "^RELATED_IMAGE_.*_cpp_.*_devfile_registry_image.*", + "^RELATED_IMAGE_.*_dotnet_.*_devfile_registry_image.*", + "^RELATED_IMAGE_.*_golang_.*_devfile_registry_image.*", + "^RELATED_IMAGE_.*_php_.*_devfile_registry_image.*", + "^RELATED_IMAGE_.*_java.*_maven_devfile_registry_image.*", + } + + var err error + imageVars := []v1.EnvVar{} + for _, pattern := range imagePatterns { + matches := util.GetEnvByRegExp(pattern) + for _, match := range matches { + match.Name = match.Name[len("RELATED_IMAGE_"):] + match.Name, err = ConvertToRFC1123(match.Name) + if err != nil { + logrus.Errorf(err.Error()) + continue + } + imageVars = append(imageVars, match) + } + } + return imageVars +} + +// Convert input string to RFC 1123 format ([a-z0-9]([-a-z0-9]*[a-z0-9])?) max 63 characters, if possible +func ConvertToRFC1123(str string) (string, error) { + result := strings.ToLower(str) + if len(str) > validation.DNS1123LabelMaxLength { + result = result[:validation.DNS1123LabelMaxLength] + } + + // Remove illegal trailing characters + i := len(result) - 1 + for i >= 0 && !IsRFC1123Char(result[i]) { + i -= 1 + } + result = result[:i+1] + + result = strings.ReplaceAll(result, "_", "-") + + if errs := validation.IsDNS1123Label(result); len(errs) > 0 { + return "", goerror.New("Cannot convert the following string to RFC 1123 format: " + str) + } + return result, nil +} + +func IsRFC1123Char(ch byte) bool { + errs := validation.IsDNS1123Label(string(ch)) + return len(errs) == 0 +} + func CreateKubernetesImagePuller(ctx *DeployContext) (bool, error) { imagePuller := GetExpectedKubernetesImagePuller(ctx) err := ctx.ClusterAPI.Client.Create(context.TODO(), imagePuller, &client.CreateOptions{}) diff --git a/vendor/github.com/che-incubator/kubernetes-image-puller-operator/pkg/apis/che/v1alpha1/kubernetesimagepuller_types.go b/vendor/github.com/che-incubator/kubernetes-image-puller-operator/pkg/apis/che/v1alpha1/kubernetesimagepuller_types.go index ddeb95724..b5cd4c251 100644 --- a/vendor/github.com/che-incubator/kubernetes-image-puller-operator/pkg/apis/che/v1alpha1/kubernetesimagepuller_types.go +++ b/vendor/github.com/che-incubator/kubernetes-image-puller-operator/pkg/apis/che/v1alpha1/kubernetesimagepuller_types.go @@ -8,12 +8,14 @@ import ( // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. +// +k8s:openapi-gen=true // KubernetesImagePullerSpec defines the desired state of KubernetesImagePuller type KubernetesImagePullerSpec struct { + // If empty, a set of recommended workspace-related images will be automatically detected and pre-pulled after installation. + Images string `json:"images,omitempty"` ConfigMapName string `json:"configMapName,omitempty"` DaemonsetName string `json:"daemonsetName,omitempty"` DeploymentName string `json:"deploymentName,omitempty"` - Images string `json:"images,omitempty"` CachingIntervalHours string `json:"cachingIntervalHours,omitempty"` CachingMemoryRequest string `json:"cachingMemoryRequest,omitempty"` CachingMemoryLimit string `json:"cachingMemoryLimit,omitempty"`