From 0070138c62403fc1afcd448ec8b873bbd91c2a89 Mon Sep 17 00:00:00 2001 From: Daniel Jiang Date: Tue, 22 Feb 2022 18:15:28 +0800 Subject: [PATCH] Bypass the remap CRD version plugin when v1beta1 CRD is not supported When velero is running on clusters that don't support v1beta1 CRD, the plugin will not try to backup v1beta1 CRD. The plugin should be kept for backward compatibility. It will be removed when velero drop the support for k8s v1.21 Signed-off-by: Daniel Jiang --- changelogs/unreleased/4686-reasonerjt | 1 + pkg/backup/remap_crd_version_action.go | 32 +++++++++++-- pkg/backup/remap_crd_version_action_test.go | 53 +++++++++++++++++++-- pkg/cmd/server/plugin/plugin.go | 11 ++++- 4 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 changelogs/unreleased/4686-reasonerjt diff --git a/changelogs/unreleased/4686-reasonerjt b/changelogs/unreleased/4686-reasonerjt new file mode 100644 index 000000000..ed64de8f6 --- /dev/null +++ b/changelogs/unreleased/4686-reasonerjt @@ -0,0 +1 @@ +Bypass the remap CRD version plugin when v1beta1 CRD is not supported diff --git a/pkg/backup/remap_crd_version_action.go b/pkg/backup/remap_crd_version_action.go index b282e876e..d54f018ca 100644 --- a/pkg/backup/remap_crd_version_action.go +++ b/pkg/backup/remap_crd_version_action.go @@ -30,6 +30,8 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + velerodiscovery "github.com/vmware-tanzu/velero/pkg/discovery" + v1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" "github.com/vmware-tanzu/velero/pkg/plugin/velero" ) @@ -37,13 +39,14 @@ import ( // RemapCRDVersionAction inspects CustomResourceDefinition and decides if it is a v1 // CRD that needs to be backed up as v1beta1. type RemapCRDVersionAction struct { - logger logrus.FieldLogger - betaCRDClient apiextv1beta1client.CustomResourceDefinitionInterface + logger logrus.FieldLogger + betaCRDClient apiextv1beta1client.CustomResourceDefinitionInterface + discoveryHelper velerodiscovery.Helper } // NewRemapCRDVersionAction instantiates a new RemapCRDVersionAction plugin. -func NewRemapCRDVersionAction(logger logrus.FieldLogger, betaCRDClient apiextv1beta1client.CustomResourceDefinitionInterface) *RemapCRDVersionAction { - return &RemapCRDVersionAction{logger: logger, betaCRDClient: betaCRDClient} +func NewRemapCRDVersionAction(logger logrus.FieldLogger, betaCRDClient apiextv1beta1client.CustomResourceDefinitionInterface, discoveryHelper velerodiscovery.Helper) *RemapCRDVersionAction { + return &RemapCRDVersionAction{logger: logger, betaCRDClient: betaCRDClient, discoveryHelper: discoveryHelper} } // AppliesTo selects the resources the plugin should run against. In this case, CustomResourceDefinitions. @@ -68,7 +71,26 @@ func (a *RemapCRDVersionAction) Execute(item runtime.Unstructured, backup *v1.Ba return item, nil, nil } - // We've got a v1 CRD, so proceed. + // This plugin will exit if the CRD was installed via v1beta1 but the cluster does not support v1beta1 CRD + supportv1b1 := false +CheckVersion: + for _, g := range a.discoveryHelper.APIGroups() { + if g.Name == apiextv1.GroupName { + for _, v := range g.Versions { + if v.Version == apiextv1beta1.SchemeGroupVersion.Version { + supportv1b1 = true + break CheckVersion + } + } + + } + } + if !supportv1b1 { + a.logger.Info("Exiting RemapCRDVersionAction, the cluster does not support v1beta1 CRD") + return item, nil, nil + } + + // We've got a v1 CRD and the cluster supports v1beta1 CRD, so proceed. var crd apiextv1.CustomResourceDefinition // Do not use runtime.DefaultUnstructuredConverter.FromUnstructured here because it has a bug when converting integers/whole diff --git a/pkg/backup/remap_crd_version_action_test.go b/pkg/backup/remap_crd_version_action_test.go index 9308ea049..ea679ef0e 100644 --- a/pkg/backup/remap_crd_version_action_test.go +++ b/pkg/backup/remap_crd_version_action_test.go @@ -32,6 +32,8 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + velerodiscovery "github.com/vmware-tanzu/velero/pkg/discovery" + v1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" "github.com/vmware-tanzu/velero/pkg/builder" velerotest "github.com/vmware-tanzu/velero/pkg/test" @@ -48,8 +50,7 @@ func TestRemapCRDVersionAction(t *testing.T) { c := b.Result() _, err := betaClient.Create(context.TODO(), c, metav1.CreateOptions{}) require.NoError(t, err) - - a := NewRemapCRDVersionAction(velerotest.NewLogger(), betaClient) + a := NewRemapCRDVersionAction(velerotest.NewLogger(), betaClient, fakeDiscoveryHelper()) t.Run("Test a v1 CRD without any Schema information", func(t *testing.T) { b := builder.ForV1CustomResourceDefinition("test.velero.io") @@ -109,6 +110,33 @@ func TestRemapCRDVersionAction(t *testing.T) { require.NoError(t, err) assert.Equal(t, "apiextensions.k8s.io/v1beta1", item.UnstructuredContent()["apiVersion"]) }) + + t.Run("When the cluster only supports v1 CRD, v1 CRD will be returned even the input has Spec.PreserveUnknownFields set to true (issue 4080)", func(t *testing.T) { + a.discoveryHelper = &velerotest.FakeDiscoveryHelper{ + APIGroupsList: []metav1.APIGroup{ + { + Name: apiextv1.GroupName, + Versions: []metav1.GroupVersionForDiscovery{ + { + Version: apiextv1.SchemeGroupVersion.Version, + }, + }, + }, + }, + } + b := builder.ForV1CustomResourceDefinition("test.velero.io") + b.PreserveUnknownFields(true) + c := b.Result() + obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&c) + require.NoError(t, err) + + item, _, err := a.Execute(&unstructured.Unstructured{Object: obj}, backup) + require.NoError(t, err) + assert.Equal(t, "apiextensions.k8s.io/v1", item.UnstructuredContent()["apiVersion"]) + // set it back to the default one + a.discoveryHelper = fakeDiscoveryHelper() + }) + } // TestRemapCRDVersionActionData tests the RemapCRDVersionAction plugin against actual CRD to confirm that the v1beta1 version is returned when the v1 version is passed in to the plugin. @@ -116,8 +144,7 @@ func TestRemapCRDVersionActionData(t *testing.T) { backup := &v1.Backup{} clientset := apiextfakes.NewSimpleClientset() betaClient := clientset.ApiextensionsV1beta1().CustomResourceDefinitions() - - a := NewRemapCRDVersionAction(velerotest.NewLogger(), betaClient) + a := NewRemapCRDVersionAction(velerotest.NewLogger(), betaClient, fakeDiscoveryHelper()) tests := []struct { crd string @@ -192,3 +219,21 @@ func TestRemapCRDVersionActionData(t *testing.T) { } } + +func fakeDiscoveryHelper() velerodiscovery.Helper { + return &velerotest.FakeDiscoveryHelper{ + APIGroupsList: []metav1.APIGroup{ + { + Name: apiextv1.GroupName, + Versions: []metav1.GroupVersionForDiscovery{ + { + Version: apiextv1beta1.SchemeGroupVersion.Version, + }, + { + Version: apiextv1.SchemeGroupVersion.Version, + }, + }, + }, + }, + } +} diff --git a/pkg/cmd/server/plugin/plugin.go b/pkg/cmd/server/plugin/plugin.go index 507200266..5c833d76a 100644 --- a/pkg/cmd/server/plugin/plugin.go +++ b/pkg/cmd/server/plugin/plugin.go @@ -110,7 +110,16 @@ func newRemapCRDVersionAction(f client.Factory) veleroplugin.HandlerInitializer return nil, err } - return backup.NewRemapCRDVersionAction(logger, client.ApiextensionsV1beta1().CustomResourceDefinitions()), nil + clientset, err := f.KubeClient() + if err != nil { + return nil, err + } + discoveryHelper, err := velerodiscovery.NewHelper(clientset.Discovery(), logger) + if err != nil { + return nil, err + } + + return backup.NewRemapCRDVersionAction(logger, client.ApiextensionsV1beta1().CustomResourceDefinitions(), discoveryHelper), nil } }