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 <amisevsk@redhat.com>

* 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 <amisevsk@redhat.com>

* 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 <amisevsk@redhat.com>

---------

Signed-off-by: Angel Misevski <amisevsk@redhat.com>
pull/1692/head
Angel Misevski 2023-05-31 02:58:50 -04:00 committed by GitHub
parent be2afadd93
commit 02ce7749f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 1914 additions and 147 deletions

View File

@ -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) |

View File

@ -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"`

View File

@ -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

View File

@ -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

View File

@ -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[''<KEY>'']`,
`metadata.annotations[''<KEY>'']`, 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

View File

@ -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[''<KEY>'']`,
`metadata.annotations[''<KEY>'']`, 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

View File

@ -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[''<KEY>'']`,
`metadata.annotations[''<KEY>'']`, 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

View File

@ -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[''<KEY>'']`,
`metadata.annotations[''<KEY>'']`, 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

View File

@ -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[''<KEY>'']`,
`metadata.annotations[''<KEY>'']`, 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

View File

@ -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[''<KEY>'']`,
`metadata.annotations[''<KEY>'']`, 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

2
go.mod
View File

@ -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

4
go.sum
View File

@ -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=

View File

@ -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[''<KEY>'']`,
`metadata.annotations[''<KEY>'']`, 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

View File

@ -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
}

View File

@ -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)
})
}
}

View File

@ -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

View File

@ -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)

View File

@ -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"),
},
},
},
},
}

View File

@ -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")

View File

@ -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.

View File

@ -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)))
}
}

2
vendor/modules.txt vendored
View File

@ -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