diff --git a/pkg/restore/apiservice_action.go b/pkg/restore/apiservice_action.go index 97c4dc808..7f817a59e 100644 --- a/pkg/restore/apiservice_action.go +++ b/pkg/restore/apiservice_action.go @@ -17,10 +17,7 @@ limitations under the License. package restore import ( - "github.com/pkg/errors" "github.com/sirupsen/logrus" - "k8s.io/apimachinery/pkg/runtime" - apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" "k8s.io/kube-aggregator/pkg/controllers/autoregister" "github.com/vmware-tanzu/velero/pkg/plugin/velero" @@ -41,20 +38,14 @@ func NewAPIServiceAction(logger logrus.FieldLogger) *APIServiceAction { func (a *APIServiceAction) AppliesTo() (velero.ResourceSelector, error) { return velero.ResourceSelector{ IncludedResources: []string{"apiservices"}, + LabelSelector: autoregister.AutoRegisterManagedLabel, }, nil } func (a *APIServiceAction) Execute(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) { - apiService := new(apiregistrationv1.APIService) - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(input.Item.UnstructuredContent(), apiService); err != nil { - return nil, errors.WithStack(err) - } + a.logger.Info("Executing APIServiceAction") + defer a.logger.Info("Done executing APIServiceAction") - output := velero.NewRestoreItemActionExecuteOutput(input.Item) - - if _, ok := apiService.Labels[autoregister.AutoRegisterManagedLabel]; ok { - output = output.WithoutRestore() - } - - return output, nil + a.logger.Infof("Skipping restore of APIService as it is managed by Kubernetes") + return velero.NewRestoreItemActionExecuteOutput(input.Item).WithoutRestore(), nil } diff --git a/pkg/restore/apiservice_action_test.go b/pkg/restore/apiservice_action_test.go index 3cf2fce8b..81f4a6171 100644 --- a/pkg/restore/apiservice_action_test.go +++ b/pkg/restore/apiservice_action_test.go @@ -1,5 +1,5 @@ /* -Copyright 2017 the Velero contributors. +Copyright the Velero contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,129 +19,35 @@ package restore import ( "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" - "k8s.io/kube-aggregator/pkg/controllers/autoregister" "github.com/vmware-tanzu/velero/pkg/plugin/velero" velerotest "github.com/vmware-tanzu/velero/pkg/test" ) -func TestAPIServiceActionExecute(t *testing.T) { - tests := []struct { - name string - obj apiregistrationv1.APIService - skipRestore bool - }{ - { - name: "APIService with no labels should be restored without modification", - obj: apiregistrationv1.APIService{ - ObjectMeta: metav1.ObjectMeta{ - Name: "v1.foo.velero.io", - }, - }, - skipRestore: false, - }, - { - name: "Non-Local APIService without Kubernetes managed label should be restored without modification", - obj: apiregistrationv1.APIService{ - ObjectMeta: metav1.ObjectMeta{ - Name: "v1.foo.velero.io", - Labels: map[string]string{ - "component": "velero", - }, - }, - Spec: apiregistrationv1.APIServiceSpec{ - Group: "velero.io", - Version: "v1", - Service: &apiregistrationv1.ServiceReference{ - Namespace: "velero", - Name: "velero-aggregated-api-server", - }, - }, - }, - skipRestore: false, - }, - { - name: "APIService with Kubernetes managed label with 'true' value should not be restored", - obj: apiregistrationv1.APIService{ - ObjectMeta: metav1.ObjectMeta{ - Name: "v1.foo.velero.io", - Labels: map[string]string{ - autoregister.AutoRegisterManagedLabel: "true", - }, - }, - }, - skipRestore: true, - }, - { - name: "APIService with Kubernetes managed label with 'onstart' value should not be restored", - obj: apiregistrationv1.APIService{ - ObjectMeta: metav1.ObjectMeta{ - Name: "v1.foo.velero.io", - Labels: map[string]string{ - autoregister.AutoRegisterManagedLabel: "onstart", - }, - }, - }, - skipRestore: true, - }, - { - name: "APIService with Kubernetes managed label with any value should not be restored", - obj: apiregistrationv1.APIService{ - ObjectMeta: metav1.ObjectMeta{ - Name: "v1.foo.velero.io", - Labels: map[string]string{ - autoregister.AutoRegisterManagedLabel: "randomvalue", - }, - }, - }, - skipRestore: true, - }, - { - name: "Non-Local APIService with Kubernetes managed label should not be restored", - obj: apiregistrationv1.APIService{ - ObjectMeta: metav1.ObjectMeta{ - Name: "v1.foo.velero.io", - Labels: map[string]string{ - autoregister.AutoRegisterManagedLabel: "onstart", - }, - }, - Spec: apiregistrationv1.APIServiceSpec{ - Group: "velero.io", - Version: "v1", - Service: &apiregistrationv1.ServiceReference{ - Namespace: "velero", - Name: "velero-aggregated-api-server", - }, - }, - }, - skipRestore: true, +func TestAPIServiceActionExecuteSkipsRestore(t *testing.T) { + obj := apiregistrationv1.APIService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "v1.test.velero.io", }, } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - action := NewAPIServiceAction(velerotest.NewLogger()) + unstructuredAPIService, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&obj) + require.NoError(t, err) - unstructuredAPIService, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&test.obj) - require.NoError(t, err) + action := NewAPIServiceAction(velerotest.NewLogger()) + res, err := action.Execute(&velero.RestoreItemActionExecuteInput{ + Item: &unstructured.Unstructured{Object: unstructuredAPIService}, + ItemFromBackup: &unstructured.Unstructured{Object: unstructuredAPIService}, + }) + require.NoError(t, err) - res, err := action.Execute(&velero.RestoreItemActionExecuteInput{ - Item: &unstructured.Unstructured{Object: unstructuredAPIService}, - ItemFromBackup: &unstructured.Unstructured{Object: unstructuredAPIService}, - }) - - require.NoError(t, err) - - var apiService apiregistrationv1.APIService - require.NoError(t, runtime.DefaultUnstructuredConverter.FromUnstructured(res.UpdatedItem.UnstructuredContent(), &apiService)) - assert.Equal(t, test.obj, apiService) - assert.Equal(t, test.skipRestore, res.SkipRestore) - }) - } + var apiService apiregistrationv1.APIService + require.NoError(t, runtime.DefaultUnstructuredConverter.FromUnstructured(res.UpdatedItem.UnstructuredContent(), &apiService)) + require.Equal(t, obj, apiService) + require.Equal(t, true, res.SkipRestore) } diff --git a/pkg/restore/restore_test.go b/pkg/restore/restore_test.go index 945026396..274397862 100644 --- a/pkg/restore/restore_test.go +++ b/pkg/restore/restore_test.go @@ -1,5 +1,5 @@ /* -Copyright 2019 the Velero contributors. +Copyright the Velero contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -1139,6 +1139,22 @@ func TestRestoreActionsRunForCorrectItems(t *testing.T) { new(recordResourcesAction).ForNamespace("ns-1").ForResource("pods"): {"ns-1/pod-1"}, }, }, + { + name: "single action with a resource and label selector runs only for resources matching that label", + restore: defaultRestore().Result(), + backup: defaultBackup().Result(), + tarball: test.NewTarWriter(t). + AddItems("pods", + builder.ForPod("ns-1", "pod-1").ObjectMeta(builder.WithLabels("restore-resource", "true")).Result(), + builder.ForPod("ns-1", "pod-2").ObjectMeta(builder.WithLabels("do-not-restore-resource", "true")).Result(), + builder.ForPod("ns-2", "pod-1").Result(), + builder.ForPod("ns-2", "pod-2").ObjectMeta(builder.WithLabels("restore-resource")).Result(), + ).Done(), + apiResources: []*test.APIResource{test.Pods()}, + actions: map[*recordResourcesAction][]string{ + new(recordResourcesAction).ForResource("pods").ForLabelSelector("restore-resource"): {"ns-1/pod-1", "ns-2/pod-2"}, + }, + }, { name: "multiple actions, each with a different resource selector using short name, run for matching resources", restore: defaultRestore().Result(),