feat: configure workspace deployment strategy with CheCluster CR (#1666)

* feat: configure workspace deployment strategy with CheCluster CR

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

* chore: add tests for configuring workspace deployment strategy

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

* chore: update dev resources for devEnvironments.DeploymentStrategy

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

---------

Signed-off-by: Andrew Obuchowicz <aobuchow@redhat.com>
pull/1671/head
Andrew O 2023-04-25 01:43:55 -04:00 committed by GitHub
parent 4bcc78a27a
commit a98d18233e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 269 additions and 14 deletions

View File

@ -31,6 +31,7 @@ import (
imagepullerv1alpha1 "github.com/che-incubator/kubernetes-image-puller-operator/api/v1alpha1"
devfile "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@ -137,6 +138,15 @@ type CheClusterDevEnvironments struct {
// +kubebuilder:validation:Minimum:=1
// +kubebuilder:default:=300
StartTimeoutSeconds *int32 `json:"startTimeoutSeconds,omitempty"`
// DeploymentStrategy defines the deployment strategy to use to replace existing workspace pods
// with new ones. The available deployment stragies are `Recreate` and `RollingUpdate`.
// With the `Recreate` deployment strategy, the existing workspace pod is killed before the new one is created.
// With the `RollingUpdate` deployment strategy, a new workspace pod is created and the existing workspace pod is deleted
// only when the new workspace pod is in a ready state.
// If not specified, the default `Recreate` deployment strategy is used.
// +optional
// +kubebuilder:validation:Enum=Recreate;RollingUpdate
DeploymentStrategy appsv1.DeploymentStrategyType `json:"deploymentStrategy,omitempty"`
// Total number of workspaces, both stopped and running, that a user can keep.
// The value, -1, allows users to keep an unlimited number of workspaces.
// +kubebuilder:validation:Minimum:=-1

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.65.0-789.next
name: eclipse-che.v7.66.0-790.next
namespace: placeholder
spec:
apiservicedefinitions: {}
@ -1243,7 +1243,7 @@ spec:
minKubeVersion: 1.19.0
provider:
name: Eclipse Foundation
version: 7.65.0-789.next
version: 7.66.0-790.next
webhookdefinitions:
- admissionReviewVersions:
- v1

View File

@ -7044,6 +7044,20 @@ spec:
type: array
type: object
type: array
deploymentStrategy:
description: DeploymentStrategy defines the deployment strategy
to use to replace existing workspace pods with new ones. The
available deployment stragies are `Recreate` and `RollingUpdate`.
With the `Recreate` deployment strategy, the existing workspace
pod is killed before the new one is created. With the `RollingUpdate`
deployment strategy, a new workspace pod is created and the
existing workspace pod is deleted only when the new workspace
pod is in a ready state. If not specified, the default `Recreate`
deployment strategy is used.
enum:
- Recreate
- RollingUpdate
type: string
disableContainerBuildCapabilities:
description: Disables the container build capabilities.
type: boolean

View File

@ -6849,6 +6849,20 @@ spec:
type: array
type: object
type: array
deploymentStrategy:
description: DeploymentStrategy defines the deployment strategy
to use to replace existing workspace pods with new ones. The
available deployment stragies are `Recreate` and `RollingUpdate`.
With the `Recreate` deployment strategy, the existing workspace
pod is killed before the new one is created. With the `RollingUpdate`
deployment strategy, a new workspace pod is created and the
existing workspace pod is deleted only when the new workspace
pod is in a ready state. If not specified, the default `Recreate`
deployment strategy is used.
enum:
- Recreate
- RollingUpdate
type: string
disableContainerBuildCapabilities:
description: Disables the container build capabilities.
type: boolean

View File

@ -6868,6 +6868,20 @@ spec:
type: array
type: object
type: array
deploymentStrategy:
description: DeploymentStrategy defines the deployment strategy
to use to replace existing workspace pods with new ones. The
available deployment stragies are `Recreate` and `RollingUpdate`.
With the `Recreate` deployment strategy, the existing workspace
pod is killed before the new one is created. With the `RollingUpdate`
deployment strategy, a new workspace pod is created and the
existing workspace pod is deleted only when the new workspace
pod is in a ready state. If not specified, the default `Recreate`
deployment strategy is used.
enum:
- Recreate
- RollingUpdate
type: string
disableContainerBuildCapabilities:
description: Disables the container build capabilities.
type: boolean

View File

@ -6863,6 +6863,20 @@ spec:
type: array
type: object
type: array
deploymentStrategy:
description: DeploymentStrategy defines the deployment strategy
to use to replace existing workspace pods with new ones. The
available deployment stragies are `Recreate` and `RollingUpdate`.
With the `Recreate` deployment strategy, the existing workspace
pod is killed before the new one is created. With the `RollingUpdate`
deployment strategy, a new workspace pod is created and the
existing workspace pod is deleted only when the new workspace
pod is in a ready state. If not specified, the default `Recreate`
deployment strategy is used.
enum:
- Recreate
- RollingUpdate
type: string
disableContainerBuildCapabilities:
description: Disables the container build capabilities.
type: boolean

View File

@ -6868,6 +6868,20 @@ spec:
type: array
type: object
type: array
deploymentStrategy:
description: DeploymentStrategy defines the deployment strategy
to use to replace existing workspace pods with new ones. The
available deployment stragies are `Recreate` and `RollingUpdate`.
With the `Recreate` deployment strategy, the existing workspace
pod is killed before the new one is created. With the `RollingUpdate`
deployment strategy, a new workspace pod is created and the
existing workspace pod is deleted only when the new workspace
pod is in a ready state. If not specified, the default `Recreate`
deployment strategy is used.
enum:
- Recreate
- RollingUpdate
type: string
disableContainerBuildCapabilities:
description: Disables the container build capabilities.
type: boolean

View File

@ -6863,6 +6863,20 @@ spec:
type: array
type: object
type: array
deploymentStrategy:
description: DeploymentStrategy defines the deployment strategy
to use to replace existing workspace pods with new ones. The
available deployment stragies are `Recreate` and `RollingUpdate`.
With the `Recreate` deployment strategy, the existing workspace
pod is killed before the new one is created. With the `RollingUpdate`
deployment strategy, a new workspace pod is created and the
existing workspace pod is deleted only when the new workspace
pod is in a ready state. If not specified, the default `Recreate`
deployment strategy is used.
enum:
- Recreate
- RollingUpdate
type: string
disableContainerBuildCapabilities:
description: Disables the container build capabilities.
type: boolean

View File

@ -6863,6 +6863,20 @@ spec:
type: array
type: object
type: array
deploymentStrategy:
description: DeploymentStrategy defines the deployment strategy
to use to replace existing workspace pods with new ones. The
available deployment stragies are `Recreate` and `RollingUpdate`.
With the `Recreate` deployment strategy, the existing workspace
pod is killed before the new one is created. With the `RollingUpdate`
deployment strategy, a new workspace pod is created and the
existing workspace pod is deleted only when the new workspace
pod is in a ready state. If not specified, the default `Recreate`
deployment strategy is used.
enum:
- Recreate
- RollingUpdate
type: string
disableContainerBuildCapabilities:
description: Disables the container build capabilities.
type: boolean

View File

@ -99,6 +99,7 @@ const (
PerWorkspacePVCStorageStrategy = "per-workspace"
EphemeralPVCStorageStrategy = "ephemeral"
CommonPVCStorageStrategy = "common"
DefaultDeploymentStrategy = "Recreate"
DefaultAutoProvision = true
DefaultWorkspaceJavaOpts = "-XX:MaxRAM=150m -XX:MaxRAMFraction=2 -XX:+UseParallelGC " +
"-XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 " +

View File

@ -20,6 +20,7 @@ import (
"github.com/eclipse-che/che-operator/pkg/common/constants"
"github.com/eclipse-che/che-operator/pkg/common/utils"
"github.com/eclipse-che/che-operator/pkg/deploy"
v1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/pointer"
@ -97,6 +98,8 @@ func updateWorkspaceConfig(cheCluster *chev2.CheCluster, operatorConfig *control
}
updateStartTimeout(operatorConfig, devEnvironments.StartTimeoutSeconds)
operatorConfig.Workspace.DeploymentStrategy = v1.DeploymentStrategyType(utils.GetValue(string(devEnvironments.DeploymentStrategy), constants.DefaultDeploymentStrategy))
return nil
}

View File

@ -91,7 +91,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
},
},
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{Workspace: &controllerv1alpha1.WorkspaceConfig{}},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{Workspace: &controllerv1alpha1.WorkspaceConfig{DeploymentStrategy: "Recreate"}},
},
{
name: "Create DevWorkspaceOperatorConfig with ephemeral strategy",
@ -117,7 +117,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
},
},
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{Workspace: &controllerv1alpha1.WorkspaceConfig{}},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{Workspace: &controllerv1alpha1.WorkspaceConfig{DeploymentStrategy: "Recreate"}},
},
{
name: "Create DevWorkspaceOperatorConfig with StorageClassName only",
@ -140,7 +140,8 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
StorageClassName: pointer.StringPtr("test-storage"),
StorageClassName: pointer.StringPtr("test-storage"),
DeploymentStrategy: "Recreate",
},
},
},
@ -170,6 +171,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity15Gi,
},
DeploymentStrategy: "Recreate",
},
},
},
@ -199,6 +201,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
PerWorkspace: &quantity15Gi,
},
DeploymentStrategy: "Recreate",
},
},
},
@ -248,6 +251,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
PerWorkspace: &quantity15Gi,
},
DeploymentStrategy: "Recreate",
},
},
},
@ -297,6 +301,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity15Gi,
},
DeploymentStrategy: "Recreate",
},
},
},
@ -350,6 +355,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity15Gi,
},
DeploymentStrategy: "Recreate",
},
},
},
@ -367,7 +373,9 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
},
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{},
Workspace: &controllerv1alpha1.WorkspaceConfig{
DeploymentStrategy: "Recreate",
},
},
},
{
@ -394,6 +402,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
},
AllowPrivilegeEscalation: pointer.BoolPtr(true),
},
DeploymentStrategy: "Recreate",
},
},
},
@ -445,6 +454,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
},
AllowPrivilegeEscalation: pointer.BoolPtr(true),
},
DeploymentStrategy: "Recreate",
},
},
},
@ -478,6 +488,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
Common: &quantity10Gi,
},
ContainerSecurityContext: &corev1.SecurityContext{},
DeploymentStrategy: "Recreate",
},
},
},
@ -488,6 +499,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity10Gi,
},
DeploymentStrategy: "Recreate",
},
},
},
@ -507,7 +519,8 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
ProgressTimeout: "600s",
ProgressTimeout: "600s",
DeploymentStrategy: "Recreate",
},
},
},
@ -551,7 +564,8 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity10Gi,
},
ProgressTimeout: "600s",
ProgressTimeout: "600s",
DeploymentStrategy: "Recreate",
},
},
},
@ -596,7 +610,8 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity10Gi,
},
ProgressTimeout: "420s",
ProgressTimeout: "420s",
DeploymentStrategy: "Recreate",
},
},
},
@ -640,6 +655,7 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) {
DefaultStorageSize: &controllerv1alpha1.StorageSizes{
Common: &quantity10Gi,
},
DeploymentStrategy: "Recreate",
},
},
},
@ -703,6 +719,7 @@ func TestReconcileServiceAccountConfig(t *testing.T) {
ServiceAccountName: "service-account",
DisableCreation: pointer.BoolPtr(false),
},
DeploymentStrategy: "Recreate",
},
},
},
@ -728,6 +745,7 @@ func TestReconcileServiceAccountConfig(t *testing.T) {
ServiceAccountName: "service-account",
DisableCreation: pointer.BoolPtr(true),
},
DeploymentStrategy: "Recreate",
},
},
},
@ -747,6 +765,7 @@ func TestReconcileServiceAccountConfig(t *testing.T) {
ServiceAccount: &controllerv1alpha1.ServiceAccountConfig{
DisableCreation: pointer.BoolPtr(false),
},
DeploymentStrategy: "Recreate",
},
},
},
@ -770,6 +789,7 @@ func TestReconcileServiceAccountConfig(t *testing.T) {
ServiceAccount: &controllerv1alpha1.ServiceAccountConfig{
DisableCreation: pointer.BoolPtr(false),
},
DeploymentStrategy: "Recreate",
},
},
},
@ -817,7 +837,8 @@ func TestReconcileDevWorkspaceConfigPodSchedulerName(t *testing.T) {
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
SchedulerName: "test-scheduler",
SchedulerName: "test-scheduler",
DeploymentStrategy: "Recreate",
},
},
},
@ -848,7 +869,8 @@ func TestReconcileDevWorkspaceConfigPodSchedulerName(t *testing.T) {
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
SchedulerName: "test-scheduler",
SchedulerName: "test-scheduler",
DeploymentStrategy: "Recreate",
},
},
},
@ -884,7 +906,8 @@ func TestReconcileDevWorkspaceConfigPodSchedulerName(t *testing.T) {
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
SchedulerName: "test-scheduler",
SchedulerName: "test-scheduler",
DeploymentStrategy: "Recreate",
},
},
},
@ -919,7 +942,9 @@ func TestReconcileDevWorkspaceConfigPodSchedulerName(t *testing.T) {
},
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{},
Workspace: &controllerv1alpha1.WorkspaceConfig{
DeploymentStrategy: "Recreate",
},
},
},
}
@ -993,6 +1018,7 @@ func TestReconcileDevWorkspaceConfigServiceAccountTokens(t *testing.T) {
ExpirationSeconds: 180,
},
}},
DeploymentStrategy: "Recreate",
},
},
},
@ -1052,6 +1078,7 @@ func TestReconcileDevWorkspaceConfigServiceAccountTokens(t *testing.T) {
},
},
},
DeploymentStrategy: "Recreate",
},
},
},
@ -1113,6 +1140,7 @@ func TestReconcileDevWorkspaceConfigServiceAccountTokens(t *testing.T) {
},
},
},
DeploymentStrategy: "Recreate",
},
},
},
@ -1163,7 +1191,8 @@ func TestReconcileDevWorkspaceConfigServiceAccountTokens(t *testing.T) {
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
ServiceAccount: &controllerv1alpha1.ServiceAccountConfig{},
ServiceAccount: &controllerv1alpha1.ServiceAccountConfig{},
DeploymentStrategy: "Recreate",
},
},
},
@ -1185,3 +1214,117 @@ func TestReconcileDevWorkspaceConfigServiceAccountTokens(t *testing.T) {
})
}
}
func TestReconcileDevWorkspaceConfigDeploymentStrategy(t *testing.T) {
type testCase struct {
name string
cheCluster *chev2.CheCluster
existedObjects []runtime.Object
expectedOperatorConfig *controllerv1alpha1.OperatorConfiguration
}
var testCases = []testCase{
{
name: "Create DevWorkspaceOperatorConfig with DeploymentStrategy",
cheCluster: &chev2.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
Spec: chev2.CheClusterSpec{
DevEnvironments: chev2.CheClusterDevEnvironments{
DeploymentStrategy: "Recreate",
},
},
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
DeploymentStrategy: "Recreate",
},
},
},
{
name: "Update existing DevWorkspaceOperatorConfig when DeploymentStrategy is added",
cheCluster: &chev2.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
Spec: chev2.CheClusterSpec{
DevEnvironments: chev2.CheClusterDevEnvironments{
DeploymentStrategy: "Recreate",
},
},
},
existedObjects: []runtime.Object{
&controllerv1alpha1.DevWorkspaceOperatorConfig{
ObjectMeta: metav1.ObjectMeta{
Name: devWorkspaceConfigName,
Namespace: "eclipse-che",
},
TypeMeta: metav1.TypeMeta{
Kind: "DevWorkspaceOperatorConfig",
APIVersion: controllerv1alpha1.GroupVersion.String(),
},
},
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
DeploymentStrategy: "Recreate",
},
},
},
{
name: "Update existing DevWorkspaceOperatorConfig when DeploymentStrategy is changed",
cheCluster: &chev2.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
Spec: chev2.CheClusterSpec{
DevEnvironments: chev2.CheClusterDevEnvironments{
DeploymentStrategy: "RollingUpdate",
},
},
},
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{
DeploymentStrategy: "Recreate",
},
},
},
},
expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{
Workspace: &controllerv1alpha1.WorkspaceConfig{
DeploymentStrategy: "RollingUpdate",
},
},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
deployContext := test.GetDeployContext(testCase.cheCluster, []runtime.Object{})
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: testCase.cheCluster.Namespace}, dwoc)
assert.NoError(t, err)
assert.Equal(t, testCase.expectedOperatorConfig.Workspace.DeploymentStrategy, dwoc.Config.Workspace.DeploymentStrategy)
})
}
}