Skip to content

Conversation

@tolusha
Copy link
Contributor

@tolusha tolusha commented Oct 9, 2025

What does this PR do?

This PR implements a retention mechanism for synchronized Kubernetes objects to prevent automatic deletion of PVCs and other resources in user namespaces when their source objects are removed. The implementation introduces a che.eclipse.org/sync-retain-on-delete annotation that allows objects to be retained in destination namespaces even when source objects are deleted.

Screenshot/screencast of this PR

N/A

What issues does this PR fix or reference?

eclipse-che/che#23569

How to test this PR?

  1. Deploy the operator (OpenShift): chectl server:deploy -p openshift --che-operator-image quay.io/abazko/che-operator:23569
  2. Log into Eclipse Che
  3. Define a user namespace name USER_NAMEPSACE=<..>
  4. Create PVC
oc apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test
  namespace: eclipse-che
  labels:
    app.kubernetes.io/part-of: che.eclipse.org
    app.kubernetes.io/component: workspaces-config
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 1Gi
EOF
  1. Ensure that pvc is created in a user namespace a well
$ oc get pvc -n $USER_NAMESPACE test
NAME      STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
test   Pending 
  1. Delete pvc from eclipse-che namespace oc delete pvc -n eclipse-che test
  2. Check that pvc still exists in the user namespace
$ oc get pvc -n $USER_NAMESPACE test
NAME      STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
test   Pending 
  1. Create a CM in eclipse-che namespace to sync into user namespace
oc apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: test
  namespace:  eclipse-che
  annotations:
    che.eclipse.org/sync-retain-on-delete: "true"
  labels:
    app.kubernetes.io/part-of: che.eclipse.org
    app.kubernetes.io/component: workspaces-config
EOF
  1. Check that CM exists in a user namespace
$ oc get configmaps -n $USER_NAMESPACE test
NAME   DATA   AGE
test   0      5s
  1. Delete CM from eclipse-che namespace oc delete configmaps -n eclipse-che test
  2. Check that CM still exists in a user namespace
$ oc get configmaps -n $USER_NAMESPACE test
NAME   DATA   AGE
test   0      5s

PR Checklist

As the author of this Pull Request I made sure that:

Reviewers

Reviewers, please comment how you tested the PR when approving it.

@openshift-ci
Copy link

openshift-ci bot commented Oct 9, 2025

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

Signed-off-by: Anatolii Bazko <[email protected]>
Signed-off-by: Anatolii Bazko <[email protected]>
@tolusha tolusha requested a review from Copilot October 10, 2025 10:28
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements a retention mechanism for synchronized Kubernetes objects to prevent automatic deletion of PVCs and other resources in user workspaces when their source objects are removed. The implementation introduces a che.eclipse.org/sync-retain annotation that allows objects to be retained in destination namespaces even when source objects are deleted.

  • Adds shouldRetain method to check retention annotation and default retention behavior
  • Implements defaultRetention() method across all Object2Sync types, with PVCs defaulting to true (retain by default)
  • Refactors object creation functions and improves error handling and logging

Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
controllers/workspaceconfig/workspaces_config_controller.go Core logic for retention checking and sync behavior modifications
controllers/workspaceconfig/pvc2sync.go PVC-specific sync implementation with default retention enabled
controllers/workspaceconfig/configmap2sync.go ConfigMap sync implementation with retention support
controllers/workspaceconfig/secret2sync.go Secret sync implementation with retention support
controllers/workspaceconfig/unstructured2sync.go Generic object sync with retention support
controllers/workspaceconfig/object2sync_factory.go Factory method refactoring for object creation
controllers/workspaceconfig/pvc2sync_test.go Test cases for PVC retention behavior
controllers/workspaceconfig/configmap2sync_test.go Test cases for ConfigMap retention behavior
controllers/workspaceconfig/unstructured2sync_test.go Test cases for unstructured object retention behavior

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@tolusha tolusha changed the title chore: do not remove synced users pvc chore: retention mechanism for synchronized Kubernetes objects Oct 10, 2025
Signed-off-by: Anatolii Bazko <[email protected]>
Signed-off-by: Anatolii Bazko <[email protected]>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

controllers/workspaceconfig/object2sync_factory.go:1

  • Relying on obj.GetObjectKind().GroupVersionKind() can return an empty GVK for typed objects fetched via client/scheme, causing all objects to fall through to unstructured2Sync. This breaks defaultRetention (e.g., PVCs should default to true) and may mis-handle sync behavior. Use a type switch on the concrete type instead of GVK, or explicitly set the GVK before switching. For example: switch o := obj.(type) { case *corev1.ConfigMap: return &configMap2Sync{cm:o} ... }.
//

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +715 to +740
// shouldRetain returns true if object in the destination namespace
// should be retained if source one is deleted.
func (r *WorkspacesConfigReconciler) shouldRetain(
ctx context.Context,
key client.ObjectKey,
gkv schema.GroupVersionKind,
clientWrapper *k8sclient.K8sClientWrapper,
) (bool, error) {
blueprint, err := r.scheme.New(gkv)
if err != nil {
return false, err
}

exists, err := clientWrapper.GetIgnoreNotFound(ctx, key, blueprint.(client.Object))
if !exists {
return false, err
}

retainOnDelete := blueprint.(metav1.Object).GetAnnotations()[syncRetainOnDeleteAnnotation]
if retainOnDelete != "" {
return strconv.ParseBool(retainOnDelete)
}

obj2Sync := createObject2SyncFromObject(blueprint.(client.Object))
return obj2Sync.defaultRetention(), nil
}
Copy link

Copilot AI Oct 13, 2025

Choose a reason for hiding this comment

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

If gkv is not registered in the scheme (e.g., CRDs synced as unstructured), r.scheme.New(gkv) returns an error and aborts reconciliation, preventing cleanup of obsolete records. Instead, fall back to an unstructured.Unstructured with SetGroupVersionKind(gvk) so GetIgnoreNotFound can proceed and retention defaults can be applied; use meta.Accessor to read annotations from both typed and unstructured objects.

Copilot uses AI. Check for mistakes.

retainOnDelete := blueprint.(metav1.Object).GetAnnotations()[syncRetainOnDeleteAnnotation]
if retainOnDelete != "" {
return strconv.ParseBool(retainOnDelete)
Copy link

Copilot AI Oct 13, 2025

Choose a reason for hiding this comment

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

Parsing an invalid boolean value here will bubble an error up and fail the reconcile. Consider treating invalid values as default (false) and logging a warning, so a mis-typed annotation doesn't block reconciliation.

Suggested change
return strconv.ParseBool(retainOnDelete)
val, err := strconv.ParseBool(retainOnDelete)
if err != nil {
fmt.Fprintf(os.Stderr, "Warning: invalid value for annotation %q on %s: %q. Defaulting to false.\n", syncRetainOnDeleteAnnotation, key.String(), retainOnDelete)
return false, nil
}
return val, nil

Copilot uses AI. Check for mistakes.
assert.Nil(t, err)
assertSyncConfig(t, workspaceConfigReconciler, 0, v1ConfigMapGKV)

// Check that destination ConfigMap in a user namespace NOT is deleted
Copy link

Copilot AI Oct 13, 2025

Choose a reason for hiding this comment

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

Grammar improvement.

Suggested change
// Check that destination ConfigMap in a user namespace NOT is deleted
// Check that destination ConfigMap in a user namespace is NOT deleted

Copilot uses AI. Check for mistakes.
@vinokurig vinokurig self-assigned this Oct 13, 2025
@openshift-ci
Copy link

openshift-ci bot commented Oct 13, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: akurinnoy, rohanKanojia, tolusha

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

@tolusha tolusha merged commit 19e9b35 into main Oct 15, 2025
21 checks passed
@tolusha tolusha deleted the 23569 branch October 15, 2025 08:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants