From 02ce7749f0fe6da90e0b89f1239c2710aecef309 Mon Sep 17 00:00:00 2001 From: Angel Misevski Date: Wed, 31 May 2023 02:58:50 -0400 Subject: [PATCH] Add fields for configuring project clone container to CheCluster CRD (#1687) * Update devworkspace-operator dependency version to v0.21.0 Update devworkspace-operator dependency to v0.21.0 and update vendor dir Signed-off-by: Angel Misevski * Add project clone container config field to CheCluster CR Add field .spec.devEnvironments.projectCloneContainer to allow configuring image, env, resources, and pull policy for the project clone container. This change reuses the existing Container struct for storing this config, which means that * The name field is ignored (it appears to be a discriminator for the Deployment struct's containers[] field * Defaults are handled differently: * Default imagePullPolicy is the general pull policy for DWO, with default value "Always" (instead of depending on tag as documented) * Resource requirements set to "0" are interpreted as "do not set this field" Signed-off-by: Angel Misevski * Add reconcile step that syncs CheCluster project clone to DevWorkspace Sync the field CheCluster.devEnvironments.projectCloneConfig to the DevWorkspaceOperatorConfig owned by the operator. Update tests to cover new functionality. Signed-off-by: Angel Misevski --------- Signed-off-by: Angel Misevski --- DEPENDENCIES.md | 2 +- api/v2/checluster_types.go | 5 +- api/v2/zz_generated.deepcopy.go | 5 + .../che-operator.clusterserviceversion.yaml | 4 +- .../org.eclipse.che_checlusters.yaml | 192 +++++++++ .../bases/org.eclipse.che_checlusters.yaml | 188 +++++++++ deploy/deployment/kubernetes/combined.yaml | 188 +++++++++ ....eclipse.che.CustomResourceDefinition.yaml | 188 +++++++++ deploy/deployment/openshift/combined.yaml | 188 +++++++++ ....eclipse.che.CustomResourceDefinition.yaml | 188 +++++++++ go.mod | 2 +- go.sum | 4 +- ....eclipse.che.CustomResourceDefinition.yaml | 188 +++++++++ .../dev_workspace_config.go | 60 ++- .../dev_workspace_config_test.go | 382 +++++++++++++++--- .../devworkspaceoperatorconfig_types.go | 155 +++---- .../v1alpha1/zz_generated.deepcopy.go | 32 ++ .../pkg/config/defaults.go | 12 + .../devworkspace-operator/pkg/config/sync.go | 64 +++ .../pkg/constants/constants.go | 6 - .../pkg/provision/sync/sync.go | 6 +- vendor/modules.txt | 2 +- 22 files changed, 1914 insertions(+), 147 deletions(-) diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index 8cf13d04a..21cf7feab 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -448,7 +448,7 @@ | [golang.org/x/mobile@d3739f865fa66d07c1f506505c18aac71a8ead6e](https://cs.opensource.google/go) | BSD-3-Clause | N/A | | [github.com/devfile/api/v2@0d163445376d4d28898f3fbac4f2ff62863b944b](https://github.com/devfile/api.git) | Apache-2.0 | [clearlydefined](https://clearlydefined.io/definitions/git/github/devfile/api/0d163445376d4d28898f3fbac4f2ff62863b944b) | | [github.com/che-incubator/kubernetes-image-puller-operator@0128446f5af78587c0427a35d693bbb8d24036bc](https://github.com/che-incubator/kubernetes-image-puller-operator.git) | EPL-2.0 | todo | -| [github.com/devfile/devworkspace-operator@v0.20.0](https://github.com/devfile/devworkspace-operator.git) | Apache-2.0 | [clearlydefined](https://clearlydefined.io/definitions/git/github/devfile/devworkspace-operator/ef761d812e029d094d2e9936d11ce4a3f6b8efd3) | +| [github.com/devfile/devworkspace-operator@v0.21.0](https://github.com/devfile/devworkspace-operator.git) | Apache-2.0 | [clearlydefined](https://clearlydefined.io/definitions/git/github/devfile/devworkspace-operator/21edf4373322c228ed54a5d4747b0451435a8f08) | | [github.com/gophercloud/gophercloud@v0.1.0](https://github.com/gophercloud/gophercloud) | Apache-2.0 | [clearlydefined](https://clearlydefined.io/definitions/go/golang/github.com%2Fgophercloud/gophercloud/v0.1.0) | | [gopkg.in/imdario/mergo.v0@v0.3.7](https://github.com/imdario/mergo/) | BSD-3-Clause | [clearlydefined](https://clearlydefined.io/definitions/go/golang/github.com%2Fimdario/mergo/v0.3.7) | | [github.com/mikefarah/yq/v2@v2.4.1](https://github.com/mikefarah/yq) | MIT | [clearlydefined](https://clearlydefined.io/definitions/git/github/mikefarah/yq/b8b2c9de6189471c0cdbd459b5b0b49a57844bd4) | diff --git a/api/v2/checluster_types.go b/api/v2/checluster_types.go index 1b2ed3481..c0d0b327d 100644 --- a/api/v2/checluster_types.go +++ b/api/v2/checluster_types.go @@ -78,6 +78,9 @@ type CheClusterDevEnvironments struct { // GatewayContainer configuration. // +optional GatewayContainer *Container `json:"gatewayContainer,omitempty"` + // Project clone container configuration. + // +optional + ProjectCloneContainer *Container `json:"projectCloneContainer,omitempty"` // Workspaces persistent storage. // +optional // +kubebuilder:default:={pvcStrategy: per-user} @@ -779,7 +782,7 @@ type CheCluster struct { Status CheClusterStatus `json:"status,omitempty"` } -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true // The CheClusterList contains a list of CheClusters. type CheClusterList struct { metav1.TypeMeta `json:",inline"` diff --git a/api/v2/zz_generated.deepcopy.go b/api/v2/zz_generated.deepcopy.go index 7185cd812..0fae43f27 100644 --- a/api/v2/zz_generated.deepcopy.go +++ b/api/v2/zz_generated.deepcopy.go @@ -152,6 +152,11 @@ func (in *CheClusterDevEnvironments) DeepCopyInto(out *CheClusterDevEnvironments *out = new(Container) (*in).DeepCopyInto(*out) } + if in.ProjectCloneContainer != nil { + in, out := &in.ProjectCloneContainer, &out.ProjectCloneContainer + *out = new(Container) + (*in).DeepCopyInto(*out) + } in.Storage.DeepCopyInto(&out.Storage) if in.DefaultPlugins != nil { in, out := &in.DefaultPlugins, &out.DefaultPlugins diff --git a/bundle/next/eclipse-che/manifests/che-operator.clusterserviceversion.yaml b/bundle/next/eclipse-che/manifests/che-operator.clusterserviceversion.yaml index 79e71b130..e65d98e48 100644 --- a/bundle/next/eclipse-che/manifests/che-operator.clusterserviceversion.yaml +++ b/bundle/next/eclipse-che/manifests/che-operator.clusterserviceversion.yaml @@ -77,7 +77,7 @@ metadata: operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/eclipse-che/che-operator support: Eclipse Foundation - name: eclipse-che.v7.68.0-794.next + name: eclipse-che.v7.68.0-795.next namespace: placeholder spec: apiservicedefinitions: {} @@ -1235,7 +1235,7 @@ spec: minKubeVersion: 1.19.0 provider: name: Eclipse Foundation - version: 7.68.0-794.next + version: 7.68.0-795.next webhookdefinitions: - admissionReviewVersions: - v1 diff --git a/bundle/next/eclipse-che/manifests/org.eclipse.che_checlusters.yaml b/bundle/next/eclipse-che/manifests/org.eclipse.che_checlusters.yaml index 0835e385b..c55638846 100644 --- a/bundle/next/eclipse-che/manifests/org.eclipse.che_checlusters.yaml +++ b/bundle/next/eclipse-che/manifests/org.eclipse.che_checlusters.yaml @@ -7001,6 +7001,198 @@ spec: description: Pod scheduler for the workspace pods. If not specified, the pod scheduler is set to the default scheduler on the cluster. type: string + projectCloneContainer: + description: Project clone container configuration. + properties: + env: + description: List of environment variables to set in the + container. + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are + expanded using the previously defined environment + variables in the container and any service environment + variables. If a variable cannot be resolved, the + reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)". Escaped + references will never be expanded, regardless of + whether the variable exists or not. Defaults to + "".' + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for + volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the + pod's namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + 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. + enum: + - Always + - IfNotPresent + - Never + type: string + name: + description: Container name. + type: string + resources: + description: Compute resources required by this container. + properties: + limits: + description: Describes the maximum amount of compute + resources allowed. + properties: + cpu: + anyOf: + - type: integer + - type: string + description: CPU, in cores. (500m = .5 cores) If + the value is not specified, then the default value + is set depending on the component. If value is + `0`, then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: Memory, in bytes. (500Gi = 500GiB = + 500 * 1024 * 1024 * 1024) If the value is not + specified, then the default value is set depending + on the component. If value is `0`, then no value + is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + request: + description: Describes the minimum amount of compute + resources required. + properties: + cpu: + anyOf: + - type: integer + - type: string + description: CPU, in cores. (500m = .5 cores) If + the value is not specified, then the default value + is set depending on the component. If value is + `0`, then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: Memory, in bytes. (500Gi = 500GiB = + 500 * 1024 * 1024 * 1024) If the value is not + specified, then the default value is set depending + on the component. If value is `0`, then no value + is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + type: object secondsOfInactivityBeforeIdling: default: 1800 description: Idle timeout for workspaces in seconds. This timeout diff --git a/config/crd/bases/org.eclipse.che_checlusters.yaml b/config/crd/bases/org.eclipse.che_checlusters.yaml index f45841865..01e995cde 100644 --- a/config/crd/bases/org.eclipse.che_checlusters.yaml +++ b/config/crd/bases/org.eclipse.che_checlusters.yaml @@ -6804,6 +6804,194 @@ spec: description: Pod scheduler for the workspace pods. If not specified, the pod scheduler is set to the default scheduler on the cluster. type: string + projectCloneContainer: + description: Project clone container configuration. + properties: + env: + description: List of environment variables to set in the container. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables + in the container and any service environment variables. + If a variable cannot be resolved, the reference in + the input string will be unchanged. Double $$ are + reduced to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + 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. + enum: + - Always + - IfNotPresent + - Never + type: string + name: + description: Container name. + type: string + resources: + description: Compute resources required by this container. + properties: + limits: + description: Describes the maximum amount of compute resources + allowed. + properties: + cpu: + anyOf: + - type: integer + - type: string + description: CPU, in cores. (500m = .5 cores) If the + value is not specified, then the default value is + set depending on the component. If value is `0`, + then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: Memory, in bytes. (500Gi = 500GiB = 500 + * 1024 * 1024 * 1024) If the value is not specified, + then the default value is set depending on the component. + If value is `0`, then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + request: + description: Describes the minimum amount of compute resources + required. + properties: + cpu: + anyOf: + - type: integer + - type: string + description: CPU, in cores. (500m = .5 cores) If the + value is not specified, then the default value is + set depending on the component. If value is `0`, + then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: Memory, in bytes. (500Gi = 500GiB = 500 + * 1024 * 1024 * 1024) If the value is not specified, + then the default value is set depending on the component. + If value is `0`, then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + type: object secondsOfInactivityBeforeIdling: default: 1800 description: Idle timeout for workspaces in seconds. This timeout diff --git a/deploy/deployment/kubernetes/combined.yaml b/deploy/deployment/kubernetes/combined.yaml index 0cf453c08..3e451e8fb 100644 --- a/deploy/deployment/kubernetes/combined.yaml +++ b/deploy/deployment/kubernetes/combined.yaml @@ -6823,6 +6823,194 @@ spec: description: Pod scheduler for the workspace pods. If not specified, the pod scheduler is set to the default scheduler on the cluster. type: string + projectCloneContainer: + description: Project clone container configuration. + properties: + env: + description: List of environment variables to set in the container. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables + in the container and any service environment variables. + If a variable cannot be resolved, the reference in + the input string will be unchanged. Double $$ are + reduced to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + 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. + enum: + - Always + - IfNotPresent + - Never + type: string + name: + description: Container name. + type: string + resources: + description: Compute resources required by this container. + properties: + limits: + description: Describes the maximum amount of compute resources + allowed. + properties: + cpu: + anyOf: + - type: integer + - type: string + description: CPU, in cores. (500m = .5 cores) If the + value is not specified, then the default value is + set depending on the component. If value is `0`, + then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: Memory, in bytes. (500Gi = 500GiB = 500 + * 1024 * 1024 * 1024) If the value is not specified, + then the default value is set depending on the component. + If value is `0`, then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + request: + description: Describes the minimum amount of compute resources + required. + properties: + cpu: + anyOf: + - type: integer + - type: string + description: CPU, in cores. (500m = .5 cores) If the + value is not specified, then the default value is + set depending on the component. If value is `0`, + then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: Memory, in bytes. (500Gi = 500GiB = 500 + * 1024 * 1024 * 1024) If the value is not specified, + then the default value is set depending on the component. + If value is `0`, then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + type: object secondsOfInactivityBeforeIdling: default: 1800 description: Idle timeout for workspaces in seconds. This timeout diff --git a/deploy/deployment/kubernetes/objects/checlusters.org.eclipse.che.CustomResourceDefinition.yaml b/deploy/deployment/kubernetes/objects/checlusters.org.eclipse.che.CustomResourceDefinition.yaml index 99d628bc4..749fdb29d 100644 --- a/deploy/deployment/kubernetes/objects/checlusters.org.eclipse.che.CustomResourceDefinition.yaml +++ b/deploy/deployment/kubernetes/objects/checlusters.org.eclipse.che.CustomResourceDefinition.yaml @@ -6818,6 +6818,194 @@ spec: description: Pod scheduler for the workspace pods. If not specified, the pod scheduler is set to the default scheduler on the cluster. type: string + projectCloneContainer: + description: Project clone container configuration. + properties: + env: + description: List of environment variables to set in the container. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables + in the container and any service environment variables. + If a variable cannot be resolved, the reference in + the input string will be unchanged. Double $$ are + reduced to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + 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. + enum: + - Always + - IfNotPresent + - Never + type: string + name: + description: Container name. + type: string + resources: + description: Compute resources required by this container. + properties: + limits: + description: Describes the maximum amount of compute resources + allowed. + properties: + cpu: + anyOf: + - type: integer + - type: string + description: CPU, in cores. (500m = .5 cores) If the + value is not specified, then the default value is + set depending on the component. If value is `0`, + then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: Memory, in bytes. (500Gi = 500GiB = 500 + * 1024 * 1024 * 1024) If the value is not specified, + then the default value is set depending on the component. + If value is `0`, then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + request: + description: Describes the minimum amount of compute resources + required. + properties: + cpu: + anyOf: + - type: integer + - type: string + description: CPU, in cores. (500m = .5 cores) If the + value is not specified, then the default value is + set depending on the component. If value is `0`, + then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: Memory, in bytes. (500Gi = 500GiB = 500 + * 1024 * 1024 * 1024) If the value is not specified, + then the default value is set depending on the component. + If value is `0`, then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + type: object secondsOfInactivityBeforeIdling: default: 1800 description: Idle timeout for workspaces in seconds. This timeout diff --git a/deploy/deployment/openshift/combined.yaml b/deploy/deployment/openshift/combined.yaml index 5cad47d1c..81906b499 100644 --- a/deploy/deployment/openshift/combined.yaml +++ b/deploy/deployment/openshift/combined.yaml @@ -6823,6 +6823,194 @@ spec: description: Pod scheduler for the workspace pods. If not specified, the pod scheduler is set to the default scheduler on the cluster. type: string + projectCloneContainer: + description: Project clone container configuration. + properties: + env: + description: List of environment variables to set in the container. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables + in the container and any service environment variables. + If a variable cannot be resolved, the reference in + the input string will be unchanged. Double $$ are + reduced to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + 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. + enum: + - Always + - IfNotPresent + - Never + type: string + name: + description: Container name. + type: string + resources: + description: Compute resources required by this container. + properties: + limits: + description: Describes the maximum amount of compute resources + allowed. + properties: + cpu: + anyOf: + - type: integer + - type: string + description: CPU, in cores. (500m = .5 cores) If the + value is not specified, then the default value is + set depending on the component. If value is `0`, + then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: Memory, in bytes. (500Gi = 500GiB = 500 + * 1024 * 1024 * 1024) If the value is not specified, + then the default value is set depending on the component. + If value is `0`, then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + request: + description: Describes the minimum amount of compute resources + required. + properties: + cpu: + anyOf: + - type: integer + - type: string + description: CPU, in cores. (500m = .5 cores) If the + value is not specified, then the default value is + set depending on the component. If value is `0`, + then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: Memory, in bytes. (500Gi = 500GiB = 500 + * 1024 * 1024 * 1024) If the value is not specified, + then the default value is set depending on the component. + If value is `0`, then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + type: object secondsOfInactivityBeforeIdling: default: 1800 description: Idle timeout for workspaces in seconds. This timeout diff --git a/deploy/deployment/openshift/objects/checlusters.org.eclipse.che.CustomResourceDefinition.yaml b/deploy/deployment/openshift/objects/checlusters.org.eclipse.che.CustomResourceDefinition.yaml index 2586c6a3e..16831144c 100644 --- a/deploy/deployment/openshift/objects/checlusters.org.eclipse.che.CustomResourceDefinition.yaml +++ b/deploy/deployment/openshift/objects/checlusters.org.eclipse.che.CustomResourceDefinition.yaml @@ -6818,6 +6818,194 @@ spec: description: Pod scheduler for the workspace pods. If not specified, the pod scheduler is set to the default scheduler on the cluster. type: string + projectCloneContainer: + description: Project clone container configuration. + properties: + env: + description: List of environment variables to set in the container. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables + in the container and any service environment variables. + If a variable cannot be resolved, the reference in + the input string will be unchanged. Double $$ are + reduced to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + 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. + enum: + - Always + - IfNotPresent + - Never + type: string + name: + description: Container name. + type: string + resources: + description: Compute resources required by this container. + properties: + limits: + description: Describes the maximum amount of compute resources + allowed. + properties: + cpu: + anyOf: + - type: integer + - type: string + description: CPU, in cores. (500m = .5 cores) If the + value is not specified, then the default value is + set depending on the component. If value is `0`, + then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: Memory, in bytes. (500Gi = 500GiB = 500 + * 1024 * 1024 * 1024) If the value is not specified, + then the default value is set depending on the component. + If value is `0`, then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + request: + description: Describes the minimum amount of compute resources + required. + properties: + cpu: + anyOf: + - type: integer + - type: string + description: CPU, in cores. (500m = .5 cores) If the + value is not specified, then the default value is + set depending on the component. If value is `0`, + then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: Memory, in bytes. (500Gi = 500GiB = 500 + * 1024 * 1024 * 1024) If the value is not specified, + then the default value is set depending on the component. + If value is `0`, then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + type: object secondsOfInactivityBeforeIdling: default: 1800 description: Idle timeout for workspaces in seconds. This timeout diff --git a/go.mod b/go.mod index b0e4cce76..3162c1d3a 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/che-incubator/kubernetes-image-puller-operator v0.0.0-20210929175054-0128446f5af7 github.com/devfile/api/v2 v2.2.1-alpha.0.20230413012049-a6c32fca0dbd - github.com/devfile/devworkspace-operator v0.20.0 + github.com/devfile/devworkspace-operator v0.21.0 github.com/go-logr/logr v1.2.3 github.com/golang/mock v1.5.0 github.com/google/go-cmp v0.5.9 diff --git a/go.sum b/go.sum index 60569ebbf..aeebedc47 100644 --- a/go.sum +++ b/go.sum @@ -102,8 +102,8 @@ github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC github.com/denisenkom/go-mssqldb v0.0.0-20190204142019-df6d76eb9289/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= github.com/devfile/api/v2 v2.2.1-alpha.0.20230413012049-a6c32fca0dbd h1:HpGR728CfB6BB9ZuFtQb0UeTIYNFgpuGsuoMOJNMUTM= github.com/devfile/api/v2 v2.2.1-alpha.0.20230413012049-a6c32fca0dbd/go.mod h1:qp8jcw12y1JdCsxjK/7LJ7uWaJOxcY1s2LUk5PhbkbM= -github.com/devfile/devworkspace-operator v0.20.0 h1:xm8+vCzVGf1D7AV05d4liRijIzWxnNwuV1Z976uzIOU= -github.com/devfile/devworkspace-operator v0.20.0/go.mod h1:LTraBqSugk9bR/ZKj3HAry+pnAdYOfwEYCl/FkuIjfI= +github.com/devfile/devworkspace-operator v0.21.0 h1:AiN2HEBpBkYoOcKClFZsOut46zKhsMIlHwmjI+OB2Oc= +github.com/devfile/devworkspace-operator v0.21.0/go.mod h1:42cQKSbE+Zdqez8X5IqlEfdeeA0a/LkOTe2kkekJX6c= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dhui/dktest v0.3.2/go.mod h1:l1/ib23a/CmxAe7yixtrYPc8Iy90Zy2udyaHINM5p58= github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492 h1:FwssHbCDJD025h+BchanCwE1Q8fyMgqDr2mOQAWOLGw= diff --git a/helmcharts/next/crds/checlusters.org.eclipse.che.CustomResourceDefinition.yaml b/helmcharts/next/crds/checlusters.org.eclipse.che.CustomResourceDefinition.yaml index 99d628bc4..749fdb29d 100644 --- a/helmcharts/next/crds/checlusters.org.eclipse.che.CustomResourceDefinition.yaml +++ b/helmcharts/next/crds/checlusters.org.eclipse.che.CustomResourceDefinition.yaml @@ -6818,6 +6818,194 @@ spec: description: Pod scheduler for the workspace pods. If not specified, the pod scheduler is set to the default scheduler on the cluster. type: string + projectCloneContainer: + description: Project clone container configuration. + properties: + env: + description: List of environment variables to set in the container. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables + in the container and any service environment variables. + If a variable cannot be resolved, the reference in + the input string will be unchanged. Double $$ are + reduced to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + 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. + enum: + - Always + - IfNotPresent + - Never + type: string + name: + description: Container name. + type: string + resources: + description: Compute resources required by this container. + properties: + limits: + description: Describes the maximum amount of compute resources + allowed. + properties: + cpu: + anyOf: + - type: integer + - type: string + description: CPU, in cores. (500m = .5 cores) If the + value is not specified, then the default value is + set depending on the component. If value is `0`, + then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: Memory, in bytes. (500Gi = 500GiB = 500 + * 1024 * 1024 * 1024) If the value is not specified, + then the default value is set depending on the component. + If value is `0`, then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + request: + description: Describes the minimum amount of compute resources + required. + properties: + cpu: + anyOf: + - type: integer + - type: string + description: CPU, in cores. (500m = .5 cores) If the + value is not specified, then the default value is + set depending on the component. If value is `0`, + then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: Memory, in bytes. (500Gi = 500GiB = 500 + * 1024 * 1024 * 1024) If the value is not specified, + then the default value is set depending on the component. + If value is `0`, then no value is set for the component. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + type: object secondsOfInactivityBeforeIdling: default: 1800 description: Idle timeout for workspaces in seconds. This timeout diff --git a/pkg/deploy/dev-workspace-config/dev_workspace_config.go b/pkg/deploy/dev-workspace-config/dev_workspace_config.go index 5c81fa112..b4190c2aa 100644 --- a/pkg/deploy/dev-workspace-config/dev_workspace_config.go +++ b/pkg/deploy/dev-workspace-config/dev_workspace_config.go @@ -9,6 +9,7 @@ // Contributors: // Red Hat, Inc. - initial API and implementation // + package devworkspaceconfig import ( @@ -21,6 +22,7 @@ import ( "github.com/eclipse-che/che-operator/pkg/common/utils" "github.com/eclipse-che/che-operator/pkg/deploy" v1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/pointer" @@ -84,14 +86,14 @@ func updateWorkspaceConfig(cheCluster *chev2.CheCluster, operatorConfig *control return err } - if err := updateWorkspaceServiceAccountConfig(devEnvironments, operatorConfig.Workspace); err != nil { - return err - } + updateWorkspaceServiceAccountConfig(devEnvironments, operatorConfig.Workspace) if err := updateWorkspacePodSchedulerNameConfig(devEnvironments, operatorConfig.Workspace); err != nil { return err } + updateProjectCloneConfig(devEnvironments, operatorConfig.Workspace) + operatorConfig.Workspace.ContainerSecurityContext = nil if cheCluster.IsContainerBuildCapabilitiesEnabled() { operatorConfig.Workspace.ContainerSecurityContext = constants.DefaultWorkspaceContainerSecurityContext.DeepCopy() @@ -146,19 +148,63 @@ func updateWorkspaceStorageConfig(devEnvironments *chev2.CheClusterDevEnvironmen return nil } -func updateWorkspaceServiceAccountConfig(devEnvironments *chev2.CheClusterDevEnvironments, workspaceConfig *controllerv1alpha1.WorkspaceConfig) error { - isNamespaceAutoProvisioned := pointer.BoolPtrDerefOr(devEnvironments.DefaultNamespace.AutoProvision, constants.DefaultAutoProvision) +func updateWorkspaceServiceAccountConfig(devEnvironments *chev2.CheClusterDevEnvironments, workspaceConfig *controllerv1alpha1.WorkspaceConfig) { + isNamespaceAutoProvisioned := pointer.BoolDeref(devEnvironments.DefaultNamespace.AutoProvision, constants.DefaultAutoProvision) workspaceConfig.ServiceAccount = &controllerv1alpha1.ServiceAccountConfig{ ServiceAccountName: devEnvironments.ServiceAccount, ServiceAccountTokens: devEnvironments.ServiceAccountTokens, // If user's Namespace is not auto provisioned (is pre-created by admin), then ServiceAccount must be pre-created as well - DisableCreation: pointer.BoolPtr(!isNamespaceAutoProvisioned && devEnvironments.ServiceAccount != ""), + DisableCreation: pointer.Bool(!isNamespaceAutoProvisioned && devEnvironments.ServiceAccount != ""), } - return nil } func updateWorkspacePodSchedulerNameConfig(devEnvironments *chev2.CheClusterDevEnvironments, workspaceConfig *controllerv1alpha1.WorkspaceConfig) error { workspaceConfig.SchedulerName = devEnvironments.PodSchedulerName return nil } + +func updateProjectCloneConfig(devEnvironments *chev2.CheClusterDevEnvironments, workspaceConfig *controllerv1alpha1.WorkspaceConfig) { + if devEnvironments.ProjectCloneContainer == nil { + return + } + if workspaceConfig.ProjectCloneConfig == nil { + workspaceConfig.ProjectCloneConfig = &controllerv1alpha1.ProjectCloneConfig{} + } + container := devEnvironments.ProjectCloneContainer + + workspaceConfig.ProjectCloneConfig.Image = container.Image + workspaceConfig.ProjectCloneConfig.ImagePullPolicy = container.ImagePullPolicy + workspaceConfig.ProjectCloneConfig.Env = container.Env + workspaceConfig.ProjectCloneConfig.Resources = cheResourcesToCoreV1Resources(container.Resources) +} + +// cheResourcesToCoreV1Resources converts a Che resources struct to the usual Kubernetes object by directly copying fields. +// It does not set any default values or include logic for removing requests/limits that are set to "0" as it is intended +// to prepare resources for the DevWorkspace Operator, which has its own defaults and handling of "0" values. +func cheResourcesToCoreV1Resources(resources *chev2.ResourceRequirements) *corev1.ResourceRequirements { + if resources == nil { + return nil + } + + result := &corev1.ResourceRequirements{} + if resources.Limits != nil { + result.Limits = corev1.ResourceList{} + if resources.Limits.Memory != nil { + result.Limits[corev1.ResourceMemory] = *resources.Limits.Memory + } + if resources.Limits.Cpu != nil { + result.Limits[corev1.ResourceCPU] = *resources.Limits.Cpu + } + } + if resources.Requests != nil { + result.Requests = corev1.ResourceList{} + if resources.Requests.Memory != nil { + result.Requests[corev1.ResourceMemory] = *resources.Requests.Memory + } + if resources.Requests.Cpu != nil { + result.Requests[corev1.ResourceCPU] = *resources.Requests.Cpu + } + } + return result +} diff --git a/pkg/deploy/dev-workspace-config/dev_workspace_config_test.go b/pkg/deploy/dev-workspace-config/dev_workspace_config_test.go index d897952ac..cf195ea76 100644 --- a/pkg/deploy/dev-workspace-config/dev_workspace_config_test.go +++ b/pkg/deploy/dev-workspace-config/dev_workspace_config_test.go @@ -9,30 +9,28 @@ // Contributors: // Red Hat, Inc. - initial API and implementation // + package devworkspaceconfig import ( + "context" "regexp" "testing" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - corev1 "k8s.io/api/core/v1" - - "github.com/eclipse-che/che-operator/pkg/common/constants" - "k8s.io/apimachinery/pkg/api/resource" - "k8s.io/utils/pointer" - - "context" - controllerv1alpha1 "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1" "github.com/devfile/devworkspace-operator/pkg/infrastructure" chev2 "github.com/eclipse-che/che-operator/api/v2" + "github.com/eclipse-che/che-operator/pkg/common/constants" "github.com/eclipse-che/che-operator/pkg/common/test" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/pointer" ) func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { @@ -52,6 +50,8 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { var quantity15Gi = resource.MustParse("15Gi") var quantity10Gi = resource.MustParse("10Gi") + var quantity1CPU = resource.MustParse("1000m") + var quantity500mCPU = resource.MustParse("500m") var expectedErrorTestCases = []errorTestCase{ { @@ -87,7 +87,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(true), + DisableContainerBuildCapabilities: pointer.Bool(true), }, }, }, @@ -102,7 +102,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(true), + DisableContainerBuildCapabilities: pointer.Bool(true), Storage: chev2.WorkspaceStorage{ PvcStrategy: constants.EphemeralPVCStorageStrategy, PerUserStrategyPvcConfig: &chev2.PVC{ @@ -128,7 +128,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(true), + DisableContainerBuildCapabilities: pointer.Bool(true), Storage: chev2.WorkspaceStorage{ PvcStrategy: constants.PerUserPVCStorageStrategy, PerUserStrategyPvcConfig: &chev2.PVC{ @@ -140,7 +140,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("test-storage"), + StorageClassName: pointer.String("test-storage"), DeploymentStrategy: "Recreate", }, }, @@ -154,7 +154,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(true), + DisableContainerBuildCapabilities: pointer.Bool(true), Storage: chev2.WorkspaceStorage{ PvcStrategy: constants.PerUserPVCStorageStrategy, PerUserStrategyPvcConfig: &chev2.PVC{ @@ -167,7 +167,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("test-storage"), + StorageClassName: pointer.String("test-storage"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ Common: &quantity15Gi, }, @@ -184,7 +184,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(true), + DisableContainerBuildCapabilities: pointer.Bool(true), Storage: chev2.WorkspaceStorage{ PvcStrategy: constants.PerWorkspacePVCStorageStrategy, PerWorkspaceStrategyPvcConfig: &chev2.PVC{ @@ -197,7 +197,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("test-storage"), + StorageClassName: pointer.String("test-storage"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ PerWorkspace: &quantity15Gi, }, @@ -214,7 +214,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(true), + DisableContainerBuildCapabilities: pointer.Bool(true), Storage: chev2.WorkspaceStorage{ PvcStrategy: constants.PerWorkspacePVCStorageStrategy, PerWorkspaceStrategyPvcConfig: &chev2.PVC{ @@ -237,7 +237,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Config: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("default-storage-class"), + StorageClassName: pointer.String("default-storage-class"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ PerWorkspace: &quantity10Gi, }, @@ -247,7 +247,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("test-storage"), + StorageClassName: pointer.String("test-storage"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ PerWorkspace: &quantity15Gi, }, @@ -264,7 +264,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(true), + DisableContainerBuildCapabilities: pointer.Bool(true), Storage: chev2.WorkspaceStorage{ PvcStrategy: constants.PerUserPVCStorageStrategy, PerUserStrategyPvcConfig: &chev2.PVC{ @@ -287,7 +287,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Config: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("default-storage-class"), + StorageClassName: pointer.String("default-storage-class"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ Common: &quantity10Gi, }, @@ -297,7 +297,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("test-storage"), + StorageClassName: pointer.String("test-storage"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ Common: &quantity15Gi, }, @@ -314,7 +314,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(true), + DisableContainerBuildCapabilities: pointer.Bool(true), Storage: chev2.WorkspaceStorage{ PvcStrategy: constants.PerUserPVCStorageStrategy, PerUserStrategyPvcConfig: &chev2.PVC{ @@ -351,7 +351,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Workspace: &controllerv1alpha1.WorkspaceConfig{ ImagePullPolicy: "Always", - StorageClassName: pointer.StringPtr("test-storage"), + StorageClassName: pointer.String("test-storage"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ Common: &quantity15Gi, }, @@ -368,7 +368,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(true), + DisableContainerBuildCapabilities: pointer.Bool(true), }, }, }, @@ -387,7 +387,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(false), + DisableContainerBuildCapabilities: pointer.Bool(false), }, }, }, @@ -400,7 +400,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { "SETUID", }, }, - AllowPrivilegeEscalation: pointer.BoolPtr(true), + AllowPrivilegeEscalation: pointer.Bool(true), }, DeploymentStrategy: "Recreate", }, @@ -415,7 +415,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(false), + DisableContainerBuildCapabilities: pointer.Bool(false), }, }, }, @@ -431,7 +431,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Config: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("default-storage-class"), + StorageClassName: pointer.String("default-storage-class"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ Common: &quantity10Gi, }, @@ -441,7 +441,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("default-storage-class"), + StorageClassName: pointer.String("default-storage-class"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ Common: &quantity10Gi, }, @@ -452,7 +452,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { "SETUID", }, }, - AllowPrivilegeEscalation: pointer.BoolPtr(true), + AllowPrivilegeEscalation: pointer.Bool(true), }, DeploymentStrategy: "Recreate", }, @@ -467,7 +467,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(true), + DisableContainerBuildCapabilities: pointer.Bool(true), }, }, }, @@ -483,7 +483,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Config: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("default-storage-class"), + StorageClassName: pointer.String("default-storage-class"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ Common: &quantity10Gi, }, @@ -495,7 +495,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("default-storage-class"), + StorageClassName: pointer.String("default-storage-class"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ Common: &quantity10Gi, }, @@ -512,8 +512,8 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(true), - StartTimeoutSeconds: pointer.Int32Ptr(600), + DisableContainerBuildCapabilities: pointer.Bool(true), + StartTimeoutSeconds: pointer.Int32(600), }, }, }, @@ -533,8 +533,8 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(true), - StartTimeoutSeconds: pointer.Int32Ptr(600), + DisableContainerBuildCapabilities: pointer.Bool(true), + StartTimeoutSeconds: pointer.Int32(600), }, }, }, @@ -550,7 +550,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Config: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("default-storage-class"), + StorageClassName: pointer.String("default-storage-class"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ Common: &quantity10Gi, }, @@ -560,7 +560,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("default-storage-class"), + StorageClassName: pointer.String("default-storage-class"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ Common: &quantity10Gi, }, @@ -578,8 +578,8 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(true), - StartTimeoutSeconds: pointer.Int32Ptr(420), + DisableContainerBuildCapabilities: pointer.Bool(true), + StartTimeoutSeconds: pointer.Int32(420), }, }, }, @@ -595,7 +595,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Config: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("default-storage-class"), + StorageClassName: pointer.String("default-storage-class"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ Common: &quantity10Gi, }, @@ -606,7 +606,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("default-storage-class"), + StorageClassName: pointer.String("default-storage-class"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ Common: &quantity10Gi, }, @@ -624,7 +624,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ - DisableContainerBuildCapabilities: pointer.BoolPtr(true), + DisableContainerBuildCapabilities: pointer.Bool(true), }, }, }, @@ -640,7 +640,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, Config: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("default-storage-class"), + StorageClassName: pointer.String("default-storage-class"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ Common: &quantity10Gi, }, @@ -651,7 +651,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ - StorageClassName: pointer.StringPtr("default-storage-class"), + StorageClassName: pointer.String("default-storage-class"), DefaultStorageSize: &controllerv1alpha1.StorageSizes{ Common: &quantity10Gi, }, @@ -659,6 +659,87 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, }, }, + { + name: "Configures ProjectCloneConfig in DevWorkspaceOperatorConfig", + cheCluster: &chev2.CheCluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "eclipse-che", + Name: "eclipse-che", + }, + Spec: chev2.CheClusterSpec{ + DevEnvironments: chev2.CheClusterDevEnvironments{ + DisableContainerBuildCapabilities: pointer.Bool(true), + ProjectCloneContainer: &chev2.Container{ + Name: "project-clone", + Image: "test-image", + ImagePullPolicy: "IfNotPresent", + Env: []corev1.EnvVar{ + {Name: "test-env-1", Value: "test-val-1"}, + {Name: "test-env-2", Value: "test-val-2"}, + }, + Resources: &chev2.ResourceRequirements{ + Requests: &chev2.ResourceList{ + Memory: &quantity10Gi, + Cpu: &quantity500mCPU, + }, + Limits: &chev2.ResourceList{ + Memory: &quantity15Gi, + Cpu: &quantity1CPU, + }, + }, + }, + }, + }, + }, + existedObjects: []runtime.Object{ + &controllerv1alpha1.DevWorkspaceOperatorConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: devWorkspaceConfigName, + Namespace: "eclipse-che", + }, + TypeMeta: metav1.TypeMeta{ + Kind: "DevWorkspaceOperatorConfig", + APIVersion: controllerv1alpha1.GroupVersion.String(), + }, + Config: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{ + StorageClassName: pointer.String("default-storage-class"), + DefaultStorageSize: &controllerv1alpha1.StorageSizes{ + Common: &quantity10Gi, + }, + ProgressTimeout: "1h30m", + }, + }, + }, + }, + expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{ + StorageClassName: pointer.String("default-storage-class"), + DefaultStorageSize: &controllerv1alpha1.StorageSizes{ + Common: &quantity10Gi, + }, + DeploymentStrategy: "Recreate", + ProjectCloneConfig: &controllerv1alpha1.ProjectCloneConfig{ + Image: "test-image", + ImagePullPolicy: "IfNotPresent", + Env: []corev1.EnvVar{ + {Name: "test-env-1", Value: "test-val-1"}, + {Name: "test-env-2", Value: "test-val-2"}, + }, + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceMemory: quantity10Gi, + corev1.ResourceCPU: quantity500mCPU, + }, + Limits: corev1.ResourceList{ + corev1.ResourceMemory: quantity15Gi, + corev1.ResourceCPU: quantity1CPU, + }, + }, + }, + }, + }, + }, } for _, testCase := range testCases { @@ -717,7 +798,7 @@ func TestReconcileServiceAccountConfig(t *testing.T) { Workspace: &controllerv1alpha1.WorkspaceConfig{ ServiceAccount: &controllerv1alpha1.ServiceAccountConfig{ ServiceAccountName: "service-account", - DisableCreation: pointer.BoolPtr(false), + DisableCreation: pointer.Bool(false), }, DeploymentStrategy: "Recreate", }, @@ -733,7 +814,7 @@ func TestReconcileServiceAccountConfig(t *testing.T) { Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ DefaultNamespace: chev2.DefaultNamespace{ - AutoProvision: pointer.BoolPtr(false), + AutoProvision: pointer.Bool(false), }, ServiceAccount: "service-account", }, @@ -743,7 +824,7 @@ func TestReconcileServiceAccountConfig(t *testing.T) { Workspace: &controllerv1alpha1.WorkspaceConfig{ ServiceAccount: &controllerv1alpha1.ServiceAccountConfig{ ServiceAccountName: "service-account", - DisableCreation: pointer.BoolPtr(true), + DisableCreation: pointer.Bool(true), }, DeploymentStrategy: "Recreate", }, @@ -763,7 +844,7 @@ func TestReconcileServiceAccountConfig(t *testing.T) { expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ ServiceAccount: &controllerv1alpha1.ServiceAccountConfig{ - DisableCreation: pointer.BoolPtr(false), + DisableCreation: pointer.Bool(false), }, DeploymentStrategy: "Recreate", }, @@ -779,7 +860,7 @@ func TestReconcileServiceAccountConfig(t *testing.T) { Spec: chev2.CheClusterSpec{ DevEnvironments: chev2.CheClusterDevEnvironments{ DefaultNamespace: chev2.DefaultNamespace{ - AutoProvision: pointer.BoolPtr(false), + AutoProvision: pointer.Bool(false), }, }, }, @@ -787,7 +868,7 @@ func TestReconcileServiceAccountConfig(t *testing.T) { expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ Workspace: &controllerv1alpha1.WorkspaceConfig{ ServiceAccount: &controllerv1alpha1.ServiceAccountConfig{ - DisableCreation: pointer.BoolPtr(false), + DisableCreation: pointer.Bool(false), }, DeploymentStrategy: "Recreate", }, @@ -1328,3 +1409,194 @@ func TestReconcileDevWorkspaceConfigDeploymentStrategy(t *testing.T) { }) } } + +func TestReconcileDevWorkspaceProjectCloneCOnfig(t *testing.T) { + const testNamespace = "eclipse-che" + testMemLimit := resource.MustParse("2Gi") + testCpuLimit := resource.MustParse("1000m") + testMemRequest := resource.MustParse("1Gi") + testCpuRequest := resource.MustParse("500m") + + type testCase struct { + name string + cheProjectCloneConfig *chev2.Container + expectedDevWorkspaceConfig *controllerv1alpha1.ProjectCloneConfig + existingDevWorkspaceConfig *controllerv1alpha1.ProjectCloneConfig + } + + tests := []testCase{ + { + name: "Syncs Che project clone config to DevWorkspaceOperatorConfig", + cheProjectCloneConfig: &chev2.Container{ + Name: "project-clone", + Image: "test-image", + ImagePullPolicy: "IfNotPresent", + Env: []corev1.EnvVar{ + {Name: "test-env-1", Value: "test-val-1"}, + {Name: "test-env-2", Value: "test-val-2"}, + }, + Resources: &chev2.ResourceRequirements{ + Limits: &chev2.ResourceList{ + Memory: &testMemLimit, + Cpu: &testCpuLimit, + }, + Requests: &chev2.ResourceList{ + Memory: &testMemRequest, + Cpu: &testCpuRequest, + }, + }, + }, + expectedDevWorkspaceConfig: &controllerv1alpha1.ProjectCloneConfig{ + Image: "test-image", + ImagePullPolicy: "IfNotPresent", + Env: []corev1.EnvVar{ + {Name: "test-env-1", Value: "test-val-1"}, + {Name: "test-env-2", Value: "test-val-2"}, + }, + Resources: &corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceMemory: testMemLimit, + corev1.ResourceCPU: testCpuLimit, + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: testMemRequest, + corev1.ResourceCPU: testCpuRequest, + }, + }, + }, + }, + { + name: "Updates existing DevWorkspaceOperatorConfig with new Che project clone config", + cheProjectCloneConfig: &chev2.Container{ + Name: "project-clone", + Image: "test-image", + ImagePullPolicy: "IfNotPresent", + Env: []corev1.EnvVar{ + {Name: "test-env-1", Value: "test-val-1"}, + {Name: "test-env-2", Value: "test-val-2"}, + }, + Resources: &chev2.ResourceRequirements{ + Limits: &chev2.ResourceList{ + Memory: &testMemLimit, + Cpu: &testCpuLimit, + }, + Requests: &chev2.ResourceList{ + Memory: &testMemRequest, + Cpu: &testCpuRequest, + }, + }, + }, + expectedDevWorkspaceConfig: &controllerv1alpha1.ProjectCloneConfig{ + Image: "test-image", + ImagePullPolicy: "IfNotPresent", + Env: []corev1.EnvVar{ + {Name: "test-env-1", Value: "test-val-1"}, + {Name: "test-env-2", Value: "test-val-2"}, + }, + Resources: &corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceMemory: testMemLimit, + corev1.ResourceCPU: testCpuLimit, + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: testMemRequest, + corev1.ResourceCPU: testCpuRequest, + }, + }, + }, + existingDevWorkspaceConfig: &controllerv1alpha1.ProjectCloneConfig{ + Image: "other image", + ImagePullPolicy: "Always", + Env: []corev1.EnvVar{ + {Name: "other-env", Value: "other-val"}, + }, + Resources: &corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("1234Mi"), + corev1.ResourceCPU: resource.MustParse("1234m"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("1111Mi"), + corev1.ResourceCPU: resource.MustParse("1111m"), + }, + }, + }, + }, + { + name: "Removes fields from existing config when removed from CheCluster", + cheProjectCloneConfig: &chev2.Container{ + Name: "", + Image: "", + ImagePullPolicy: "", + Env: nil, + Resources: nil, + }, + expectedDevWorkspaceConfig: &controllerv1alpha1.ProjectCloneConfig{ + Image: "", + ImagePullPolicy: "", + Env: nil, + Resources: nil, + }, + existingDevWorkspaceConfig: &controllerv1alpha1.ProjectCloneConfig{ + Image: "other image", + ImagePullPolicy: "Always", + Env: []corev1.EnvVar{ + {Name: "other-env", Value: "other-val"}, + }, + Resources: &corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("1234Mi"), + corev1.ResourceCPU: resource.MustParse("1234m"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("1111Mi"), + corev1.ResourceCPU: resource.MustParse("1111m"), + }, + }, + }, + }, + } + + for _, testCase := range tests { + t.Run(testCase.name, func(t *testing.T) { + cheCluster := &chev2.CheCluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "eclipse-che", + }, + Spec: chev2.CheClusterSpec{ + DevEnvironments: chev2.CheClusterDevEnvironments{ + ProjectCloneContainer: testCase.cheProjectCloneConfig, + }, + }, + } + existingDWOC := &controllerv1alpha1.DevWorkspaceOperatorConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: devWorkspaceConfigName, + Namespace: testNamespace, + }, + Config: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{ + ProjectCloneConfig: testCase.existingDevWorkspaceConfig, + }, + }, + } + runtimeDWOC := runtime.Object(existingDWOC) + + deployContext := test.GetDeployContext(cheCluster, []runtime.Object{runtimeDWOC}) + infrastructure.InitializeForTesting(infrastructure.OpenShiftv4) + + devWorkspaceConfigReconciler := NewDevWorkspaceConfigReconciler() + _, _, err := devWorkspaceConfigReconciler.Reconcile(deployContext) + assert.NoError(t, err) + + dwoc := &controllerv1alpha1.DevWorkspaceOperatorConfig{} + err = deployContext.ClusterAPI.Client.Get(context.TODO(), types.NamespacedName{Name: devWorkspaceConfigName, Namespace: testNamespace}, dwoc) + assert.NoError(t, err) + + diff := cmp.Diff(testCase.expectedDevWorkspaceConfig, dwoc.Config.Workspace.ProjectCloneConfig) + assert.Empty(t, diff) + }) + } + +} diff --git a/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go b/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go index 692687bb4..31bc96e47 100644 --- a/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go +++ b/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go @@ -62,76 +62,10 @@ type RoutingConfig struct { ProxyConfig *Proxy `json:"proxyConfig,omitempty"` } -type Proxy struct { - // HttpProxy is the URL of the proxy for HTTP requests, in the format http://USERNAME:PASSWORD@SERVER:PORT/ - HttpProxy string `json:"httpProxy,omitempty"` - // HttpsProxy is the URL of the proxy for HTTPS requests, in the format http://USERNAME:PASSWORD@SERVER:PORT/ - HttpsProxy string `json:"httpsProxy,omitempty"` - // NoProxy is a comma-separated list of hostnames and/or CIDRs for which the proxy should not be used. Ignored - // when HttpProxy and HttpsProxy are unset - NoProxy string `json:"noProxy,omitempty"` -} - -type StorageSizes struct { - // The default Persistent Volume Claim size for the "common" storage class. - // Note that the "async" storage class also uses the PVC size set for the "common" storage class. - // If not specified, the "common" and "async" Persistent Volume Claim sizes are set to 10Gi - Common *resource.Quantity `json:"common,omitempty"` - // The default Persistent Volume Claim size for the "per-workspace" storage class. - // If not specified, the "per-workspace" Persistent Volume Claim size is set to 5Gi - PerWorkspace *resource.Quantity `json:"perWorkspace,omitempty"` -} - -type ServiceAccountConfig struct { - // ServiceAccountName defines a fixed name to be used for all DevWorkspaces. If set, the DevWorkspace - // Operator will not generate a separate ServiceAccount for each DevWorkspace, and will instead create - // a ServiceAccount with the specified name in each namespace where DevWorkspaces are created. If specified, - // the created ServiceAccount will not be removed when DevWorkspaces are deleted and must be cleaned up manually. - // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - // +kubebuilder:validation:MaxLength=63 - ServiceAccountName string `json:"serviceAccountName,omitempty"` - // Disable creation of DevWorkspace ServiceAccounts by the DevWorkspace Operator. If set to true, the serviceAccountName - // field must also be set. If ServiceAccount creation is disabled, it is assumed that the specified ServiceAccount already - // exists in any namespace where a workspace is created. If a suitable ServiceAccount does not exist, starting DevWorkspaces - // will fail. - DisableCreation *bool `json:"disableCreation,omitempty"` - // List of ServiceAccount tokens that will be mounted into workspace pods as projected volumes. - ServiceAccountTokens []ServiceAccountToken `json:"serviceAccountTokens,omitempty"` -} - -type ServiceAccountToken struct { - // Identifiable name of the ServiceAccount token. - // If multiple ServiceAccount tokens use the same mount path, a generic name will be used - // for the projected volume instead. - // +kubebuilder:validation:Required - Name string `json:"name"` - // Path within the workspace container at which the token should be mounted. Must - // not contain ':'. - // +kubebuilder:validation:Required - MountPath string `json:"mountPath"` - // Path is the path relative to the mount point of the file to project the - // token into. - // +kubebuilder:validation:Required - Path string `json:"path"` - // Audience is the intended audience of the token. A recipient of a token - // must identify itself with an identifier specified in the audience of the - // token, and otherwise should reject the token. The audience defaults to the - // identifier of the apiserver. - // +kubebuilder:validation:Optional - Audience string `json:"audience,omitempty"` - // ExpirationSeconds is the requested duration of validity of the service - // account token. As the token approaches expiration, the kubelet volume - // plugin will proactively rotate the service account token. The kubelet will - // start trying to rotate the token if the token is older than 80 percent of - // its time to live or if the token is older than 24 hours. Defaults to 1 hour - // and must be at least 10 minutes. - // +kubebuilder:validation:Minimum=600 - // +kubebuilder:default:=3600 - // +kubebuilder:validation:Optional - ExpirationSeconds int64 `json:"expirationSeconds,omitempty"` -} - type WorkspaceConfig struct { + // ProjectCloneConfig defines configuration related to the project clone init container + // that is used to clone git projects into the DevWorkspace. + ProjectCloneConfig *ProjectCloneConfig `json:"projectClone,omitempty"` // ImagePullPolicy defines the imagePullPolicy used for containers in a DevWorkspace // For additional information, see Kubernetes documentation for imagePullPolicy. If // not specified, the default value of "Always" is used. @@ -203,6 +137,89 @@ type WorkspaceConfig struct { SchedulerName string `json:"schedulerName,omitempty"` } +type Proxy struct { + // HttpProxy is the URL of the proxy for HTTP requests, in the format http://USERNAME:PASSWORD@SERVER:PORT/ + HttpProxy string `json:"httpProxy,omitempty"` + // HttpsProxy is the URL of the proxy for HTTPS requests, in the format http://USERNAME:PASSWORD@SERVER:PORT/ + HttpsProxy string `json:"httpsProxy,omitempty"` + // NoProxy is a comma-separated list of hostnames and/or CIDRs for which the proxy should not be used. Ignored + // when HttpProxy and HttpsProxy are unset + NoProxy string `json:"noProxy,omitempty"` +} + +type StorageSizes struct { + // The default Persistent Volume Claim size for the "common" storage class. + // Note that the "async" storage class also uses the PVC size set for the "common" storage class. + // If not specified, the "common" and "async" Persistent Volume Claim sizes are set to 10Gi + Common *resource.Quantity `json:"common,omitempty"` + // The default Persistent Volume Claim size for the "per-workspace" storage class. + // If not specified, the "per-workspace" Persistent Volume Claim size is set to 5Gi + PerWorkspace *resource.Quantity `json:"perWorkspace,omitempty"` +} + +type ServiceAccountConfig struct { + // ServiceAccountName defines a fixed name to be used for all DevWorkspaces. If set, the DevWorkspace + // Operator will not generate a separate ServiceAccount for each DevWorkspace, and will instead create + // a ServiceAccount with the specified name in each namespace where DevWorkspaces are created. If specified, + // the created ServiceAccount will not be removed when DevWorkspaces are deleted and must be cleaned up manually. + // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + // +kubebuilder:validation:MaxLength=63 + ServiceAccountName string `json:"serviceAccountName,omitempty"` + // Disable creation of DevWorkspace ServiceAccounts by the DevWorkspace Operator. If set to true, the serviceAccountName + // field must also be set. If ServiceAccount creation is disabled, it is assumed that the specified ServiceAccount already + // exists in any namespace where a workspace is created. If a suitable ServiceAccount does not exist, starting DevWorkspaces + // will fail. + DisableCreation *bool `json:"disableCreation,omitempty"` + // List of ServiceAccount tokens that will be mounted into workspace pods as projected volumes. + ServiceAccountTokens []ServiceAccountToken `json:"serviceAccountTokens,omitempty"` +} + +type ServiceAccountToken struct { + // Identifiable name of the ServiceAccount token. + // If multiple ServiceAccount tokens use the same mount path, a generic name will be used + // for the projected volume instead. + // +kubebuilder:validation:Required + Name string `json:"name"` + // Path within the workspace container at which the token should be mounted. Must + // not contain ':'. + // +kubebuilder:validation:Required + MountPath string `json:"mountPath"` + // Path is the path relative to the mount point of the file to project the + // token into. + // +kubebuilder:validation:Required + Path string `json:"path"` + // Audience is the intended audience of the token. A recipient of a token + // must identify itself with an identifier specified in the audience of the + // token, and otherwise should reject the token. The audience defaults to the + // identifier of the apiserver. + // +kubebuilder:validation:Optional + Audience string `json:"audience,omitempty"` + // ExpirationSeconds is the requested duration of validity of the service + // account token. As the token approaches expiration, the kubelet volume + // plugin will proactively rotate the service account token. The kubelet will + // start trying to rotate the token if the token is older than 80 percent of + // its time to live or if the token is older than 24 hours. Defaults to 1 hour + // and must be at least 10 minutes. + // +kubebuilder:validation:Minimum=600 + // +kubebuilder:default:=3600 + // +kubebuilder:validation:Optional + ExpirationSeconds int64 `json:"expirationSeconds,omitempty"` +} + +type ProjectCloneConfig struct { + // Image is the container image to use for cloning projects + Image string `json:"image,omitempty"` + // ImagePullPolicy configures the imagePullPolicy for the project clone container. + // If undefined, the general setting .config.workspace.imagePullPolicy is used instead. + ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"` + // Resources defines the resource (cpu, memory) limits and requests for the project + // clone container. To explicitly not specify a limit or request, define the resource + // quantity as zero ('0') + Resources *corev1.ResourceRequirements `json:"resources,omitempty"` + // Env allows defining additional environment variables for the project clone container. + Env []corev1.EnvVar `json:"env,omitempty"` +} + // DevWorkspaceOperatorConfig is the Schema for the devworkspaceoperatorconfigs API // +kubebuilder:object:root=true // +kubebuilder:resource:path=devworkspaceoperatorconfigs,scope=Namespaced,shortName=dwoc diff --git a/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/zz_generated.deepcopy.go index 8cf65ffff..24a97d005 100644 --- a/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/zz_generated.deepcopy.go @@ -444,6 +444,33 @@ func (in *PodAdditions) DeepCopy() *PodAdditions { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProjectCloneConfig) DeepCopyInto(out *ProjectCloneConfig) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = new(v1.ResourceRequirements) + (*in).DeepCopyInto(*out) + } + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]v1.EnvVar, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectCloneConfig. +func (in *ProjectCloneConfig) DeepCopy() *ProjectCloneConfig { + if in == nil { + return nil + } + out := new(ProjectCloneConfig) + 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 @@ -547,6 +574,11 @@ func (in *StorageSizes) DeepCopy() *StorageSizes { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WorkspaceConfig) DeepCopyInto(out *WorkspaceConfig) { *out = *in + if in.ProjectCloneConfig != nil { + in, out := &in.ProjectCloneConfig, &out.ProjectCloneConfig + *out = new(ProjectCloneConfig) + (*in).DeepCopyInto(*out) + } if in.ServiceAccount != nil { in, out := &in.ServiceAccount, &out.ServiceAccount *out = new(ServiceAccountConfig) diff --git a/vendor/github.com/devfile/devworkspace-operator/pkg/config/defaults.go b/vendor/github.com/devfile/devworkspace-operator/pkg/config/defaults.go index 05d13e92d..c145dea3b 100644 --- a/vendor/github.com/devfile/devworkspace-operator/pkg/config/defaults.go +++ b/vendor/github.com/devfile/devworkspace-operator/pkg/config/defaults.go @@ -49,6 +49,18 @@ var defaultConfig = &v1alpha1.OperatorConfiguration{ PodSecurityContext: nil, ContainerSecurityContext: &corev1.SecurityContext{}, DefaultTemplate: nil, + ProjectCloneConfig: &v1alpha1.ProjectCloneConfig{ + Resources: &corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("1Gi"), + corev1.ResourceCPU: resource.MustParse("1000m"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("128Mi"), + corev1.ResourceCPU: resource.MustParse("100m"), + }, + }, + }, }, } diff --git a/vendor/github.com/devfile/devworkspace-operator/pkg/config/sync.go b/vendor/github.com/devfile/devworkspace-operator/pkg/config/sync.go index 7b66ef60d..51ff528ec 100644 --- a/vendor/github.com/devfile/devworkspace-operator/pkg/config/sync.go +++ b/vendor/github.com/devfile/devworkspace-operator/pkg/config/sync.go @@ -334,6 +334,29 @@ func mergeConfig(from, to *controller.OperatorConfiguration) { if from.Workspace.SchedulerName != "" { to.Workspace.SchedulerName = from.Workspace.SchedulerName } + if from.Workspace.ProjectCloneConfig != nil { + if to.Workspace.ProjectCloneConfig == nil { + to.Workspace.ProjectCloneConfig = &controller.ProjectCloneConfig{} + } + if from.Workspace.ProjectCloneConfig.Image != "" { + to.Workspace.ProjectCloneConfig.Image = from.Workspace.ProjectCloneConfig.Image + } + if from.Workspace.ProjectCloneConfig.ImagePullPolicy != "" { + to.Workspace.ProjectCloneConfig.ImagePullPolicy = from.Workspace.ProjectCloneConfig.ImagePullPolicy + } + if from.Workspace.ProjectCloneConfig.Resources != nil { + if to.Workspace.ProjectCloneConfig.Resources == nil { + to.Workspace.ProjectCloneConfig.Resources = &corev1.ResourceRequirements{} + } + to.Workspace.ProjectCloneConfig.Resources = mergeResources(from.Workspace.ProjectCloneConfig.Resources, to.Workspace.ProjectCloneConfig.Resources) + } + + // Overwrite env instead of trying to merge, don't want to bother merging lists when + // the default is empty + if from.Workspace.ProjectCloneConfig.Env != nil { + to.Workspace.ProjectCloneConfig.Env = from.Workspace.ProjectCloneConfig.Env + } + } } } @@ -385,6 +408,33 @@ func mergeContainerSecurityContext(base, patch *corev1.SecurityContext) *corev1. return patched } +func mergeResources(from, to *corev1.ResourceRequirements) *corev1.ResourceRequirements { + result := to.DeepCopy() + if from.Limits != nil { + if result.Limits == nil { + result.Limits = corev1.ResourceList{} + } + if cpu, ok := from.Limits[corev1.ResourceCPU]; ok { + result.Limits[corev1.ResourceCPU] = cpu + } + if memory, ok := from.Limits[corev1.ResourceMemory]; ok { + result.Limits[corev1.ResourceMemory] = memory + } + } + if from.Requests != nil { + if result.Requests == nil { + result.Requests = corev1.ResourceList{} + } + if cpu, ok := from.Requests[corev1.ResourceCPU]; ok { + result.Requests[corev1.ResourceCPU] = cpu + } + if memory, ok := from.Requests[corev1.ResourceMemory]; ok { + result.Requests[corev1.ResourceMemory] = memory + } + } + return result +} + func GetCurrentConfigString(currConfig *controller.OperatorConfiguration) string { if currConfig == nil { return "" @@ -462,6 +512,20 @@ func GetCurrentConfigString(currConfig *controller.OperatorConfiguration) string if workspace.SchedulerName != "" { config = append(config, fmt.Sprintf("workspace.schedulerName=%s", workspace.SchedulerName)) } + if workspace.ProjectCloneConfig != nil { + if workspace.ProjectCloneConfig.Image != defaultConfig.Workspace.ProjectCloneConfig.Image { + config = append(config, fmt.Sprintf("workspace.projectClone.image=%s", workspace.ProjectCloneConfig.Image)) + } + if workspace.ProjectCloneConfig.ImagePullPolicy != defaultConfig.Workspace.ProjectCloneConfig.ImagePullPolicy { + config = append(config, fmt.Sprintf("workspace.projectClone.imagePullPolicy=%s", workspace.ProjectCloneConfig.ImagePullPolicy)) + } + if workspace.ProjectCloneConfig.Env != nil { + config = append(config, "workspace.projectClone.env is set") + } + if !reflect.DeepEqual(workspace.ProjectCloneConfig.Resources, defaultConfig.Workspace.ProjectCloneConfig.Resources) { + config = append(config, "workspace.projectClone.resources is set") + } + } } if currConfig.EnableExperimentalFeatures != nil && *currConfig.EnableExperimentalFeatures { config = append(config, "enableExperimentalFeatures=true") diff --git a/vendor/github.com/devfile/devworkspace-operator/pkg/constants/constants.go b/vendor/github.com/devfile/devworkspace-operator/pkg/constants/constants.go index 9660bc5ae..71659976c 100644 --- a/vendor/github.com/devfile/devworkspace-operator/pkg/constants/constants.go +++ b/vendor/github.com/devfile/devworkspace-operator/pkg/constants/constants.go @@ -65,12 +65,6 @@ const ( // PVCCleanupPodCPURequest is the cpu request used for PVC clean up pods PVCCleanupPodCPURequest = "5m" - // Resource limits/requests for project cloner init container - ProjectCloneMemoryLimit = "1Gi" - ProjectCloneMemoryRequest = "128Mi" - ProjectCloneCPULimit = "1000m" - ProjectCloneCPURequest = "100m" - // Constants describing storage classes supported by the controller // CommonStorageClassType defines the 'common' storage policy, which is an alias of the 'per-user' storage policy, and operates in the same fashion as the 'per-user' storage policy. diff --git a/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/sync.go b/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/sync.go index 62ad02d5b..e0ff5a7c4 100644 --- a/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/sync.go +++ b/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/sync.go @@ -200,17 +200,19 @@ func printDiff(specObj, clusterObj crclient.Object, log logr.Logger) { diffOpts = podDiffOpts case *corev1.ConfigMap: diffOpts = configmapDiffOpts - case *corev1.Secret: - diffOpts = secretDiffOpts case *v1alpha1.DevWorkspaceRouting: diffOpts = routingDiffOpts case *networkingv1.Ingress: diffOpts = ingressDiffOpts case *routev1.Route: diffOpts = routeDiffOpts + case *corev1.Secret: + log.Info(fmt.Sprintf("Diff: secret %s data upated", specObj.GetName())) + return default: diffOpts = nil } + log.Info(fmt.Sprintf("Diff: %s", cmp.Diff(specObj, clusterObj, diffOpts))) } } diff --git a/vendor/modules.txt b/vendor/modules.txt index b3d99ae00..cad42123e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -32,7 +32,7 @@ github.com/davecgh/go-spew/spew github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2 github.com/devfile/api/v2/pkg/attributes github.com/devfile/api/v2/pkg/devfile -# github.com/devfile/devworkspace-operator v0.20.0 +# github.com/devfile/devworkspace-operator v0.21.0 ## explicit; go 1.18 github.com/devfile/devworkspace-operator/apis/controller/v1alpha1 github.com/devfile/devworkspace-operator/controllers/controller/devworkspacerouting