Skip to content
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

Change ForDynamic to proper generic type *Unstructured #795

Merged
merged 1 commit into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions pkg/federate/create_or_update_federator.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ func (f *createOrUpdateFederator) Distribute(ctx context.Context, obj runtime.Ob

f.prepareResourceForSync(toDistribute)

result, err := util.CreateOrUpdate[runtime.Object](ctx, resource.ForDynamic(resourceClient), toDistribute,
func(obj runtime.Object) (runtime.Object, error) {
return util.CopyImmutableMetadata(obj.(*unstructured.Unstructured), toDistribute), nil
result, err := util.CreateOrUpdate[*unstructured.Unstructured](ctx, resource.ForDynamic(resourceClient), toDistribute,
func(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
return util.CopyImmutableMetadata(obj, toDistribute), nil
})

if f.eventLogName != "" {
Expand Down
22 changes: 12 additions & 10 deletions pkg/federate/fake/federator.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,28 @@ import (
"time"

. "github.com/onsi/gomega"
"github.com/submariner-io/admiral/pkg/resource"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
)

type Federator struct {
distribute chan runtime.Object
delete chan runtime.Object
distribute chan *unstructured.Unstructured
delete chan *unstructured.Unstructured
FailOnDistribute error
FailOnDelete error
ResetOnFailure bool
}

func New() *Federator {
return &Federator{
distribute: make(chan runtime.Object, 100),
delete: make(chan runtime.Object, 100),
distribute: make(chan *unstructured.Unstructured, 100),
delete: make(chan *unstructured.Unstructured, 100),
ResetOnFailure: true,
}
}

func (f *Federator) Distribute(_ context.Context, resource runtime.Object) error {
func (f *Federator) Distribute(_ context.Context, obj runtime.Object) error {
err := f.FailOnDistribute
if err != nil {
if f.ResetOnFailure {
Expand All @@ -53,12 +55,12 @@ func (f *Federator) Distribute(_ context.Context, resource runtime.Object) error
return err
}

f.distribute <- resource
f.distribute <- resource.MustToUnstructured(obj)

return nil
}

func (f *Federator) Delete(_ context.Context, resource runtime.Object) error {
func (f *Federator) Delete(_ context.Context, obj runtime.Object) error {
err := f.FailOnDelete
if err != nil {
if f.ResetOnFailure {
Expand All @@ -68,21 +70,21 @@ func (f *Federator) Delete(_ context.Context, resource runtime.Object) error {
return err
}

f.delete <- resource
f.delete <- resource.MustToUnstructured(obj)

return nil
}

func (f *Federator) VerifyDistribute(expected runtime.Object) {
Eventually(f.distribute, 5).Should(Receive(Equal(expected)), "Distribute was not called")
Eventually(f.distribute, 5).Should(Receive(Equal(resource.MustToUnstructured(expected))), "Distribute was not called")
}

func (f *Federator) VerifyNoDistribute() {
Consistently(f.distribute, 300*time.Millisecond).ShouldNot(Receive(), "Distribute was unexpectedly called")
}

func (f *Federator) VerifyDelete(expected runtime.Object) {
Eventually(f.delete, 5).Should(Receive(Equal(expected)), "Delete was not called")
Eventually(f.delete, 5).Should(Receive(Equal(resource.MustToUnstructured(expected))), "Delete was not called")
}

func (f *Federator) VerifyNoDelete() {
Expand Down
6 changes: 3 additions & 3 deletions pkg/federate/update_federator.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ func (f *updateFederator) Distribute(ctx context.Context, obj runtime.Object) er

f.prepareResourceForSync(toUpdate)

return util.Update[runtime.Object](ctx, resource.ForDynamic(resourceClient), toUpdate,
func(obj runtime.Object) (runtime.Object, error) {
return f.update(obj.(*unstructured.Unstructured), toUpdate), nil
return util.Update[*unstructured.Unstructured](ctx, resource.ForDynamic(resourceClient), toUpdate,
func(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
return f.update(obj, toUpdate), nil
})
}
60 changes: 18 additions & 42 deletions pkg/resource/dynamic.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,70 +23,46 @@ import (
"context"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/client-go/dynamic"
)

type dynamicType struct {
client dynamic.ResourceInterface
}

func (d *dynamicType) Get(ctx context.Context, name string, options metav1.GetOptions) (runtime.Object, error) {
func (d *dynamicType) Get(ctx context.Context, name string, options metav1.GetOptions) (*unstructured.Unstructured, error) {
return d.client.Get(ctx, name, options)
}

//nolint:gocritic // hugeParam - we're matching K8s API
func (d *dynamicType) Create(ctx context.Context, obj runtime.Object, options metav1.CreateOptions) (runtime.Object, error) {
raw, err := ToUnstructured(obj)
if err != nil {
return nil, err
}

return d.client.Create(ctx, raw, options)
func (d *dynamicType) Create(ctx context.Context, obj *unstructured.Unstructured, options metav1.CreateOptions,
) (*unstructured.Unstructured, error) {
return d.client.Create(ctx, obj, options)
}

//nolint:gocritic // hugeParam - we're matching K8s API
func (d *dynamicType) Update(ctx context.Context, obj runtime.Object, options metav1.UpdateOptions) (runtime.Object, error) {
raw, err := ToUnstructured(obj)
if err != nil {
return nil, err
}

return d.client.Update(ctx, raw, options)
func (d *dynamicType) Update(ctx context.Context, obj *unstructured.Unstructured, options metav1.UpdateOptions,
) (*unstructured.Unstructured, error) {
return d.client.Update(ctx, obj, options)
}

//nolint:gocritic // hugeParam - we're matching K8s API
func (d *dynamicType) UpdateStatus(ctx context.Context, obj runtime.Object, options metav1.UpdateOptions) (runtime.Object, error) {
raw, err := ToUnstructured(obj)
if err != nil {
return nil, err
}

return d.client.UpdateStatus(ctx, raw, options)
func (d *dynamicType) UpdateStatus(ctx context.Context, obj *unstructured.Unstructured, options metav1.UpdateOptions,
) (*unstructured.Unstructured, error) {
return d.client.UpdateStatus(ctx, obj, options)
}

func (d *dynamicType) Delete(ctx context.Context, name string,
options metav1.DeleteOptions, //nolint:gocritic // hugeParam - we're matching K8s API
) error {
//nolint:gocritic // hugeParam - we're matching K8s API
func (d *dynamicType) Delete(ctx context.Context, name string, options metav1.DeleteOptions) error {
return d.client.Delete(ctx, name, options)
}

func (d *dynamicType) List(ctx context.Context,
options metav1.ListOptions, //nolint:gocritic // hugeParam - we're matching K8s API
) ([]runtime.Object, error) {
l, err := d.client.List(ctx, options)
return MustExtractList[runtime.Object](l), err
//nolint:gocritic // hugeParam - we're matching K8s API
func (d *dynamicType) List(ctx context.Context, options metav1.ListOptions) (*unstructured.UnstructuredList, error) {
return d.client.List(ctx, options)
}

func ForDynamic(client dynamic.ResourceInterface) *InterfaceFuncs[runtime.Object] {
t := &dynamicType{client: client}

return &InterfaceFuncs[runtime.Object]{
GetFunc: t.Get,
CreateFunc: t.Create,
UpdateFunc: t.Update,
UpdateStatusFunc: t.UpdateStatus,
DeleteFunc: t.Delete,
ListFunc: t.List,
}
func ForDynamic(client dynamic.ResourceInterface) Interface[*unstructured.Unstructured] {
return kubernetesStatusInterfaceAdapter[*unstructured.Unstructured, *unstructured.UnstructuredList](&dynamicType{client: client})
}
7 changes: 4 additions & 3 deletions pkg/resource/interface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
rbacv1 "k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
Expand Down Expand Up @@ -191,14 +192,14 @@ var _ = Describe("Interface", func() {
})

Context("ForDynamic", func() {
testInterfaceFuncs(func() resource.Interface[runtime.Object] {
testInterfaceFuncs(func() resource.Interface[*unstructured.Unstructured] {
return resource.ForDynamic(dynamicfake.NewSimpleDynamicClient(scheme.Scheme).Resource(
schema.GroupVersionResource{
Group: corev1.SchemeGroupVersion.Group,
Version: corev1.SchemeGroupVersion.Version,
Resource: "pods",
}).Namespace(test.LocalNamespace))
}, runtime.Object(resource.MustToUnstructured(&corev1.Pod{
}, resource.MustToUnstructured(&corev1.Pod{
TypeMeta: metav1.TypeMeta{
Kind: "Pod",
APIVersion: "v1",
Expand All @@ -210,7 +211,7 @@ var _ = Describe("Interface", func() {
Spec: corev1.PodSpec{
Hostname: "my-host",
},
})))
}))
})
})

Expand Down
34 changes: 17 additions & 17 deletions pkg/syncer/resource_syncer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/submariner-io/admiral/pkg/federate/fake"
. "github.com/submariner-io/admiral/pkg/gomega"
"github.com/submariner-io/admiral/pkg/resource"
resourceutils "github.com/submariner-io/admiral/pkg/resource"
"github.com/submariner-io/admiral/pkg/syncer"
"github.com/submariner-io/admiral/pkg/syncer/test"
"github.com/submariner-io/admiral/pkg/util"
Expand Down Expand Up @@ -90,7 +90,7 @@ func testReconcileLocalToRemote() {
When("the resource to reconcile is local and does not exist", func() {
It("should invoke delete", func() {
d.resource.Namespace = test.LocalNamespace
d.federator.VerifyDelete(test.SetClusterIDLabel(resource.MustToUnstructured(d.resource), ""))
d.federator.VerifyDelete(test.SetClusterIDLabel(d.resource, ""))
})
})

Expand Down Expand Up @@ -133,7 +133,7 @@ func testReconcileRemoteToLocal() {

When("the resource to reconcile is remote and does not exist", func() {
It("should invoke delete", func() {
d.federator.VerifyDelete(resource.MustToUnstructured(d.resource))
d.federator.VerifyDelete(d.resource)
})
})

Expand Down Expand Up @@ -177,7 +177,7 @@ func testReconcileNoDirection() {

When("the resource to reconcile does not exist", func() {
It("should invoke delete", func() {
d.federator.VerifyDelete(resource.MustToUnstructured(d.resource))
d.federator.VerifyDelete(d.resource)
})
})

Expand Down Expand Up @@ -355,11 +355,11 @@ func testTransformFunction() {
})

verifyDistribute := func() {
d.federator.VerifyDistribute(test.SetClusterIDLabel(resource.MustToUnstructured(transformed), "remote"))
d.federator.VerifyDistribute(test.SetClusterIDLabel(transformed.DeepCopy(), "remote"))
}

verifyDelete := func() {
d.federator.VerifyDelete(test.SetClusterIDLabel(resource.MustToUnstructured(transformed), "remote"))
d.federator.VerifyDelete(test.SetClusterIDLabel(transformed.DeepCopy(), "remote"))
}

When("a resource is created in the datastore", func() {
Expand Down Expand Up @@ -399,7 +399,7 @@ func testTransformFunction() {

d.resource = test.NewPodWithImage(d.config.SourceNamespace, "updated")
test.UpdateResource(d.sourceClient, test.NewPodWithImage(d.config.SourceNamespace, "updated"))
d.federator.VerifyDistribute(resource.MustToUnstructured(transformed))
d.federator.VerifyDistribute(transformed)
Eventually(expOperation).Should(Receive(Equal(syncer.Update)))
})
})
Expand Down Expand Up @@ -630,7 +630,7 @@ func testOnSuccessfulSyncFunction() {

It("should invoke the OnSuccessfulSync function with the transformed resource", func() {
test.CreateResource(d.sourceClient, d.resource)
d.federator.VerifyDistribute(resource.MustToUnstructured(expResource))
d.federator.VerifyDistribute(expResource)
Eventually(expOperation).Should(Receive(Equal(syncer.Create)))
})
})
Expand Down Expand Up @@ -883,7 +883,7 @@ func testUpdateSuppression() {
})

It("should distribute it", func() {
d.federator.VerifyDistribute(resource.MustToUnstructured(d.resource))
d.federator.VerifyDistribute(test.GetResource(d.sourceClient, d.resource))
})
})

Expand All @@ -894,7 +894,7 @@ func testUpdateSuppression() {
})

It("should distribute it", func() {
d.federator.VerifyDistribute(resource.MustToUnstructured(d.resource))
d.federator.VerifyDistribute(test.GetResource(d.sourceClient, d.resource))
})
})
})
Expand Down Expand Up @@ -931,7 +931,7 @@ func testUpdateSuppression() {
})

It("should distribute it", func() {
d.federator.VerifyDistribute(resource.MustToUnstructured(d.resource))
d.federator.VerifyDistribute(test.GetResource(d.sourceClient, d.resource))
})
})

Expand All @@ -941,7 +941,7 @@ func testUpdateSuppression() {
})

It("should distribute it", func() {
d.federator.VerifyDistribute(resource.MustToUnstructured(d.resource))
d.federator.VerifyDistribute(test.GetResource(d.sourceClient, d.resource))
})
})
})
Expand All @@ -960,7 +960,7 @@ func testUpdateSuppression() {
})

It("should distribute it", func() {
d.federator.VerifyDistribute(resource.MustToUnstructured(d.resource))
d.federator.VerifyDistribute(test.GetResource(d.sourceClient, d.resource))
})
})
})
Expand All @@ -976,7 +976,7 @@ func testUpdateSuppression() {
})

It("should distribute it", func() {
d.federator.VerifyDistribute(resource.MustToUnstructured(d.resource))
d.federator.VerifyDistribute(test.GetResource(d.sourceClient, d.resource))
})
})

Expand Down Expand Up @@ -1152,11 +1152,11 @@ func testRequeueResource() {
})

It("should requeue it", func() {
d.federator.VerifyDistribute(resource.MustToUnstructured(transformed))
d.federator.VerifyDistribute(transformed)

d.syncer.RequeueResource(d.resource.Name, d.resource.Namespace)

d.federator.VerifyDistribute(resource.MustToUnstructured(transformed))
d.federator.VerifyDistribute(transformed)
})
})

Expand Down Expand Up @@ -1257,7 +1257,7 @@ func newTestDriver(sourceNamespace, localClusterID string, syncDirection syncer.
}

func (t *testDriver) addInitialResource(obj runtime.Object) {
t.initialResources = append(t.initialResources, resource.MustToUnstructured(obj))
t.initialResources = append(t.initialResources, resourceutils.MustToUnstructured(obj))
}

func (t *testDriver) verifyDistributeOnCreateTest(clusterID string) {
Expand Down
10 changes: 4 additions & 6 deletions pkg/syncer/test/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,7 @@ const (
)

func GetResourceAndError(resourceInterface dynamic.ResourceInterface, obj runtime.Object) (*unstructured.Unstructured, error) {
meta, err := metaapi.Accessor(obj)
Expect(err).To(Succeed())

return resourceInterface.Get(context.TODO(), meta.GetName(), metav1.GetOptions{})
return resourceInterface.Get(context.TODO(), resource.MustToMeta(obj).GetName(), metav1.GetOptions{})
}

func GetResource(resourceInterface dynamic.ResourceInterface, obj runtime.Object) *unstructured.Unstructured {
Expand All @@ -70,8 +67,9 @@ func CreateResource(resourceInterface dynamic.ResourceInterface, obj runtime.Obj
}

func UpdateResource(resourceInterface dynamic.ResourceInterface, obj runtime.Object) *unstructured.Unstructured {
err := util.Update[runtime.Object](context.Background(), resource.ForDynamic(resourceInterface), obj,
util.Replace(obj))
u := resource.MustToUnstructured(obj)
err := util.Update[*unstructured.Unstructured](context.Background(), resource.ForDynamic(resourceInterface), u,
util.Replace(u))
Expect(err).To(Succeed())

return GetResource(resourceInterface, obj)
Expand Down
Loading
Loading