Skip to content

Commit

Permalink
šŸ› fix the AlreadyExists logic case if the manifest is not cached by Gā€¦
Browse files Browse the repository at this point in the history
ā€¦etter when applying a manifest

Signed-off-by: Yang Le <yangle@redhat.com>
  • Loading branch information
elgnay committed Sep 11, 2023
1 parent 3fc013f commit 2d520a2
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 20 deletions.
20 changes: 13 additions & 7 deletions pkg/common/apply/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ type Getter[T runtime.Object] interface {

// Client is a wrapper interface of client
type Client[T runtime.Object] interface {
Get(ctx context.Context, name string, opts metav1.GetOptions) (T, error)

Create(ctx context.Context, obj T, opts metav1.CreateOptions) (T, error)

Update(ctx context.Context, obj T, opts metav1.UpdateOptions) (T, error)
Expand All @@ -43,20 +45,24 @@ func Apply[T runtime.Object](
existing, err := getter.Get(requiredAccessor.GetName())
if errors.IsNotFound(err) {
actual, createErr := client.Create(ctx, required, metav1.CreateOptions{})
if errors.IsAlreadyExists(createErr) {
return required, false, nil
}
if createErr == nil {
switch {
case errors.IsAlreadyExists(createErr):
actual, getErr := client.Get(ctx, requiredAccessor.GetName(), metav1.GetOptions{})
if getErr != nil {
return required, false, getErr
}
existing = actual
case createErr == nil:
recorder.Eventf(
fmt.Sprintf("%sCreated", gvk.Kind),
"Created %s because it was missing", resourcehelper.FormatResourceForCLIWithNamespace(actual))
} else {
return actual, true, nil
default:
recorder.Warningf(
fmt.Sprintf("%sCreateFailed", gvk.Kind),
"Failed to create %s: %v", resourcehelper.FormatResourceForCLIWithNamespace(required), createErr)
return actual, true, createErr
}

return actual, true, createErr
}

updated, modified := compare(required, existing)
Expand Down
58 changes: 45 additions & 13 deletions pkg/common/apply/rbac_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ func TestPermissionApply(t *testing.T) {
name string
manifest string
existingManifest string
validateAction func(t *testing.T, actions []clienttesting.Action)
// filtered indicates if the existing manifest is in the informer cache or not. For example,
// it may not match the expected label/field selector of the informer factory.
filtered bool
validateAction func(t *testing.T, actions []clienttesting.Action)
}{
{
name: "create clusterrole",
Expand Down Expand Up @@ -64,6 +67,33 @@ rules:
testingcommon.AssertActions(t, actions, "update")
},
},
{
name: "upate clusterrole with no cache",
existingManifest: `
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: test
rules:
- apiGroups: [""]
resources: ["configmaps", "events"]
verbs: ["get", "list", "watch", "create"]
`,
manifest: `
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: test
rules:
- apiGroups: [""]
resources: ["configmaps", "events"]
verbs: ["get", "list", "watch"]
`,
filtered: true,
validateAction: func(t *testing.T, actions []clienttesting.Action) {
testingcommon.AssertActions(t, actions, "create", "get", "update")
},
},
{
name: "compare and no update clusterrole",
existingManifest: `
Expand Down Expand Up @@ -349,18 +379,20 @@ subjects:
}
kubeClient = kubefake.NewSimpleClientset(o)
informerFactory = informers.NewSharedInformerFactory(kubeClient, 3*time.Minute)
switch t := o.(type) {
case *rbacv1.ClusterRole:
err = informerFactory.Rbac().V1().ClusterRoles().Informer().GetStore().Add(t)
case *rbacv1.ClusterRoleBinding:
err = informerFactory.Rbac().V1().ClusterRoleBindings().Informer().GetStore().Add(t)
case *rbacv1.Role:
err = informerFactory.Rbac().V1().Roles().Informer().GetStore().Add(t)
case *rbacv1.RoleBinding:
err = informerFactory.Rbac().V1().RoleBindings().Informer().GetStore().Add(t)
}
if err != nil {
t.Fatal(err)
if !c.filtered {
switch t := o.(type) {
case *rbacv1.ClusterRole:
err = informerFactory.Rbac().V1().ClusterRoles().Informer().GetStore().Add(t)
case *rbacv1.ClusterRoleBinding:
err = informerFactory.Rbac().V1().ClusterRoleBindings().Informer().GetStore().Add(t)
case *rbacv1.Role:
err = informerFactory.Rbac().V1().Roles().Informer().GetStore().Add(t)
case *rbacv1.RoleBinding:
err = informerFactory.Rbac().V1().RoleBindings().Informer().GetStore().Add(t)
}
if err != nil {
t.Fatal(err)
}
}
} else {
kubeClient = kubefake.NewSimpleClientset()
Expand Down

0 comments on commit 2d520a2

Please sign in to comment.