forked from openstack-k8s-operators/lib-common
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add object package with generic ownerref func
Adds object package to the common module with initial functions to add additional non controller owner references to objects. This allows additional owners to watch resources // watch for secrets we added ourselves as additional owners, NOT as controller Watches( &source.Kind{Type: &corev1.Secret{}}, &handler.EnqueueRequestForOwner{OwnerType: &clientv1.OpenStackClient{}, IsController: false}). Note: Adding as an additional owner will not triggere a reconcilation when the object gets re-created from scratch, like deleting a secret.
- Loading branch information
Showing
12 changed files
with
289 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/* | ||
Copyright 2023 Red Hat | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package object | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
|
||
"golang.org/x/exp/slices" | ||
|
||
"github.com/openstack-k8s-operators/lib-common/modules/common/helper" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/types" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" | ||
|
||
k8s_errors "k8s.io/apimachinery/pkg/api/errors" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
// CheckOwnerRefExist - returns true if the owner is already in the owner ref list | ||
func CheckOwnerRefExist( | ||
uid types.UID, | ||
ownerRefs []metav1.OwnerReference, | ||
) bool { | ||
f := func(o metav1.OwnerReference) bool { | ||
return o.UID == uid | ||
} | ||
if idx := slices.IndexFunc(ownerRefs, f); idx >= 0 { | ||
return true | ||
} | ||
|
||
return false | ||
} | ||
|
||
// PatchOwnerRef - creates a patch to add ownerref to an object | ||
func PatchOwnerRef( | ||
owner client.Object, | ||
object client.Object, | ||
scheme *runtime.Scheme, | ||
) (map[string]interface{}, client.Patch, error) { | ||
beforeObject := object.DeepCopyObject().(client.Object) | ||
|
||
// add owner ref to the object | ||
err := controllerutil.SetOwnerReference(owner, object, scheme) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
// create patch | ||
patch := client.MergeFrom(beforeObject) | ||
diff, err := patch.Data(object) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
// Unmarshal patch data into a local map for logging | ||
patchDiff := map[string]interface{}{} | ||
if err := json.Unmarshal(diff, &patchDiff); err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
return patchDiff, patch, nil | ||
} | ||
|
||
// EnsureOwnerRef - adds owner ref (no controller) to an object which then can | ||
// can be used to reconcile when the object changes by adding the following in | ||
// NewControllerManagedBy(). | ||
// Note: This will not triggere a reconcilation when the object gets re-created | ||
// from scratch, like deleting a secret. | ||
// | ||
// watch for secrets we added ourselves as additional owners, NOT as controller | ||
// Watches( | ||
// | ||
// &source.Kind{Type: &corev1.Secret{}}, | ||
// &handler.EnqueueRequestForOwner{OwnerType: &clientv1.OpenStackClient{}, IsController: false}). | ||
func EnsureOwnerRef( | ||
ctx context.Context, | ||
h *helper.Helper, | ||
owner client.Object, | ||
object client.Object, | ||
) error { | ||
// return if the owner is already in the owner ref list | ||
if CheckOwnerRefExist(owner.GetUID(), object.GetOwnerReferences()) { | ||
return nil | ||
} | ||
|
||
// create owner ref patch | ||
patchDiff, patch, err := PatchOwnerRef(owner, object, h.GetScheme()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = h.GetClient().Patch(ctx, object, patch) | ||
if k8s_errors.IsConflict(err) { | ||
return fmt.Errorf("error metadata update conflict: %w", err) | ||
} else if err != nil && !k8s_errors.IsNotFound(err) { | ||
return fmt.Errorf("error metadata update failed: %w", err) | ||
} | ||
|
||
h.GetLogger().Info(fmt.Sprintf("Owner reference patched - diff %+v", patchDiff["metadata"])) | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/* | ||
Copyright 2023 Red Hat | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package object | ||
|
||
import ( | ||
"testing" | ||
|
||
. "github.com/onsi/gomega" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/types" | ||
"k8s.io/utils/ptr" | ||
) | ||
|
||
var ( | ||
metadata = metav1.ObjectMeta{ | ||
Name: "foo", | ||
Namespace: "bar", | ||
OwnerReferences: []metav1.OwnerReference{ | ||
{ | ||
APIVersion: "core.openstack.org/v1beta1", | ||
BlockOwnerDeletion: ptr.To(true), | ||
Controller: ptr.To(true), | ||
Kind: "OpenStackControlPlane", | ||
Name: "openstack-network-isolation", | ||
UID: "11111111-1111-1111-1111-111111111111", | ||
}, | ||
}, | ||
} | ||
) | ||
|
||
func TestCheckOwnerRefExist(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
ownerRefs []metav1.OwnerReference | ||
uid types.UID | ||
want bool | ||
}{ | ||
{ | ||
name: "Check existing owner", | ||
ownerRefs: metadata.OwnerReferences, | ||
uid: types.UID("11111111-1111-1111-1111-111111111111"), | ||
want: true, | ||
}, | ||
{ | ||
name: "Check non existing owner", | ||
ownerRefs: metadata.OwnerReferences, | ||
uid: types.UID("22222222-2222-2222-2222-222222222222"), | ||
want: false, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
g := NewWithT(t) | ||
|
||
g.Expect(CheckOwnerRefExist(tt.uid, tt.ownerRefs)).To(BeIdenticalTo(tt.want)) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/* | ||
Copyright 2023 Red Hat | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
package functional | ||
|
||
import ( | ||
"github.com/google/uuid" | ||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
"github.com/openstack-k8s-operators/lib-common/modules/common/object" | ||
|
||
"k8s.io/apimachinery/pkg/types" | ||
) | ||
|
||
var _ = Describe("object package", func() { | ||
var namespace string | ||
|
||
BeforeEach(func() { | ||
// NOTE(gibi): We need to create a unique namespace for each test run | ||
// as namespaces cannot be deleted in a locally running envtest. See | ||
// https://book.kubebuilder.io/reference/envtest.html#namespace-usage-limitation | ||
namespace = uuid.New().String() | ||
th.CreateNamespace(namespace) | ||
// We still request the delete of the Namespace to properly cleanup if | ||
// we run the test in an existing cluster. | ||
DeferCleanup(th.DeleteNamespace, namespace) | ||
|
||
}) | ||
|
||
It("now new owner gets added when adding same ownerref", func() { | ||
cmName := types.NamespacedName{ | ||
Namespace: namespace, | ||
Name: "test-cm", | ||
} | ||
|
||
cm := th.CreateConfigMap(cmName, map[string]interface{}{}) | ||
|
||
err := object.EnsureOwnerRef(th.Ctx, h, cm, cm) | ||
Expect(err).ShouldNot(HaveOccurred()) | ||
Expect(object.CheckOwnerRefExist(cm.GetUID(), cm.GetOwnerReferences())).To(BeTrue()) | ||
Expect(cm.GetOwnerReferences()).To(HaveLen(1)) | ||
}) | ||
|
||
It("adds an additional owner to the ownerref list", func() { | ||
// create owner obj | ||
owner := types.NamespacedName{ | ||
Namespace: namespace, | ||
Name: "test-owner", | ||
} | ||
ownerCM := th.CreateConfigMap(owner, map[string]interface{}{}) | ||
|
||
// create target obj we add the owner ref to | ||
cmName := types.NamespacedName{ | ||
Namespace: namespace, | ||
Name: "test-cm", | ||
} | ||
cm := th.CreateConfigMap(cmName, map[string]interface{}{}) | ||
|
||
err := object.EnsureOwnerRef(th.Ctx, h, ownerCM, cm) | ||
Expect(err).ShouldNot(HaveOccurred()) | ||
Expect(object.CheckOwnerRefExist(ownerCM.GetUID(), cm.GetOwnerReferences())).To(BeTrue()) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.