Skip to content

Commit 5183198

Browse files
authored
fix: Recreate non cached object in a user namespace (#2001)
* fix: Recreate non cached object in a user namespace Signed-off-by: Anatolii Bazko <abazko@redhat.com>
1 parent 8094056 commit 5183198

File tree

10 files changed

+357
-242
lines changed

10 files changed

+357
-242
lines changed

controllers/usernamespace/configmap2sync_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2019-2024 Red Hat, Inc.
2+
// Copyright (c) 2019-2025 Red Hat, Inc.
33
// This program and the accompanying materials are made
44
// available under the terms of the Eclipse Public License 2.0
55
// which is available at https://www.eclipse.org/legal/epl-2.0/
@@ -69,6 +69,7 @@ func TestSyncConfigMap(t *testing.T) {
6969
}})
7070

7171
workspaceConfigReconciler := NewWorkspacesConfigReconciler(
72+
deployContext.ClusterAPI.Client,
7273
deployContext.ClusterAPI.Client,
7374
deployContext.ClusterAPI.Scheme,
7475
&namespaceCache{
@@ -235,6 +236,7 @@ func TestSyncConfigMapShouldMergeLabelsAndAnnotationsOnUpdate(t *testing.T) {
235236
}})
236237

237238
workspaceConfigReconciler := NewWorkspacesConfigReconciler(
239+
deployContext.ClusterAPI.Client,
238240
deployContext.ClusterAPI.Client,
239241
deployContext.ClusterAPI.Scheme,
240242
&namespaceCache{
@@ -352,6 +354,7 @@ func TestSyncConfigMapShouldRespectDWOLabels(t *testing.T) {
352354
}})
353355

354356
workspaceConfigReconciler := NewWorkspacesConfigReconciler(
357+
deployContext.ClusterAPI.Client,
355358
deployContext.ClusterAPI.Client,
356359
deployContext.ClusterAPI.Scheme,
357360
&namespaceCache{
@@ -449,6 +452,7 @@ func TestSyncConfigMapShouldRemoveSomeLabels(t *testing.T) {
449452
}})
450453

451454
workspaceConfigReconciler := NewWorkspacesConfigReconciler(
455+
deployContext.ClusterAPI.Client,
452456
deployContext.ClusterAPI.Client,
453457
deployContext.ClusterAPI.Scheme,
454458
&namespaceCache{

controllers/usernamespace/pvc2sync_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2019-2024 Red Hat, Inc.
2+
// Copyright (c) 2019-2025 Red Hat, Inc.
33
// This program and the accompanying materials are made
44
// available under the terms of the Eclipse Public License 2.0
55
// which is available at https://www.eclipse.org/legal/epl-2.0/
@@ -56,6 +56,7 @@ func TestSyncPVC(t *testing.T) {
5656
}})
5757

5858
workspaceConfigReconciler := NewWorkspacesConfigReconciler(
59+
deployContext.ClusterAPI.Client,
5960
deployContext.ClusterAPI.Client,
6061
deployContext.ClusterAPI.Scheme,
6162
&namespaceCache{

controllers/usernamespace/secret2sync_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2019-2024 Red Hat, Inc.
2+
// Copyright (c) 2019-2025 Red Hat, Inc.
33
// This program and the accompanying materials are made
44
// available under the terms of the Eclipse Public License 2.0
55
// which is available at https://www.eclipse.org/legal/epl-2.0/
@@ -60,6 +60,7 @@ func TestSyncSecrets(t *testing.T) {
6060
}})
6161

6262
workspaceConfigReconciler := NewWorkspacesConfigReconciler(
63+
deployContext.ClusterAPI.Client,
6364
deployContext.ClusterAPI.Client,
6465
deployContext.ClusterAPI.Scheme,
6566
&namespaceCache{
@@ -235,6 +236,7 @@ func TestSyncSecretShouldMergeLabelsAndAnnotationsOnUpdate(t *testing.T) {
235236
}})
236237

237238
workspaceConfigReconciler := NewWorkspacesConfigReconciler(
239+
deployContext.ClusterAPI.Client,
238240
deployContext.ClusterAPI.Client,
239241
deployContext.ClusterAPI.Scheme,
240242
&namespaceCache{
@@ -341,6 +343,7 @@ func TestSyncSecretShouldRespectDWOLabels(t *testing.T) {
341343
}})
342344

343345
workspaceConfigReconciler := NewWorkspacesConfigReconciler(
346+
deployContext.ClusterAPI.Client,
344347
deployContext.ClusterAPI.Client,
345348
deployContext.ClusterAPI.Scheme,
346349
&namespaceCache{
@@ -439,6 +442,7 @@ func TestSyncSecretShouldRemoveSomeLabels(t *testing.T) {
439442
}})
440443

441444
workspaceConfigReconciler := NewWorkspacesConfigReconciler(
445+
deployContext.ClusterAPI.Client,
442446
deployContext.ClusterAPI.Client,
443447
deployContext.ClusterAPI.Scheme,
444448
&namespaceCache{

controllers/usernamespace/unstructured2sync_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2019-2024 Red Hat, Inc.
2+
// Copyright (c) 2019-2025 Red Hat, Inc.
33
// This program and the accompanying materials are made
44
// available under the terms of the Eclipse Public License 2.0
55
// which is available at https://www.eclipse.org/legal/epl-2.0/
@@ -82,6 +82,7 @@ func TestSyncTemplateWithLimitRange(t *testing.T) {
8282
}})
8383

8484
workspaceConfigReconciler := NewWorkspacesConfigReconciler(
85+
deployContext.ClusterAPI.Client,
8586
deployContext.ClusterAPI.Client,
8687
deployContext.ClusterAPI.Scheme,
8788
&namespaceCache{

controllers/usernamespace/workspaces_config_controller.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2019-2024 Red Hat, Inc.
2+
// Copyright (c) 2019-2025 Red Hat, Inc.
33
// This program and the accompanying materials are made
44
// available under the terms of the Eclipse Public License 2.0
55
// which is available at https://www.eclipse.org/legal/epl-2.0/
@@ -50,6 +50,7 @@ const (
5050
type WorkspacesConfigReconciler struct {
5151
scheme *runtime.Scheme
5252
client client.Client
53+
nonCachedClient client.Client
5354
namespaceCache *namespaceCache
5455
labelsToRemoveBeforeSync []*regexp.Regexp
5556
annotationsToRemoveBeforeSync []*regexp.Regexp
@@ -87,6 +88,7 @@ var (
8788

8889
func NewWorkspacesConfigReconciler(
8990
client client.Client,
91+
nonCachedClient client.Client,
9092
scheme *runtime.Scheme,
9193
namespaceCache *namespaceCache) *WorkspacesConfigReconciler {
9294

@@ -112,6 +114,7 @@ func NewWorkspacesConfigReconciler(
112114
return &WorkspacesConfigReconciler{
113115
scheme: scheme,
114116
client: client,
117+
nonCachedClient: nonCachedClient,
115118
namespaceCache: namespaceCache,
116119
labelsToRemoveBeforeSync: labelsToRemoveBeforeSync,
117120
annotationsToRemoveBeforeSync: annotationsToRemoveBeforeSync,
@@ -520,14 +523,35 @@ func (r *WorkspacesConfigReconciler) doCreateObject(
520523
syncContext *syncContext,
521524
dstObj client.Object) error {
522525

523-
if err := r.client.Create(syncContext.ctx, dstObj); err != nil {
524-
return err
526+
err := r.client.Create(syncContext.ctx, dstObj)
527+
if err != nil {
528+
if !errors.IsAlreadyExists(err) {
529+
return err
530+
}
531+
532+
// AlreadyExists Error might happen if object already exists and doesn't contain
533+
// `app.kubernetes.io/part-of=che.eclipse.org` label (is not cached)
534+
// 1. Delete the object from a destination namespace using non-cached client
535+
// 2. Create the object again using cached client
536+
if err = deploy.DeleteIgnoreIfNotFound(
537+
syncContext.ctx,
538+
r.nonCachedClient,
539+
types.NamespacedName{
540+
Name: dstObj.GetName(),
541+
Namespace: dstObj.GetNamespace(),
542+
},
543+
dstObj); err != nil {
544+
return err
545+
}
546+
547+
if err = r.client.Create(syncContext.ctx, dstObj); err != nil {
548+
return err
549+
}
525550
}
526551

527552
logger.Info("Object created", "namespace", dstObj.GetNamespace(),
528553
"kind", gvk2PrintString(syncContext.object2Sync.getGKV()),
529554
"name", dstObj.GetName())
530-
531555
return nil
532556
}
533557

controllers/usernamespace/workspaces_config_controller_test.go

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2019-2024 Red Hat, Inc.
2+
// Copyright (c) 2019-2025 Red Hat, Inc.
33
// This program and the accompanying materials are made
44
// available under the terms of the Eclipse Public License 2.0
55
// which is available at https://www.eclipse.org/legal/epl-2.0/
@@ -31,6 +31,63 @@ import (
3131
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3232
)
3333

34+
func TestRecreateObjectIfAlreadyExists(t *testing.T) {
35+
// Actual object in a user namespace
36+
srcObject := &corev1.ConfigMap{
37+
TypeMeta: metav1.TypeMeta{
38+
Kind: "ConfigMap",
39+
APIVersion: "v1",
40+
},
41+
ObjectMeta: metav1.ObjectMeta{
42+
Name: "test",
43+
Namespace: "user-che",
44+
},
45+
Data: map[string]string{
46+
"key": "value",
47+
},
48+
}
49+
50+
// Expected object in a user namespace
51+
dstObject := &corev1.ConfigMap{
52+
TypeMeta: metav1.TypeMeta{
53+
Kind: "ConfigMap",
54+
APIVersion: "v1",
55+
},
56+
ObjectMeta: metav1.ObjectMeta{
57+
Name: "test",
58+
Namespace: "user-che",
59+
},
60+
Data: map[string]string{
61+
"new-key": "new-value",
62+
},
63+
}
64+
65+
ctx := test.GetDeployContext(nil, []runtime.Object{srcObject})
66+
67+
workspaceConfigReconciler := NewWorkspacesConfigReconciler(
68+
ctx.ClusterAPI.Client,
69+
ctx.ClusterAPI.Client,
70+
ctx.ClusterAPI.Scheme,
71+
NewNamespaceCache(ctx.ClusterAPI.NonCachingClient))
72+
73+
syncContext := &syncContext{
74+
dstNamespace: "user-che",
75+
srcNamespace: "eclipse-che",
76+
object2Sync: &configMap2Sync{cm: srcObject},
77+
syncConfig: map[string]string{},
78+
}
79+
80+
err := workspaceConfigReconciler.doCreateObject(syncContext, dstObject)
81+
assert.NoError(t, err)
82+
83+
cm := &corev1.ConfigMap{}
84+
exists, err := deploy.Get(ctx, types.NamespacedName{Namespace: "user-che", Name: "test"}, cm)
85+
assert.NoError(t, err)
86+
assert.True(t, exists)
87+
assert.Equal(t, 1, len(cm.Data))
88+
assert.Equal(t, "new-value", cm.Data["new-key"])
89+
}
90+
3491
func TestDeleteIfObjectIsObsolete(t *testing.T) {
3592
ctx := test.GetDeployContext(nil, []runtime.Object{
3693
&corev1.ConfigMap{
@@ -46,6 +103,7 @@ func TestDeleteIfObjectIsObsolete(t *testing.T) {
46103
})
47104

48105
workspaceConfigReconciler := NewWorkspacesConfigReconciler(
106+
ctx.ClusterAPI.Client,
49107
ctx.ClusterAPI.Client,
50108
ctx.ClusterAPI.Scheme,
51109
NewNamespaceCache(ctx.ClusterAPI.NonCachingClient))
@@ -103,6 +161,7 @@ func TestGetEmptySyncConfig(t *testing.T) {
103161
ctx := test.GetDeployContext(nil, []runtime.Object{})
104162

105163
workspaceConfigReconciler := NewWorkspacesConfigReconciler(
164+
ctx.ClusterAPI.Client,
106165
ctx.ClusterAPI.Client,
107166
ctx.ClusterAPI.Scheme,
108167
NewNamespaceCache(ctx.ClusterAPI.NonCachingClient))

main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2019-2023 Red Hat, Inc.
2+
// Copyright (c) 2019-2025 Red Hat, Inc.
33
// This program and the accompanying materials are made
44
// available under the terms of the Eclipse Public License 2.0
55
// which is available at https://www.eclipse.org/legal/epl-2.0/
@@ -290,7 +290,7 @@ func main() {
290290
os.Exit(1)
291291
}
292292

293-
workspacesConfigReconciler := usernamespace.NewWorkspacesConfigReconciler(mgr.GetClient(), mgr.GetScheme(), namespacechace)
293+
workspacesConfigReconciler := usernamespace.NewWorkspacesConfigReconciler(mgr.GetClient(), nonCachingClient, mgr.GetScheme(), namespacechace)
294294
if err = workspacesConfigReconciler.SetupWithManager(mgr); err != nil {
295295
setupLog.Error(err, "unable to set up controller", "controller", "WorkspacesConfigReconciler")
296296
os.Exit(1)

0 commit comments

Comments
 (0)