client.Get() does not zero out slice fields on CRD objects (original) (raw)

I've encountered some unusual behavior when using Get() on CRD objects with the controller-runtime client. When the client.Object you pass into Get() has a slice field populated with values and the object on the API server has an empty or nil slice for that field, the client does not properly zero/empty that field.

This is in contrast with the behavior when getting core objects, which does zero/empty fields as expected.

Observations

The example test below demonstrates the inconsistency.

var _ = Describe("client.Get", func() { ctx := context.Background()

var (
    crdObject  *v1alpha1.CRDType
    coreObject *corev1.ConfigMap
)

BeforeEach(func() {
    crdObject = &v1alpha1.Type{
        ObjectMeta: metav1.ObjectMeta{
            Name:      "crd-object",
            Namespace: "default",
            // Finalizers empty.
        },
    }
    coreObject = &corev1.ConfigMap{
        ObjectMeta: metav1.ObjectMeta{
            Name:      "core-object",
            Namespace: "default",
            // Finalizers empty.
        },
    }
})

JustBeforeEach(func() {
    Expect(k8sClient.Create(ctx, crdObject)).Should(Succeed())
    Expect(k8sClient.Create(ctx, coreObject)).Should(Succeed())
})

AfterEach(func() {
    Expect(k8sClient.Delete(ctx, crdObject)).Should(Succeed())
    Expect(k8sClient.Delete(ctx, coreObject)).Should(Succeed())
})

It("Should overwrite slices that should be empty when getting a CRD object", func() {
    crdObject.Finalizers = []string{"1.1.1.1"}

    Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(crdObject), crdObject)).
        Should(Succeed())

    // Fails: crdObject.Finalizers is []string{"1.1.1.1"}
    Expect(crdObject.Finalizers).To(BeEmpty())
})

It("Should overwrite slices that should be empty when getting a core object", func() {
    coreObject.Finalizers = []string{"1.1.1.1"}

    Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(coreObject), coreObject)).
        Should(Succeed())

    // Passes.
    Expect(coreObject.Finalizers).To(BeEmpty())
})

})