-
Notifications
You must be signed in to change notification settings - Fork 97
chore: retention mechanism for synchronized Kubernetes objects #2052
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Signed-off-by: Anatolii Bazko <[email protected]>
|
Skipping CI for Draft Pull Request. |
Signed-off-by: Anatolii Bazko <[email protected]>
Signed-off-by: Anatolii Bazko <[email protected]>
There was a problem hiding this 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
shouldRetainmethod 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.
Signed-off-by: Anatolii Bazko <[email protected]>
Signed-off-by: Anatolii Bazko <[email protected]>
There was a problem hiding this 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.
| // 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 | ||
| } |
Copilot
AI
Oct 13, 2025
There was a problem hiding this comment.
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.
|
|
||
| retainOnDelete := blueprint.(metav1.Object).GetAnnotations()[syncRetainOnDeleteAnnotation] | ||
| if retainOnDelete != "" { | ||
| return strconv.ParseBool(retainOnDelete) |
Copilot
AI
Oct 13, 2025
There was a problem hiding this comment.
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.
| 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 |
| assert.Nil(t, err) | ||
| assertSyncConfig(t, workspaceConfigReconciler, 0, v1ConfigMapGKV) | ||
|
|
||
| // Check that destination ConfigMap in a user namespace NOT is deleted |
Copilot
AI
Oct 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Grammar improvement.
| // Check that destination ConfigMap in a user namespace NOT is deleted | |
| // Check that destination ConfigMap in a user namespace is NOT deleted |
|
[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. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
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-deleteannotation 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?
chectl server:deploy -p openshift --che-operator-image quay.io/abazko/che-operator:23569USER_NAMEPSACE=<..>oc delete pvc -n eclipse-che testoc delete configmaps -n eclipse-che testPR Checklist
As the author of this Pull Request I made sure that:
What issues does this PR fix or referenceandHow to test this PRcompletedReviewers
Reviewers, please comment how you tested the PR when approving it.