From 6deb9f67cb255c93f2333eb941a91c22b11bacd9 Mon Sep 17 00:00:00 2001 From: Stefan Bueringer Date: Mon, 20 Sep 2021 18:24:13 +0200 Subject: [PATCH] Add MachinePool conversion Signed-off-by: Stefan Bueringer --- .../types/upstreamv1beta1/conversion_test.go | 4 ++ .../types/upstreamv1beta2/conversion_test.go | 4 ++ .../types/upstreamv1beta3/conversion_test.go | 3 + config/crd/kustomization.yaml | 2 + .../patches/cainjection_in_machinepools.yaml | 8 +++ .../crd/patches/webhook_in_machinepools.yaml | 19 +++++ exp/api/v1alpha3/conversion.go | 70 +++++++++++++++++-- exp/api/v1alpha3/conversion_test.go | 66 +++++++++++++++++ exp/api/v1alpha3/zz_generated.conversion.go | 15 ++-- exp/api/v1alpha4/conversion.go | 46 ++++++++++++ exp/api/v1alpha4/conversion_test.go | 33 +++++++++ exp/api/v1beta1/conversion.go | 20 ++++++ util/conversion/conversion.go | 8 +++ 13 files changed, 283 insertions(+), 15 deletions(-) create mode 100644 config/crd/patches/cainjection_in_machinepools.yaml create mode 100644 config/crd/patches/webhook_in_machinepools.yaml create mode 100644 exp/api/v1alpha3/conversion_test.go create mode 100644 exp/api/v1alpha4/conversion.go create mode 100644 exp/api/v1alpha4/conversion_test.go create mode 100644 exp/api/v1beta1/conversion.go diff --git a/bootstrap/kubeadm/types/upstreamv1beta1/conversion_test.go b/bootstrap/kubeadm/types/upstreamv1beta1/conversion_test.go index 92c78c412104..946796c9d8b3 100644 --- a/bootstrap/kubeadm/types/upstreamv1beta1/conversion_test.go +++ b/bootstrap/kubeadm/types/upstreamv1beta1/conversion_test.go @@ -32,6 +32,7 @@ func TestFuzzyConversion(t *testing.T) { Spoke: &ClusterConfiguration{}, // NOTE: Kubeadm types does not have ObjectMeta, so we are required to skip data annotation cleanup in the spoke-hub-spoke round trip test. SkipSpokeAnnotationCleanup: true, + SkipHubAnnotationCleanup: true, FuzzerFuncs: []fuzzer.FuzzerFuncs{fuzzFuncs}, })) t.Run("for ClusterStatus", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{ @@ -39,6 +40,7 @@ func TestFuzzyConversion(t *testing.T) { Spoke: &ClusterStatus{}, // NOTE: Kubeadm types does not have ObjectMeta, so we are required to skip data annotation cleanup in the spoke-hub-spoke round trip test. SkipSpokeAnnotationCleanup: true, + SkipHubAnnotationCleanup: true, FuzzerFuncs: []fuzzer.FuzzerFuncs{fuzzFuncs}, })) t.Run("for InitConfiguration", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{ @@ -46,6 +48,7 @@ func TestFuzzyConversion(t *testing.T) { Spoke: &InitConfiguration{}, // NOTE: Kubeadm types does not have ObjectMeta, so we are required to skip data annotation cleanup in the spoke-hub-spoke round trip test. SkipSpokeAnnotationCleanup: true, + SkipHubAnnotationCleanup: true, FuzzerFuncs: []fuzzer.FuzzerFuncs{fuzzFuncs}, })) t.Run("for JoinConfiguration", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{ @@ -53,6 +56,7 @@ func TestFuzzyConversion(t *testing.T) { Spoke: &JoinConfiguration{}, // NOTE: Kubeadm types does not have ObjectMeta, so we are required to skip data annotation cleanup in the spoke-hub-spoke round trip test. SkipSpokeAnnotationCleanup: true, + SkipHubAnnotationCleanup: true, FuzzerFuncs: []fuzzer.FuzzerFuncs{fuzzFuncs}, })) } diff --git a/bootstrap/kubeadm/types/upstreamv1beta2/conversion_test.go b/bootstrap/kubeadm/types/upstreamv1beta2/conversion_test.go index 44b5e756af68..dedff22afe36 100644 --- a/bootstrap/kubeadm/types/upstreamv1beta2/conversion_test.go +++ b/bootstrap/kubeadm/types/upstreamv1beta2/conversion_test.go @@ -32,6 +32,7 @@ func TestFuzzyConversion(t *testing.T) { Spoke: &ClusterConfiguration{}, // NOTE: Kubeadm types does not have ObjectMeta, so we are required to skip data annotation cleanup in the spoke-hub-spoke round trip test. SkipSpokeAnnotationCleanup: true, + SkipHubAnnotationCleanup: true, FuzzerFuncs: []fuzzer.FuzzerFuncs{fuzzFuncs}, })) t.Run("for ClusterStatus", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{ @@ -39,6 +40,7 @@ func TestFuzzyConversion(t *testing.T) { Spoke: &ClusterStatus{}, // NOTE: Kubeadm types does not have ObjectMeta, so we are required to skip data annotation cleanup in the spoke-hub-spoke round trip test. SkipSpokeAnnotationCleanup: true, + SkipHubAnnotationCleanup: true, FuzzerFuncs: []fuzzer.FuzzerFuncs{fuzzFuncs}, })) t.Run("for InitConfiguration", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{ @@ -46,6 +48,7 @@ func TestFuzzyConversion(t *testing.T) { Spoke: &InitConfiguration{}, // NOTE: Kubeadm types does not have ObjectMeta, so we are required to skip data annotation cleanup in the spoke-hub-spoke round trip test. SkipSpokeAnnotationCleanup: true, + SkipHubAnnotationCleanup: true, FuzzerFuncs: []fuzzer.FuzzerFuncs{fuzzFuncs}, })) t.Run("for JoinConfiguration", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{ @@ -53,6 +56,7 @@ func TestFuzzyConversion(t *testing.T) { Spoke: &JoinConfiguration{}, // NOTE: Kubeadm types does not have ObjectMeta, so we are required to skip data annotation cleanup in the spoke-hub-spoke round trip test. SkipSpokeAnnotationCleanup: true, + SkipHubAnnotationCleanup: true, FuzzerFuncs: []fuzzer.FuzzerFuncs{fuzzFuncs}, })) } diff --git a/bootstrap/kubeadm/types/upstreamv1beta3/conversion_test.go b/bootstrap/kubeadm/types/upstreamv1beta3/conversion_test.go index 10ae782ac116..6fba61466aae 100644 --- a/bootstrap/kubeadm/types/upstreamv1beta3/conversion_test.go +++ b/bootstrap/kubeadm/types/upstreamv1beta3/conversion_test.go @@ -41,6 +41,7 @@ func TestFuzzyConversion(t *testing.T) { Spoke: &ClusterConfiguration{}, // NOTE: Kubeadm types does not have ObjectMeta, so we are required to skip data annotation cleanup in the spoke-hub-spoke round trip test. SkipSpokeAnnotationCleanup: true, + SkipHubAnnotationCleanup: true, FuzzerFuncs: []fuzzer.FuzzerFuncs{fuzzFuncs}, })) t.Run("for InitConfiguration", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{ @@ -49,6 +50,7 @@ func TestFuzzyConversion(t *testing.T) { Spoke: &InitConfiguration{}, // NOTE: Kubeadm types does not have ObjectMeta, so we are required to skip data annotation cleanup in the spoke-hub-spoke round trip test. SkipSpokeAnnotationCleanup: true, + SkipHubAnnotationCleanup: true, FuzzerFuncs: []fuzzer.FuzzerFuncs{fuzzFuncs}, })) t.Run("for JoinConfiguration", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{ @@ -57,6 +59,7 @@ func TestFuzzyConversion(t *testing.T) { Spoke: &JoinConfiguration{}, // NOTE: Kubeadm types does not have ObjectMeta, so we are required to skip data annotation cleanup in the spoke-hub-spoke round trip test. SkipSpokeAnnotationCleanup: true, + SkipHubAnnotationCleanup: true, FuzzerFuncs: []fuzzer.FuzzerFuncs{fuzzFuncs}, })) } diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 323ee9f430d7..75fa1c2d81b3 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -18,6 +18,7 @@ patchesStrategicMerge: # patches here are for enabling the conversion webhook for each CRD - patches/webhook_in_clusterclasses.yaml - patches/webhook_in_clusters.yaml +- patches/webhook_in_machinepools.yaml - patches/webhook_in_machines.yaml - patches/webhook_in_machinesets.yaml - patches/webhook_in_machinedeployments.yaml @@ -28,6 +29,7 @@ patchesStrategicMerge: # patches here are for enabling the CA injection for each CRD - patches/cainjection_in_clusterclasses.yaml - patches/cainjection_in_clusters.yaml +- patches/cainjection_in_machinepools.yaml - patches/cainjection_in_machines.yaml - patches/cainjection_in_machinesets.yaml - patches/cainjection_in_machinedeployments.yaml diff --git a/config/crd/patches/cainjection_in_machinepools.yaml b/config/crd/patches/cainjection_in_machinepools.yaml new file mode 100644 index 000000000000..b5329a85f8ba --- /dev/null +++ b/config/crd/patches/cainjection_in_machinepools.yaml @@ -0,0 +1,8 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +# CRD conversion requires k8s 1.13 or later. +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: machinepools.cluster.x-k8s.io diff --git a/config/crd/patches/webhook_in_machinepools.yaml b/config/crd/patches/webhook_in_machinepools.yaml new file mode 100644 index 000000000000..44ddf9ddc36a --- /dev/null +++ b/config/crd/patches/webhook_in_machinepools.yaml @@ -0,0 +1,19 @@ +# The following patch enables conversion webhook for CRD +# CRD conversion requires k8s 1.13 or later. +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: machinepools.cluster.x-k8s.io +spec: + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: ["v1", "v1beta1"] + clientConfig: + # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, + # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) + caBundle: Cg== + service: + namespace: system + name: webhook-service + path: /convert diff --git a/exp/api/v1alpha3/conversion.go b/exp/api/v1alpha3/conversion.go index c1ea87de0204..5e20d1d5e752 100644 --- a/exp/api/v1alpha3/conversion.go +++ b/exp/api/v1alpha3/conversion.go @@ -17,26 +17,86 @@ limitations under the License. package v1alpha3 import ( - "k8s.io/apimachinery/pkg/conversion" - v1beta1 "sigs.k8s.io/cluster-api/exp/api/v1beta1" + apimachineryconversion "k8s.io/apimachinery/pkg/conversion" + "sigs.k8s.io/cluster-api/exp/api/v1beta1" + utilconversion "sigs.k8s.io/cluster-api/util/conversion" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/conversion" ) // Convert_v1alpha3_MachinePoolSpec_To_v1beta1_MachinePoolSpec is an autogenerated conversion function. -func Convert_v1alpha3_MachinePoolSpec_To_v1beta1_MachinePoolSpec(in *MachinePoolSpec, out *v1beta1.MachinePoolSpec, s conversion.Scope) error { +func Convert_v1alpha3_MachinePoolSpec_To_v1beta1_MachinePoolSpec(in *MachinePoolSpec, out *v1beta1.MachinePoolSpec, s apimachineryconversion.Scope) error { return autoConvert_v1alpha3_MachinePoolSpec_To_v1beta1_MachinePoolSpec(in, out, s) } -func Convert_v1alpha3_MachinePool_To_v1beta1_MachinePool(in *MachinePool, out *v1beta1.MachinePool, s conversion.Scope) error { +func Convert_v1alpha3_MachinePool_To_v1beta1_MachinePool(in *MachinePool, out *v1beta1.MachinePool, s apimachineryconversion.Scope) error { if err := autoConvert_v1alpha3_MachinePool_To_v1beta1_MachinePool(in, out, s); err != nil { return err } // Replace v1alpha3 finalizer to allow old MachinePools to get deleted. - if !controllerutil.ContainsFinalizer(out, MachinePoolFinalizer) { + if controllerutil.ContainsFinalizer(out, MachinePoolFinalizer) { controllerutil.RemoveFinalizer(out, MachinePoolFinalizer) controllerutil.AddFinalizer(out, v1beta1.MachinePoolFinalizer) } return nil } + +func Convert_v1beta1_MachinePool_To_v1alpha3_MachinePool(in *v1beta1.MachinePool, out *MachinePool, s apimachineryconversion.Scope) error { + if err := autoConvert_v1beta1_MachinePool_To_v1alpha3_MachinePool(in, out, s); err != nil { + return err + } + + // Replace v1beta1 finalizer to allow old MachinePools to get deleted. + if controllerutil.ContainsFinalizer(out, v1beta1.MachinePoolFinalizer) { + controllerutil.RemoveFinalizer(out, v1beta1.MachinePoolFinalizer) + controllerutil.AddFinalizer(out, MachinePoolFinalizer) + } + + return nil +} + +func (src *MachinePool) ConvertTo(dstRaw conversion.Hub) error { + dst := dstRaw.(*v1beta1.MachinePool) + + if err := Convert_v1alpha3_MachinePool_To_v1beta1_MachinePool(src, dst, nil); err != nil { + return err + } + + // Preserve Hub data on conversion except for metadata + if err := utilconversion.MarshalData(src, dst); err != nil { + return err + } + + return nil +} + +func (dst *MachinePool) ConvertFrom(srcRaw conversion.Hub) error { + src := srcRaw.(*v1beta1.MachinePool) + + if err := Convert_v1beta1_MachinePool_To_v1alpha3_MachinePool(src, dst, nil); err != nil { + return err + } + + // Manually restore data. + restored := &MachinePool{} + if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok { + return err + } + + dst.Spec.Strategy = restored.Spec.Strategy + return nil +} + +func (src *MachinePoolList) ConvertTo(dstRaw conversion.Hub) error { + dst := dstRaw.(*v1beta1.MachinePoolList) + + return Convert_v1alpha3_MachinePoolList_To_v1beta1_MachinePoolList(src, dst, nil) +} + +func (dst *MachinePoolList) ConvertFrom(srcRaw conversion.Hub) error { + src := srcRaw.(*v1beta1.MachinePoolList) + + return Convert_v1beta1_MachinePoolList_To_v1alpha3_MachinePoolList(src, dst, nil) +} diff --git a/exp/api/v1alpha3/conversion_test.go b/exp/api/v1alpha3/conversion_test.go new file mode 100644 index 000000000000..d1edc84cdbb8 --- /dev/null +++ b/exp/api/v1alpha3/conversion_test.go @@ -0,0 +1,66 @@ +/* +Copyright 2021 The Kubernetes Authors. + +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 v1alpha3 + +import ( + "testing" + + fuzz "github.com/google/gofuzz" + "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" + runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" + clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3" + clusterv1exp "sigs.k8s.io/cluster-api/exp/api/v1beta1" + utilconversion "sigs.k8s.io/cluster-api/util/conversion" +) + +func TestFuzzyConversion(t *testing.T) { + t.Run("for MachinePool", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{ + Hub: &clusterv1exp.MachinePool{}, + Spoke: &MachinePool{}, + FuzzerFuncs: []fuzzer.FuzzerFuncs{BootstrapFuzzFuncs, CustomObjectMetaFuzzFunc}, + })) +} + +func CustomObjectMetaFuzzFunc(_ runtimeserializer.CodecFactory) []interface{} { + return []interface{}{ + CustomObjectMetaFuzzer, + } +} + +func CustomObjectMetaFuzzer(in *clusterv1.ObjectMeta, c fuzz.Continue) { + c.FuzzNoCustom(in) + + // These fields have been removed in v1beta1 + // data is going to be lost, so we're forcing zero values here. + in.Name = "" + in.GenerateName = "" + in.Namespace = "" + in.OwnerReferences = nil +} + +func BootstrapFuzzFuncs(_ runtimeserializer.CodecFactory) []interface{} { + return []interface{}{ + BootstrapFuzzer, + } +} + +func BootstrapFuzzer(obj *clusterv1.Bootstrap, c fuzz.Continue) { + c.FuzzNoCustom(obj) + + // Bootstrap.Data has been removed in v1alpha4, so setting it to nil in order to avoid v1alpha3 --> --> v1alpha3 round trip errors. + obj.Data = nil +} diff --git a/exp/api/v1alpha3/zz_generated.conversion.go b/exp/api/v1alpha3/zz_generated.conversion.go index 258e74660f90..bca7b16deac6 100644 --- a/exp/api/v1alpha3/zz_generated.conversion.go +++ b/exp/api/v1alpha3/zz_generated.conversion.go @@ -39,11 +39,6 @@ func init() { // RegisterConversions adds conversion functions to the given scheme. // Public to allow building arbitrary schemes. func RegisterConversions(s *runtime.Scheme) error { - if err := s.AddGeneratedConversionFunc((*v1beta1.MachinePool)(nil), (*MachinePool)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_MachinePool_To_v1alpha3_MachinePool(a.(*v1beta1.MachinePool), b.(*MachinePool), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*MachinePoolList)(nil), (*v1beta1.MachinePoolList)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha3_MachinePoolList_To_v1beta1_MachinePoolList(a.(*MachinePoolList), b.(*v1beta1.MachinePoolList), scope) }); err != nil { @@ -79,6 +74,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1beta1.MachinePool)(nil), (*MachinePool)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_MachinePool_To_v1alpha3_MachinePool(a.(*v1beta1.MachinePool), b.(*MachinePool), scope) + }); err != nil { + return err + } return nil } @@ -104,11 +104,6 @@ func autoConvert_v1beta1_MachinePool_To_v1alpha3_MachinePool(in *v1beta1.Machine return nil } -// Convert_v1beta1_MachinePool_To_v1alpha3_MachinePool is an autogenerated conversion function. -func Convert_v1beta1_MachinePool_To_v1alpha3_MachinePool(in *v1beta1.MachinePool, out *MachinePool, s conversion.Scope) error { - return autoConvert_v1beta1_MachinePool_To_v1alpha3_MachinePool(in, out, s) -} - func autoConvert_v1alpha3_MachinePoolList_To_v1beta1_MachinePoolList(in *MachinePoolList, out *v1beta1.MachinePoolList, s conversion.Scope) error { out.ListMeta = in.ListMeta if in.Items != nil { diff --git a/exp/api/v1alpha4/conversion.go b/exp/api/v1alpha4/conversion.go new file mode 100644 index 000000000000..409d122c80f4 --- /dev/null +++ b/exp/api/v1alpha4/conversion.go @@ -0,0 +1,46 @@ +/* +Copyright 2021 The Kubernetes Authors. + +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 v1alpha4 + +import ( + v1beta1 "sigs.k8s.io/cluster-api/exp/api/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/conversion" +) + +func (src *MachinePool) ConvertTo(dstRaw conversion.Hub) error { + dst := dstRaw.(*v1beta1.MachinePool) + + return Convert_v1alpha4_MachinePool_To_v1beta1_MachinePool(src, dst, nil) +} + +func (dst *MachinePool) ConvertFrom(srcRaw conversion.Hub) error { + src := srcRaw.(*v1beta1.MachinePool) + + return Convert_v1beta1_MachinePool_To_v1alpha4_MachinePool(src, dst, nil) +} + +func (src *MachinePoolList) ConvertTo(dstRaw conversion.Hub) error { + dst := dstRaw.(*v1beta1.MachinePoolList) + + return Convert_v1alpha4_MachinePoolList_To_v1beta1_MachinePoolList(src, dst, nil) +} + +func (dst *MachinePoolList) ConvertFrom(srcRaw conversion.Hub) error { + src := srcRaw.(*v1beta1.MachinePoolList) + + return Convert_v1beta1_MachinePoolList_To_v1alpha4_MachinePoolList(src, dst, nil) +} diff --git a/exp/api/v1alpha4/conversion_test.go b/exp/api/v1alpha4/conversion_test.go new file mode 100644 index 000000000000..0e50bdd07a89 --- /dev/null +++ b/exp/api/v1alpha4/conversion_test.go @@ -0,0 +1,33 @@ +/* +Copyright 2021 The Kubernetes Authors. + +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 v1alpha4 + +import ( + "testing" + + "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" + clusterv1exp "sigs.k8s.io/cluster-api/exp/api/v1beta1" + utilconversion "sigs.k8s.io/cluster-api/util/conversion" +) + +func TestFuzzyConversion(t *testing.T) { + t.Run("for MachinePool", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{ + Hub: &clusterv1exp.MachinePool{}, + Spoke: &MachinePool{}, + FuzzerFuncs: []fuzzer.FuzzerFuncs{}, + })) +} diff --git a/exp/api/v1beta1/conversion.go b/exp/api/v1beta1/conversion.go new file mode 100644 index 000000000000..91e5b549c388 --- /dev/null +++ b/exp/api/v1beta1/conversion.go @@ -0,0 +1,20 @@ +/* +Copyright 2021 The Kubernetes Authors. + +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 v1beta1 + +func (*MachinePool) Hub() {} +func (*MachinePoolList) Hub() {} diff --git a/util/conversion/conversion.go b/util/conversion/conversion.go index 2e1949260ddf..6bf24965a3ec 100644 --- a/util/conversion/conversion.go +++ b/util/conversion/conversion.go @@ -218,6 +218,7 @@ type FuzzTestFuncInput struct { Spoke conversion.Convertible SpokeAfterMutation func(convertible conversion.Convertible) SkipSpokeAnnotationCleanup bool + SkipHubAnnotationCleanup bool FuzzerFuncs []fuzzer.FuzzerFuncs } @@ -278,6 +279,13 @@ func FuzzTestFunc(input FuzzTestFuncInput) func(*testing.T) { hubAfter := input.Hub.DeepCopyObject().(conversion.Hub) g.Expect(dstCopy.ConvertTo(hubAfter)).To(gomega.Succeed()) + // Remove data annotation eventually added by ConvertTo for avoiding data loss in spoke-hub-spoke round trips + // NOTE: There are use case when we want to skip this operation, e.g. if the spoke object does not have ObjectMeta (e.g. kubeadm types). + if !input.SkipHubAnnotationCleanup { + metaAfter := hubAfter.(metav1.Object) + delete(metaAfter.GetAnnotations(), DataAnnotation) + } + if input.HubAfterMutation != nil { input.HubAfterMutation(hubAfter) }