From f6cd53c6cba384e86217b6b207a1e22de48b372d Mon Sep 17 00:00:00 2001 From: Rafael Brito Date: Thu, 19 Mar 2020 11:18:05 -0500 Subject: [PATCH] Adding k8s version labels on backup CRD #2342 (#2346) Signed-off-by: Rafael Brito --- changelogs/unreleased/2346-brito-rafa | 1 + pkg/apis/velero/v1/labels_annotations.go | 12 ++++ pkg/cmd/server/server.go | 1 + pkg/controller/backup_controller.go | 10 +++- pkg/controller/backup_controller_test.go | 75 +++++++++++++++++++++--- pkg/discovery/helper.go | 29 +++++++-- pkg/test/fake_discovery_helper.go | 22 +++++++ 7 files changed, 136 insertions(+), 14 deletions(-) create mode 100644 changelogs/unreleased/2346-brito-rafa diff --git a/changelogs/unreleased/2346-brito-rafa b/changelogs/unreleased/2346-brito-rafa new file mode 100644 index 000000000..0adc2b05e --- /dev/null +++ b/changelogs/unreleased/2346-brito-rafa @@ -0,0 +1 @@ +adding labels on backup CRD for k8s major, minor and git versions diff --git a/pkg/apis/velero/v1/labels_annotations.go b/pkg/apis/velero/v1/labels_annotations.go index 04fb355c5..f0a4e0064 100644 --- a/pkg/apis/velero/v1/labels_annotations.go +++ b/pkg/apis/velero/v1/labels_annotations.go @@ -50,4 +50,16 @@ const ( // ResticVolumeNamespaceLabel is the label key used to identify which // namespace a restic repository stores pod volume backups for. ResticVolumeNamespaceLabel = "velero.io/volume-namespace" + + // SourceClusterK8sVersionLabel is the label key used to identify the k8s + // git version of the backup , i.e. v1.16.4 + SourceClusterK8sGitVersionLabel = "velero.io/source-cluster-k8s-gitversion" + + // SourceClusterK8sMajorVersionLabel is the label key used to identify the k8s + // major version of the backup , i.e. 1 + SourceClusterK8sMajorVersionLabel = "velero.io/source-cluster-k8s-major-version" + + // SourceClusterK8sMajorVersionLabel is the label key used to identify the k8s + // minor version of the backup , i.e. 16 + SourceClusterK8sMinorVersionLabel = "velero.io/source-cluster-k8s-minor-version" ) diff --git a/pkg/cmd/server/server.go b/pkg/cmd/server/server.go index 0601614fe..2bc9bf93a 100644 --- a/pkg/cmd/server/server.go +++ b/pkg/cmd/server/server.go @@ -587,6 +587,7 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string backupController := controller.NewBackupController( s.sharedInformerFactory.Velero().V1().Backups(), s.veleroClient.VeleroV1(), + s.discoveryHelper, backupper, s.logger, s.logLevel, diff --git a/pkg/controller/backup_controller.go b/pkg/controller/backup_controller.go index 32b40da61..131f33ac5 100644 --- a/pkg/controller/backup_controller.go +++ b/pkg/controller/backup_controller.go @@ -39,6 +39,7 @@ import ( velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" pkgbackup "github.com/vmware-tanzu/velero/pkg/backup" + "github.com/vmware-tanzu/velero/pkg/discovery" velerov1client "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1" velerov1informers "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions/velero/v1" velerov1listers "github.com/vmware-tanzu/velero/pkg/generated/listers/velero/v1" @@ -55,7 +56,7 @@ import ( type backupController struct { *genericController - + discoveryHelper discovery.Helper backupper pkgbackup.Backupper lister velerov1listers.BackupLister client velerov1client.BackupsGetter @@ -76,6 +77,7 @@ type backupController struct { func NewBackupController( backupInformer velerov1informers.BackupInformer, client velerov1client.BackupsGetter, + discoveryHelper discovery.Helper, backupper pkgbackup.Backupper, logger logrus.FieldLogger, backupLogLevel logrus.Level, @@ -91,6 +93,7 @@ func NewBackupController( ) Interface { c := &backupController{ genericController: newGenericController("backup", logger), + discoveryHelper: discoveryHelper, backupper: backupper, lister: backupInformer.Lister(), client: client, @@ -329,6 +332,11 @@ func (c *backupController) prepareBackupRequest(backup *velerov1api.Backup) *pkg } request.Labels[velerov1api.StorageLocationLabel] = label.GetValidName(request.Spec.StorageLocation) + // Getting all information of cluster version - useful for future skip-level migration + request.Labels[velerov1api.SourceClusterK8sGitVersionLabel] = label.GetValidName(c.discoveryHelper.ServerVersion().String()) + request.Labels[velerov1api.SourceClusterK8sMajorVersionLabel] = label.GetValidName(c.discoveryHelper.ServerVersion().Major) + request.Labels[velerov1api.SourceClusterK8sMinorVersionLabel] = label.GetValidName(c.discoveryHelper.ServerVersion().Minor) + // validate the included/excluded resources for _, err := range collections.ValidateIncludesExcludes(request.Spec.IncludedResources, request.Spec.ExcludedResources) { request.Status.ValidationErrors = append(request.Status.ValidationErrors, fmt.Sprintf("Invalid included/excluded resource lists: %v", err)) diff --git a/pkg/controller/backup_controller_test.go b/pkg/controller/backup_controller_test.go index e1899abaa..6d1b750fe 100644 --- a/pkg/controller/backup_controller_test.go +++ b/pkg/controller/backup_controller_test.go @@ -33,9 +33,12 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/clock" + "k8s.io/apimachinery/pkg/version" + velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" pkgbackup "github.com/vmware-tanzu/velero/pkg/backup" "github.com/vmware-tanzu/velero/pkg/builder" + "github.com/vmware-tanzu/velero/pkg/discovery" "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/fake" informers "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions" "github.com/vmware-tanzu/velero/pkg/metrics" @@ -44,6 +47,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt" pluginmocks "github.com/vmware-tanzu/velero/pkg/plugin/mocks" "github.com/vmware-tanzu/velero/pkg/plugin/velero" + velerotest "github.com/vmware-tanzu/velero/pkg/test" "github.com/vmware-tanzu/velero/pkg/util/logging" ) @@ -168,8 +172,13 @@ func TestProcessBackupValidationFailures(t *testing.T) { logger = logging.DefaultLogger(logrus.DebugLevel, formatFlag) ) + apiServer := velerotest.NewAPIServer(t) + discoveryHelper, err := discovery.NewHelper(apiServer.DiscoveryClient, logger) + require.NoError(t, err) + c := &backupController{ genericController: newGenericController("backup-test", logger), + discoveryHelper: discoveryHelper, client: clientset.VeleroV1(), lister: sharedInformers.Velero().V1().Backups().Lister(), backupLocationLister: sharedInformers.Velero().V1().BackupStorageLocations().Lister(), @@ -236,8 +245,13 @@ func TestBackupLocationLabel(t *testing.T) { logger = logging.DefaultLogger(logrus.DebugLevel, formatFlag) ) + apiServer := velerotest.NewAPIServer(t) + discoveryHelper, err := discovery.NewHelper(apiServer.DiscoveryClient, logger) + require.NoError(t, err) + c := &backupController{ genericController: newGenericController("backup-test", logger), + discoveryHelper: discoveryHelper, client: clientset.VeleroV1(), lister: sharedInformers.Velero().V1().Backups().Lister(), backupLocationLister: sharedInformers.Velero().V1().BackupStorageLocations().Lister(), @@ -293,8 +307,14 @@ func TestDefaultBackupTTL(t *testing.T) { ) t.Run(test.name, func(t *testing.T) { + + apiServer := velerotest.NewAPIServer(t) + discoveryHelper, err := discovery.NewHelper(apiServer.DiscoveryClient, logger) + require.NoError(t, err) + c := &backupController{ genericController: newGenericController("backup-test", logger), + discoveryHelper: discoveryHelper, backupLocationLister: sharedInformers.Velero().V1().BackupStorageLocations().Lister(), snapshotLocationLister: sharedInformers.Velero().V1().VolumeSnapshotLocations().Lister(), defaultBackupTTL: defaultBackupTTL.Duration, @@ -340,7 +360,10 @@ func TestProcessBackupCompletions(t *testing.T) { Namespace: velerov1api.DefaultNamespace, Name: "backup-1", Labels: map[string]string{ - "velero.io/storage-location": "loc-1", + "velero.io/source-cluster-k8s-major-version": "1", + "velero.io/source-cluster-k8s-minor-version": "16", + "velero.io/source-cluster-k8s-gitversion": "v1.16.4", + "velero.io/storage-location": "loc-1", }, }, Spec: velerov1api.BackupSpec{ @@ -368,7 +391,10 @@ func TestProcessBackupCompletions(t *testing.T) { Namespace: velerov1api.DefaultNamespace, Name: "backup-1", Labels: map[string]string{ - "velero.io/storage-location": "alt-loc", + "velero.io/source-cluster-k8s-major-version": "1", + "velero.io/source-cluster-k8s-minor-version": "16", + "velero.io/source-cluster-k8s-gitversion": "v1.16.4", + "velero.io/storage-location": "alt-loc", }, }, Spec: velerov1api.BackupSpec{ @@ -399,7 +425,10 @@ func TestProcessBackupCompletions(t *testing.T) { Namespace: velerov1api.DefaultNamespace, Name: "backup-1", Labels: map[string]string{ - "velero.io/storage-location": "read-write", + "velero.io/source-cluster-k8s-major-version": "1", + "velero.io/source-cluster-k8s-minor-version": "16", + "velero.io/source-cluster-k8s-gitversion": "v1.16.4", + "velero.io/storage-location": "read-write", }, }, Spec: velerov1api.BackupSpec{ @@ -427,7 +456,10 @@ func TestProcessBackupCompletions(t *testing.T) { Namespace: velerov1api.DefaultNamespace, Name: "backup-1", Labels: map[string]string{ - "velero.io/storage-location": "loc-1", + "velero.io/source-cluster-k8s-major-version": "1", + "velero.io/source-cluster-k8s-minor-version": "16", + "velero.io/source-cluster-k8s-gitversion": "v1.16.4", + "velero.io/storage-location": "loc-1", }, }, Spec: velerov1api.BackupSpec{ @@ -457,7 +489,10 @@ func TestProcessBackupCompletions(t *testing.T) { Namespace: velerov1api.DefaultNamespace, Name: "backup-1", Labels: map[string]string{ - "velero.io/storage-location": "loc-1", + "velero.io/source-cluster-k8s-major-version": "1", + "velero.io/source-cluster-k8s-minor-version": "16", + "velero.io/source-cluster-k8s-gitversion": "v1.16.4", + "velero.io/storage-location": "loc-1", }, }, Spec: velerov1api.BackupSpec{ @@ -488,7 +523,10 @@ func TestProcessBackupCompletions(t *testing.T) { Namespace: velerov1api.DefaultNamespace, Name: "backup-1", Labels: map[string]string{ - "velero.io/storage-location": "loc-1", + "velero.io/source-cluster-k8s-major-version": "1", + "velero.io/source-cluster-k8s-minor-version": "16", + "velero.io/source-cluster-k8s-gitversion": "v1.16.4", + "velero.io/storage-location": "loc-1", }, }, Spec: velerov1api.BackupSpec{ @@ -517,7 +555,10 @@ func TestProcessBackupCompletions(t *testing.T) { Namespace: velerov1api.DefaultNamespace, Name: "backup-1", Labels: map[string]string{ - "velero.io/storage-location": "loc-1", + "velero.io/source-cluster-k8s-major-version": "1", + "velero.io/source-cluster-k8s-minor-version": "16", + "velero.io/source-cluster-k8s-gitversion": "v1.16.4", + "velero.io/storage-location": "loc-1", }, }, Spec: velerov1api.BackupSpec{ @@ -546,8 +587,26 @@ func TestProcessBackupCompletions(t *testing.T) { backupper = new(fakeBackupper) ) + apiServer := velerotest.NewAPIServer(t) + + apiServer.DiscoveryClient.FakedServerVersion = &version.Info{ + Major: "1", + Minor: "16", + GitVersion: "v1.16.4", + GitCommit: "FakeTest", + GitTreeState: "", + BuildDate: "", + GoVersion: "", + Compiler: "", + Platform: "", + } + + discoveryHelper, err := discovery.NewHelper(apiServer.DiscoveryClient, logger) + require.NoError(t, err) + c := &backupController{ genericController: newGenericController("backup-test", logger), + discoveryHelper: discoveryHelper, client: clientset.VeleroV1(), lister: sharedInformers.Velero().V1().Backups().Lister(), backupLocationLister: sharedInformers.Velero().V1().BackupStorageLocations().Lister(), @@ -584,7 +643,7 @@ func TestProcessBackupCompletions(t *testing.T) { require.NoError(t, sharedInformers.Velero().V1().Backups().Informer().GetStore().Add(test.backup)) // add the default backup storage location to the clientset and the informer/lister store - _, err := clientset.VeleroV1().BackupStorageLocations(defaultBackupLocation.Namespace).Create(defaultBackupLocation) + _, err = clientset.VeleroV1().BackupStorageLocations(defaultBackupLocation.Namespace).Create(defaultBackupLocation) require.NoError(t, err) require.NoError(t, sharedInformers.Velero().V1().BackupStorageLocations().Informer().GetStore().Add(defaultBackupLocation)) diff --git a/pkg/discovery/helper.go b/pkg/discovery/helper.go index fbdc9bc8c..560ff7076 100644 --- a/pkg/discovery/helper.go +++ b/pkg/discovery/helper.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/version" "k8s.io/client-go/discovery" "k8s.io/client-go/restmapper" @@ -49,6 +50,10 @@ type Helper interface { // APIGroups gets the current set of supported APIGroups // in the cluster. APIGroups() []metav1.APIGroup + + // ServerVersion retrieves and parses the server's k8s version (git version) + // in the cluster. + ServerVersion() *version.Info } type serverResourcesInterface interface { @@ -60,11 +65,12 @@ type helper struct { logger logrus.FieldLogger // lock guards mapper, resources and resourcesMap - lock sync.RWMutex - mapper meta.RESTMapper - resources []*metav1.APIResourceList - resourcesMap map[schema.GroupVersionResource]metav1.APIResource - apiGroups []metav1.APIGroup + lock sync.RWMutex + mapper meta.RESTMapper + resources []*metav1.APIResourceList + resourcesMap map[schema.GroupVersionResource]metav1.APIResource + apiGroups []metav1.APIGroup + serverVersion *version.Info } var _ Helper = &helper{} @@ -143,6 +149,13 @@ func (h *helper) Refresh() error { } h.apiGroups = apiGroupList.Groups + serverVersion, err := h.discoveryClient.ServerVersion() + if err != nil { + return errors.WithStack(err) + } + + h.serverVersion = serverVersion + return nil } @@ -200,3 +213,9 @@ func (h *helper) APIGroups() []metav1.APIGroup { defer h.lock.RUnlock() return h.apiGroups } + +func (h *helper) ServerVersion() *version.Info { + h.lock.RLock() + defer h.lock.RUnlock() + return h.serverVersion +} diff --git a/pkg/test/fake_discovery_helper.go b/pkg/test/fake_discovery_helper.go index e48ce193b..2b94b86dc 100644 --- a/pkg/test/fake_discovery_helper.go +++ b/pkg/test/fake_discovery_helper.go @@ -23,6 +23,7 @@ import ( "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/version" "k8s.io/client-go/discovery" ) @@ -31,6 +32,7 @@ type FakeDiscoveryHelper struct { Mapper meta.RESTMapper AutoReturnResource bool APIGroupsList []metav1.APIGroup + ServerVersionData *version.Info } func NewFakeDiscoveryHelper(autoReturnResource bool, resources map[schema.GroupVersionResource]schema.GroupVersionResource) *FakeDiscoveryHelper { @@ -70,6 +72,22 @@ func NewFakeDiscoveryHelper(autoReturnResource bool, resources map[schema.GroupV helper.ResourceList = append(helper.ResourceList, &metav1.APIResourceList{GroupVersion: group, APIResources: resources}) } + // FakeTest of version.Info + + serverVersion := &version.Info{ + Major: "1", + Minor: "16", + GitVersion: "v1.16.4", + GitCommit: "FakeTest", + GitTreeState: "", + BuildDate: "", + GoVersion: "", + Compiler: "", + Platform: "", + } + + helper.ServerVersionData = serverVersion + return helper } @@ -149,3 +167,7 @@ func NewFakeServerResourcesInterface(resourceList []*metav1.APIResourceList, fai } return helper } + +func (dh *FakeDiscoveryHelper) ServerVersion() *version.Info { + return dh.ServerVersionData +}