feat: configure workspace start timeout from Che Cluster CR (#1576)

* feat: configure workspace security context for container builds

Fix eclipse/che#21770

Signed-off-by: Andrew Obuchowicz <aobuchow@redhat.com>

* feat: add spec.devEnvironments.startTimeout to Che Cluster CR

Signed-off-by: Andrew Obuchowicz <aobuchow@redhat.com>

* chore: add tests for configuring DWO progressTimeout with Che Cluster CR

Signed-off-by: Andrew Obuchowicz <aobuchow@redhat.com>

* chore: update deployment, bundle, CSV and CRD

Signed-off-by: Andrew Obuchowicz <aobuchow@redhat.com>

* Update resources

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

Signed-off-by: Andrew Obuchowicz <aobuchow@redhat.com>
Signed-off-by: Anatolii Bazko <abazko@redhat.com>
Co-authored-by: Anatolii Bazko <abazko@redhat.com>
pull/1590/head
Andrew O 2022-12-28 03:20:12 -05:00 committed by GitHub
parent 4774568459
commit 571cd1e329
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 408 additions and 7 deletions

View File

@ -37,7 +37,7 @@ type CheClusterSpec struct {
// +optional
// +operator-sdk:csv:customresourcedefinitions:type=spec,order=1
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Development environments"
// +kubebuilder:default:={disableContainerBuildCapabilities: true, defaultComponents: {{name: universal-developer-image, container: {image: "quay.io/devfile/universal-developer-image:ubi8-38da5c2"}}}, defaultEditor: che-incubator/che-code/insiders, storage: {pvcStrategy: per-user}, defaultNamespace: {template: <username>-che, autoProvision: true}, secondsOfInactivityBeforeIdling:1800, secondsOfRunBeforeIdling:-1}
// +kubebuilder:default:={disableContainerBuildCapabilities: true, defaultComponents: {{name: universal-developer-image, container: {image: "quay.io/devfile/universal-developer-image:ubi8-38da5c2"}}}, defaultEditor: che-incubator/che-code/insiders, storage: {pvcStrategy: per-user}, defaultNamespace: {template: <username>-che, autoProvision: true}, secondsOfInactivityBeforeIdling:1800, secondsOfRunBeforeIdling:-1, startTimeoutSeconds:300}
DevEnvironments CheClusterDevEnvironments `json:"devEnvironments"`
// Che components configuration.
// +optional
@ -123,6 +123,13 @@ type CheClusterDevEnvironments struct {
// If not specified, the pod scheduler is set to the default scheduler on the cluster.
// +optional
PodSchedulerName string `json:"podSchedulerName,omitempty"`
// StartTimeoutSeconds determines the maximum duration (in seconds) that a workspace can take to start
// before it is automatically failed.
// If not specified, the default value of 300 seconds (5 minutes) is used.
// +optional
// +kubebuilder:validation:Minimum:=1
// +kubebuilder:default:=300
StartTimeoutSeconds *int32 `json:"startTimeoutSeconds,omitempty"`
}
// Che components configuration.

View File

@ -187,6 +187,11 @@ func (in *CheClusterDevEnvironments) DeepCopyInto(out *CheClusterDevEnvironments
*out = new(ContainerBuildConfiguration)
**out = **in
}
if in.StartTimeoutSeconds != nil {
in, out := &in.StartTimeoutSeconds, &out.StartTimeoutSeconds
*out = new(int32)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterDevEnvironments.

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.59.0-742.next
name: eclipse-che.v7.59.0-744.next
namespace: placeholder
spec:
apiservicedefinitions: {}
@ -1233,7 +1233,7 @@ spec:
minKubeVersion: 1.19.0
provider:
name: Eclipse Foundation
version: 7.59.0-742.next
version: 7.59.0-744.next
webhookdefinitions:
- admissionReviewVersions:
- v1

View File

@ -5410,6 +5410,7 @@ spec:
disableContainerBuildCapabilities: true
secondsOfInactivityBeforeIdling: 1800
secondsOfRunBeforeIdling: -1
startTimeoutSeconds: 300
storage:
pvcStrategy: per-user
description: Development environment default configuration options.
@ -7005,6 +7006,15 @@ spec:
maxLength: 63
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
type: string
startTimeoutSeconds:
default: 300
description: StartTimeoutSeconds determines the maximum duration
(in seconds) that a workspace can take to start before it
is automatically failed. If not specified, the default value
of 300 seconds (5 minutes) is used.
format: int32
minimum: 1
type: integer
storage:
default:
pvcStrategy: per-user

View File

@ -5271,6 +5271,7 @@ spec:
disableContainerBuildCapabilities: true
secondsOfInactivityBeforeIdling: 1800
secondsOfRunBeforeIdling: -1
startTimeoutSeconds: 300
storage:
pvcStrategy: per-user
description: Development environment default configuration options.
@ -6815,6 +6816,15 @@ spec:
maxLength: 63
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
type: string
startTimeoutSeconds:
default: 300
description: StartTimeoutSeconds determines the maximum duration
(in seconds) that a workspace can take to start before it is
automatically failed. If not specified, the default value of
300 seconds (5 minutes) is used.
format: int32
minimum: 1
type: integer
storage:
default:
pvcStrategy: per-user

View File

@ -5290,6 +5290,7 @@ spec:
disableContainerBuildCapabilities: true
secondsOfInactivityBeforeIdling: 1800
secondsOfRunBeforeIdling: -1
startTimeoutSeconds: 300
storage:
pvcStrategy: per-user
description: Development environment default configuration options.
@ -6834,6 +6835,15 @@ spec:
maxLength: 63
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
type: string
startTimeoutSeconds:
default: 300
description: StartTimeoutSeconds determines the maximum duration
(in seconds) that a workspace can take to start before it is
automatically failed. If not specified, the default value of
300 seconds (5 minutes) is used.
format: int32
minimum: 1
type: integer
storage:
default:
pvcStrategy: per-user

View File

@ -5285,6 +5285,7 @@ spec:
disableContainerBuildCapabilities: true
secondsOfInactivityBeforeIdling: 1800
secondsOfRunBeforeIdling: -1
startTimeoutSeconds: 300
storage:
pvcStrategy: per-user
description: Development environment default configuration options.
@ -6829,6 +6830,15 @@ spec:
maxLength: 63
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
type: string
startTimeoutSeconds:
default: 300
description: StartTimeoutSeconds determines the maximum duration
(in seconds) that a workspace can take to start before it is
automatically failed. If not specified, the default value of
300 seconds (5 minutes) is used.
format: int32
minimum: 1
type: integer
storage:
default:
pvcStrategy: per-user

View File

@ -5290,6 +5290,7 @@ spec:
disableContainerBuildCapabilities: true
secondsOfInactivityBeforeIdling: 1800
secondsOfRunBeforeIdling: -1
startTimeoutSeconds: 300
storage:
pvcStrategy: per-user
description: Development environment default configuration options.
@ -6834,6 +6835,15 @@ spec:
maxLength: 63
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
type: string
startTimeoutSeconds:
default: 300
description: StartTimeoutSeconds determines the maximum duration
(in seconds) that a workspace can take to start before it is
automatically failed. If not specified, the default value of
300 seconds (5 minutes) is used.
format: int32
minimum: 1
type: integer
storage:
default:
pvcStrategy: per-user

View File

@ -5285,6 +5285,7 @@ spec:
disableContainerBuildCapabilities: true
secondsOfInactivityBeforeIdling: 1800
secondsOfRunBeforeIdling: -1
startTimeoutSeconds: 300
storage:
pvcStrategy: per-user
description: Development environment default configuration options.
@ -6829,6 +6830,15 @@ spec:
maxLength: 63
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
type: string
startTimeoutSeconds:
default: 300
description: StartTimeoutSeconds determines the maximum duration
(in seconds) that a workspace can take to start before it is
automatically failed. If not specified, the default value of
300 seconds (5 minutes) is used.
format: int32
minimum: 1
type: integer
storage:
default:
pvcStrategy: per-user

View File

@ -5285,6 +5285,7 @@ spec:
disableContainerBuildCapabilities: true
secondsOfInactivityBeforeIdling: 1800
secondsOfRunBeforeIdling: -1
startTimeoutSeconds: 300
storage:
pvcStrategy: per-user
description: Development environment default configuration options.
@ -6829,6 +6830,15 @@ spec:
maxLength: 63
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
type: string
startTimeoutSeconds:
default: 300
description: StartTimeoutSeconds determines the maximum duration
(in seconds) that a workspace can take to start before it is
automatically failed. If not specified, the default value of
300 seconds (5 minutes) is used.
format: int32
minimum: 1
type: integer
storage:
default:
pvcStrategy: per-user

View File

@ -12,6 +12,11 @@
package constants
import (
corev1 "k8s.io/api/core/v1"
"k8s.io/utils/pointer"
)
const (
// PostgresSQL
DefaultPostgresUser = "pgche"
@ -139,4 +144,14 @@ var (
"app": "che",
"component": "che-gateway-config",
}
DefaultWorkspaceContainerSecurityContext = corev1.SecurityContext{
Capabilities: &corev1.Capabilities{
Add: []corev1.Capability{
"SETGID",
"SETUID",
},
},
AllowPrivilegeEscalation: pointer.BoolPtr(false),
}
)

View File

@ -12,6 +12,8 @@
package devworkspaceconfig
import (
"fmt"
controllerv1alpha1 "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1"
chev2 "github.com/eclipse-che/che-operator/api/v2"
"github.com/eclipse-che/che-operator/pkg/common/chetypes"
@ -56,7 +58,7 @@ func (d *DevWorkspaceConfigReconciler) Reconcile(ctx *chetypes.DeployContext) (r
dwoc.Config = &controllerv1alpha1.OperatorConfiguration{}
}
if err := updateWorkspaceConfig(&ctx.CheCluster.Spec.DevEnvironments, dwoc.Config); err != nil {
if err := updateWorkspaceConfig(ctx.CheCluster, dwoc.Config); err != nil {
return reconcile.Result{}, false, err
}
@ -71,7 +73,8 @@ func (d *DevWorkspaceConfigReconciler) Finalize(ctx *chetypes.DeployContext) boo
return true
}
func updateWorkspaceConfig(devEnvironments *chev2.CheClusterDevEnvironments, operatorConfig *controllerv1alpha1.OperatorConfiguration) error {
func updateWorkspaceConfig(cheCluster *chev2.CheCluster, operatorConfig *controllerv1alpha1.OperatorConfiguration) error {
devEnvironments := &cheCluster.Spec.DevEnvironments
if operatorConfig.Workspace == nil {
operatorConfig.Workspace = &controllerv1alpha1.WorkspaceConfig{}
}
@ -88,9 +91,24 @@ func updateWorkspaceConfig(devEnvironments *chev2.CheClusterDevEnvironments, ope
return err
}
operatorConfig.Workspace.ContainerSecurityContext = nil
if cheCluster.IsContainerBuildCapabilitiesEnabled() {
operatorConfig.Workspace.ContainerSecurityContext = constants.DefaultWorkspaceContainerSecurityContext.DeepCopy()
}
updateStartTimeout(operatorConfig, devEnvironments.StartTimeoutSeconds)
return nil
}
func updateStartTimeout(operatorConfig *controllerv1alpha1.OperatorConfiguration, startTimeoutSeconds *int32) {
if startTimeoutSeconds == nil {
// Allow the default start timeout of 5 minutes to be used if devEnvironments.StartTimeoutSeconds is unset
operatorConfig.Workspace.ProgressTimeout = ""
} else {
operatorConfig.Workspace.ProgressTimeout = fmt.Sprintf("%ds", *startTimeoutSeconds)
}
}
func updateWorkspaceStorageConfig(devEnvironments *chev2.CheClusterDevEnvironments, workspaceConfig *controllerv1alpha1.WorkspaceConfig) error {
pvcStrategy := utils.GetValue(devEnvironments.Storage.PvcStrategy, constants.DefaultPvcStorageStrategy)
isPerWorkspacePVCStorageStrategy := pvcStrategy == constants.PerWorkspacePVCStorageStrategy

View File

@ -17,6 +17,7 @@ import (
"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"
@ -325,7 +326,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
DefaultRoutingClass: "routing-class",
},
Workspace: &controllerv1alpha1.WorkspaceConfig{
ProgressTimeout: "10s",
ImagePullPolicy: "Always",
},
},
},
@ -335,7 +336,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
DefaultRoutingClass: "routing-class",
},
Workspace: &controllerv1alpha1.WorkspaceConfig{
ProgressTimeout: "10s",
ImagePullPolicy: "Always",
StorageClassName: pointer.StringPtr("test-storage"),
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity15Gi,
@ -343,6 +344,291 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
},
},
},
{
name: "Create DevWorkspaceOperatorConfig without Pod Security Context if container build disabled",
cheCluster: &chev2.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
Spec: chev2.CheClusterSpec{
DevEnvironments: chev2.CheClusterDevEnvironments{
DisableContainerBuildCapabilities: pointer.BoolPtr(true),
},
},
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{},
},
},
{
name: "Create DevWorkspaceOperatorConfig with Pod and Container Security Context if container build enabled",
cheCluster: &chev2.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
Spec: chev2.CheClusterSpec{
DevEnvironments: chev2.CheClusterDevEnvironments{
DisableContainerBuildCapabilities: pointer.BoolPtr(false),
},
},
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
ContainerSecurityContext: &corev1.SecurityContext{
Capabilities: &corev1.Capabilities{
Add: []corev1.Capability{
"SETGID",
"SETUID",
},
},
AllowPrivilegeEscalation: pointer.BoolPtr(false),
},
},
},
},
{
name: "Update existing DevWorkspaceOperatorConfig by adding Pod and Container Security Context",
cheCluster: &chev2.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
Spec: chev2.CheClusterSpec{
DevEnvironments: chev2.CheClusterDevEnvironments{
DisableContainerBuildCapabilities: pointer.BoolPtr(false),
},
},
},
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.StringPtr("default-storage-class"),
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity10Gi,
},
},
},
},
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
StorageClassName: pointer.StringPtr("default-storage-class"),
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity10Gi,
},
ContainerSecurityContext: &corev1.SecurityContext{
Capabilities: &corev1.Capabilities{
Add: []corev1.Capability{
"SETGID",
"SETUID",
},
},
AllowPrivilegeEscalation: pointer.BoolPtr(false),
},
},
},
},
{
name: "Update existing DevWorkspaceOperatorConfig by removing Pod and Container Security Context",
cheCluster: &chev2.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
Spec: chev2.CheClusterSpec{
DevEnvironments: chev2.CheClusterDevEnvironments{
DisableContainerBuildCapabilities: pointer.BoolPtr(true),
},
},
},
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.StringPtr("default-storage-class"),
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity10Gi,
},
ContainerSecurityContext: &corev1.SecurityContext{},
},
},
},
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
StorageClassName: pointer.StringPtr("default-storage-class"),
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity10Gi,
},
},
},
},
{
name: "Create DevWorkspaceOperatorConfig with progressTimeout",
cheCluster: &chev2.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
Spec: chev2.CheClusterSpec{
DevEnvironments: chev2.CheClusterDevEnvironments{
StartTimeoutSeconds: pointer.Int32Ptr(600),
},
},
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
ProgressTimeout: "600s",
},
},
},
{
name: "Update existing DevWorkspaceOperatorConfig by adding progressTimeout",
cheCluster: &chev2.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Name: "eclipse-che",
Namespace: "eclipse-che",
},
Spec: chev2.CheClusterSpec{
DevEnvironments: chev2.CheClusterDevEnvironments{
StartTimeoutSeconds: pointer.Int32Ptr(600),
},
},
},
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.StringPtr("default-storage-class"),
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity10Gi,
},
},
},
},
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
StorageClassName: pointer.StringPtr("default-storage-class"),
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity10Gi,
},
ProgressTimeout: "600s",
},
},
},
{
name: "Update existing DevWorkspaceOperatorConfig by overwriting progressTimeout",
cheCluster: &chev2.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
Spec: chev2.CheClusterSpec{
DevEnvironments: chev2.CheClusterDevEnvironments{
StartTimeoutSeconds: pointer.Int32Ptr(420),
},
},
},
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.StringPtr("default-storage-class"),
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity10Gi,
},
ProgressTimeout: "1h30m",
},
},
},
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
StorageClassName: pointer.StringPtr("default-storage-class"),
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity10Gi,
},
ProgressTimeout: "420s",
},
},
},
{
name: "Update existing DevWorkspaceOperatorConfig by removing progressTimeout",
cheCluster: &chev2.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
Spec: chev2.CheClusterSpec{
DevEnvironments: chev2.CheClusterDevEnvironments{},
},
},
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.StringPtr("default-storage-class"),
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity10Gi,
},
ProgressTimeout: "1h30m",
},
},
},
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
StorageClassName: pointer.StringPtr("default-storage-class"),
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity10Gi,
},
},
},
},
}
for _, testCase := range testCases {