Skip to content

Conversation

@Allda
Copy link
Collaborator

@Allda Allda commented Jan 14, 2026

What does this PR do?

Add init container for workspace restoration

A new init container is added to the workspace deployment in case user choose to restore the workspace from backup.

By setting the workspace attribute "controller.devfile.io/restore-workspace" the controller sets a new init container instead of cloning data from git repository.

By default an automated path to restore image is used based on cluster settings. However user is capable overwrite that value using another attribute "controller.devfile.io/restore-source-image".

The restore container runs a wokspace-recovery.sh script that pull an image using oras an extract files to a /project directory.

What issues does this PR fix or reference?

#1525

Is it tested? How?

No automated tests are available in the first phase. I will add tests once I get the first approval that the concept is ok.

How to test:

  • Configure a cluster to enable backups
  • Create a new workspace and make changes in any of its files and save it.
  • Stop the workspace `kubectl patch devworkspace restore-workspace-2 --type=merge -p '{"spec": {"started": false}}'
  • Wait till it is stopped, and backup is executed for the workspace (verify the backup image exists in the registry)
  • Delete a workspace from cluster kubectl delete devworkspace restore-workspace-2
  • Add an attribute to the workspace CRD as shown below (controller.devfile.io/restore-workspace)
  • Create a workspace
  • Wait till it boots up and verify the changed file is present
kind: DevWorkspace
apiVersion: workspace.devfile.io/v1alpha2
metadata:
  labels:
    controller.devfile.io/creator: ""
  name: restore-workspace-2
spec:
  started: true
  routingClass: 'basic'
  template:
    attributes:
      controller.devfile.io/storage-type: common
      controller.devfile.io/restore-workspace: 'true'

PR Checklist

  • E2E tests pass (when PR is ready, comment /test v8-devworkspace-operator-e2e, v8-che-happy-path to trigger)
    • v8-devworkspace-operator-e2e: DevWorkspace e2e test
    • v8-che-happy-path: Happy path for verification integration with Che

What's missing:

  • integration with registry authentication
  • integration with build in OCP registry

@openshift-ci
Copy link

openshift-ci bot commented Jan 14, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: Allda
Once this PR has been reviewed and has the lgtm label, please assign dkwon17 for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

) (*corev1.Container, error) {
wokrspaceTempplate := &workspace.Spec.Template
// Check if restore is requested via workspace attribute
if !wokrspaceTempplate.Attributes.Exists(constants.WorkspaceRestoreAttribute) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO I think it would be more readable if this check was done by the caller in devworkspace_controller.go

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the example presented in the Is it tested? How? section of this PR, the example has:

controller.devfile.io/restore-workspace: 'true'

which made me assume that:

controller.devfile.io/restore-workspace: 'false'

would disable the restore functionality for the devworkspace.

Could we also check for "false" string here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I extracted the condition and moved it to the controller itself to make the code path easier to read. I also enhanced the logic to recognize the attribute value. The new test verifies that setting a value to false skips the restore container.

Allda added 4 commits January 16, 2026 09:56
A new init container is added to the workspace deployment in case user
choose to restore the workspace from backup.

By setting workspace attribute "controller.devfile.io/restore-workspace"
the controller sets a new init container instead of cloning data from
git repository.

By default an automated path to restore image is used based on cluster
settings. However user is capable overwrite that value using another
attribute "controller.devfile.io/restore-source-image".

The restore container runs a wokspace-recovery.sh script that pull an
image using oras an extract files to a /project directory.

Signed-off-by: Ales Raszka <araszka@redhat.com>
A new tests that verifies the workspace is created from a backup. It
checks if a deployment is ready and if it contains a new restore init
container with proper configuration.

There are 2 tests - one focused on common pvc and other that have
per-workspace storage.

Signed-off-by: Ales Raszka <araszka@redhat.com>
The condition whether an workspace should be restored from workspace was
in the restore module itself. This make a reading a code more difficult.
Now the condition is checked in the controller itself and restore
container is only added when enabled.

This commit also fixes few minor changes based on the code review
comments:
- Licence header
- Attribute validation
- Add a test for disabled workspace recovery
- Typos

Signed-off-by: Ales Raszka <araszka@redhat.com>
A new config is added to control the restore container. Default values
are set for the new init container. It can be changed by user in the
config. The config uses same logic as the project clone container
config.

Signed-off-by: Ales Raszka <araszka@redhat.com>
BackupCronJob: &controllerv1alpha1.BackupCronJobConfig{
Enable: ptr.To[bool](true),
Registry: &controllerv1alpha1.RegistryConfig{
Path: "localhost:5000",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkwon17 For the purposes of the integration tests, I need a valid backup container somewhere in a registry (the container could be empty with vely low size) to be able start and successfully execute the restore container. What would be the best place to upload it?

To verify the tests works I used my local registry, but that's not an option for running it outside of the localhost.

options Options,
log logr.Logger,
) (*corev1.Container, error) {
wokrspaceTempplate := &workspace.Spec.Template
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
wokrspaceTempplate := &workspace.Spec.Template
workspaceTemplate := &workspace.Spec.Template


resources := dwResources.FilterResources(options.Resources)
if err := dwResources.ValidateResources(resources); err != nil {
return nil, fmt.Errorf("invalid resources for project clone container: %w", err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return nil, fmt.Errorf("invalid resources for project clone container: %w", err)
return nil, fmt.Errorf("invalid resources for workspace restore container: %w", err)

Comment on lines +57 to +63
func GetWorkspaceRestoreInitContainer(
ctx context.Context,
workspace *common.DevWorkspaceWithConfig,
k8sClient client.Client,
options Options,
log logr.Logger,
) (*corev1.Container, error) {
Copy link
Member

@rohanKanojia rohanKanojia Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe cleanup unused arguments if not required for future purposes (please add TODO if that's the case)

Suggested change
func GetWorkspaceRestoreInitContainer(
ctx context.Context,
workspace *common.DevWorkspaceWithConfig,
k8sClient client.Client,
options Options,
log logr.Logger,
) (*corev1.Container, error) {
func GetWorkspaceRestoreInitContainer(
workspace *common.DevWorkspaceWithConfig,
options Options,
) (*corev1.Container, error) {

Comment on lines +50 to +51
enableRecovery := workspace.Attributes.GetBoolean(constants.WorkspaceRestoreAttribute, nil)
return enableRecovery
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps it can be inlined?

Suggested change
enableRecovery := workspace.Attributes.GetBoolean(constants.WorkspaceRestoreAttribute, nil)
return enableRecovery
return workspace.Attributes.GetBoolean(constants.WorkspaceRestoreAttribute, nil)

return nil, fmt.Errorf("workspace restore requested but backup cron job registry is not configured")
}
// Use default backup image location based on workspace info
restoreSourceImage = workspace.Config.Workspace.BackupCronJob.Registry.Path + "/" + workspace.Namespace + "/" + workspace.Name + ":latest"
Copy link
Member

@rohanKanojia rohanKanojia Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will the default backup image always have latest tag ? This can make restores non-deterministic and harder to debug or roll back if the image changes unexpectedly.

Comment on lines +155 to +160
// WorkspaceRestoreAttribute defines whether workspace restore should be performed for a DevWorkspace.
// If this attribute is present, the restore process will be performed during workspace
// initialization before the workspace containers start.

// The backup source is automatically determined from the cluster configuration or can be overridden
// by specifying the WorkspaceRestoreSourceImageAttribute.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// WorkspaceRestoreAttribute defines whether workspace restore should be performed for a DevWorkspace.
// If this attribute is present, the restore process will be performed during workspace
// initialization before the workspace containers start.
// The backup source is automatically determined from the cluster configuration or can be overridden
// by specifying the WorkspaceRestoreSourceImageAttribute.
// WorkspaceRestoreAttribute defines whether workspace restore should be performed for a DevWorkspace.
// If this attribute is present and set to true, the restore process will be performed during
// workspace initialization, before workspace containers start.
//
// The backup source is automatically determined from the cluster configuration unless overridden
// by WorkspaceRestoreSourceImageAttribute.

})
defer config.SetGlobalConfigForTesting(nil)
By("Reading DevWorkspace with restore configuration from testdata file")
createDevWorkspace(devWorkspaceName, "restore-workspace-disabled.yaml")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no file named restore-workspace-disabled.yaml in testdata/

}

type RestoreConfig struct {
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`
// ImagePullPolicy configures the imagePullPolicy for the restore clone container.
// If undefined, the general setting .config.workspace.imagePullPolicy is used instead.
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants