Skip to content

Commit

Permalink
Remove dependency of the legacy client code.
Browse files Browse the repository at this point in the history
Signed-off-by: Xun Jiang <jxun@vmware.com>
  • Loading branch information
Xun Jiang committed Jul 6, 2023
1 parent e54a8af commit 48711f8
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 90 deletions.
8 changes: 8 additions & 0 deletions pkg/apis/velero/v1/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ limitations under the License.

package v1

import "k8s.io/apimachinery/pkg/runtime/schema"

const (
// DefaultNamespace is the Kubernetes namespace that is used by default for
// the Velero server and API objects.
Expand Down Expand Up @@ -47,3 +49,9 @@ const (
// APIGroupVersionsFeatureFlag is the feature flag string that defines whether or not to handle multiple API Group Versions
APIGroupVersionsFeatureFlag = "EnableAPIGroupVersions"
)

var (
BackupGVR = schema.GroupVersionResource{Group: "velero.io", Version: "v1", Resource: "backups"}
ScheduleGVR = schema.GroupVersionResource{Group: "velero.io", Version: "v1", Resource: "schedules"}
VolumeSnapshotLocationGVR = schema.GroupVersionResource{Group: "velero.io", Version: "v1", Resource: "volumesnapshotlocations"}
)
27 changes: 19 additions & 8 deletions pkg/cmd/cli/backup/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
kubeerrs "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/dynamic/dynamicinformer"
"k8s.io/client-go/tools/cache"

velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
Expand All @@ -36,8 +40,6 @@ import (
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/util/flag"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
veleroclient "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned"
v1 "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions/velero/v1"
"github.com/vmware-tanzu/velero/pkg/util/collections"
)

Expand Down Expand Up @@ -107,7 +109,7 @@ type CreateOptions struct {
CSISnapshotTimeout time.Duration
ItemOperationTimeout time.Duration
ResPoliciesConfigmap string
client veleroclient.Interface
client dynamic.Interface
}

func NewCreateOptions() *CreateOptions {
Expand Down Expand Up @@ -203,7 +205,7 @@ func (o *CreateOptions) Validate(c *cobra.Command, args []string, f client.Facto
}

for _, loc := range o.SnapshotLocations {
if _, err := o.client.VeleroV1().VolumeSnapshotLocations(f.Namespace()).Get(context.TODO(), loc, metav1.GetOptions{}); err != nil {
if _, err := o.client.Resource(velerov1api.VolumeSnapshotLocationGVR).Namespace(f.Namespace()).Get(context.TODO(), loc, metav1.GetOptions{}); err != nil {
return err
}
}
Expand All @@ -216,7 +218,7 @@ func (o *CreateOptions) Complete(args []string, f client.Factory) error {
if len(args) > 0 {
o.Name = args[0]
}
client, err := f.Client()
client, err := f.DynamicClient()
if err != nil {
return err
}
Expand Down Expand Up @@ -246,7 +248,7 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error {

updates = make(chan *velerov1api.Backup)

backupInformer = v1.NewBackupInformer(o.client, f.Namespace(), 0, nil)
backupInformer = dynamicinformer.NewFilteredDynamicSharedInformerFactory(o.client, 0, f.Namespace(), nil).ForResource(velerov1api.BackupGVR).Informer()

backupInformer.AddEventHandler(
cache.FilteringResourceEventHandler{
Expand Down Expand Up @@ -278,7 +280,11 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error {
go backupInformer.Run(stop)
}

_, err = o.client.VeleroV1().Backups(backup.Namespace).Create(context.TODO(), backup, metav1.CreateOptions{})
backupObjMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(backup)
if err != nil {
return err
}
_, err = o.client.Resource(velerov1api.BackupGVR).Namespace(backup.Namespace).Create(context.TODO(), &unstructured.Unstructured{Object: backupObjMap}, metav1.CreateOptions{})
if err != nil {
return err
}
Expand Down Expand Up @@ -341,7 +347,12 @@ func (o *CreateOptions) BuildBackup(namespace string) (*velerov1api.Backup, erro
var backupBuilder *builder.BackupBuilder

if o.FromSchedule != "" {
schedule, err := o.client.VeleroV1().Schedules(namespace).Get(context.TODO(), o.FromSchedule, metav1.GetOptions{})
obj, err := o.client.Resource(velerov1api.ScheduleGVR).Namespace(namespace).Get(context.TODO(), o.FromSchedule, metav1.GetOptions{})
if err != nil {
return nil, err
}
schedule := new(velerov1api.Schedule)
err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), schedule)
if err != nil {
return nil, err
}
Expand Down
163 changes: 81 additions & 82 deletions pkg/cmd/cli/backup/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,21 @@ import (
"testing"
"time"

flag "github.com/spf13/pflag"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

flag "github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
dynamicfake "k8s.io/client-go/dynamic/fake"
clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"

velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/builder"

clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"

factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
cmdtest "github.com/vmware-tanzu/velero/pkg/cmd/test"
"github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/fake"
versionedmocks "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/mocks"
"github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/scheme"
velerov1mocks "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1/mocks"
"github.com/vmware-tanzu/velero/pkg/test"
)

Expand Down Expand Up @@ -77,27 +75,32 @@ func TestCreateOptions_BuildBackup(t *testing.T) {
func TestCreateOptions_BuildBackupFromSchedule(t *testing.T) {
o := NewCreateOptions()
o.FromSchedule = "test"
o.client = fake.NewSimpleClientset()

scheme := runtime.NewScheme()
err := velerov1api.AddToScheme(scheme)
require.NoError(t, err)
o.client = dynamicfake.NewSimpleDynamicClient(scheme)

t.Run("inexistent schedule", func(t *testing.T) {
_, err := o.BuildBackup(cmdtest.VeleroNameSpace)
assert.Error(t, err)
require.Error(t, err)
})

expectedBackupSpec := builder.ForBackup("test", cmdtest.VeleroNameSpace).IncludedNamespaces("test").Result().Spec
schedule := builder.ForSchedule(cmdtest.VeleroNameSpace, "test").Template(expectedBackupSpec).ObjectMeta(builder.WithLabels("velero.io/test", "true"), builder.WithAnnotations("velero.io/test", "true")).Result()
o.client.VeleroV1().Schedules(cmdtest.VeleroNameSpace).Create(context.TODO(), schedule, metav1.CreateOptions{})
scheduleObjMap, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(schedule)
o.client.Resource(velerov1api.ScheduleGVR).Namespace(cmdtest.VeleroNameSpace).Create(context.TODO(), &unstructured.Unstructured{Object: scheduleObjMap}, metav1.CreateOptions{})

t.Run("existing schedule", func(t *testing.T) {
backup, err := o.BuildBackup(cmdtest.VeleroNameSpace)
assert.NoError(t, err)
require.NoError(t, err)

assert.Equal(t, expectedBackupSpec, backup.Spec)
assert.Equal(t, map[string]string{
require.Equal(t, expectedBackupSpec, backup.Spec)
require.Equal(t, map[string]string{
"velero.io/test": "true",
velerov1api.ScheduleNameLabel: "test",
}, backup.GetLabels())
assert.Equal(t, map[string]string{
require.Equal(t, map[string]string{
"velero.io/test": "true",
}, backup.GetAnnotations())
})
Expand Down Expand Up @@ -145,6 +148,7 @@ func TestCreateCommand(t *testing.T) {
args := []string{name}

t.Run("create a backup create command with full options except fromSchedule and wait, then run by create option", func(t *testing.T) {

// create a factory
f := &factorymocks.Factory{}

Expand Down Expand Up @@ -203,79 +207,76 @@ func TestCreateCommand(t *testing.T) {
flags.Parse([]string{"--data-mover", dataMover})
//flags.Parse([]string{"--wait"})

backups := &velerov1mocks.BackupInterface{}
veleroV1 := &velerov1mocks.VeleroV1Interface{}
client := &versionedmocks.Interface{}
bk := &velerov1api.Backup{}
backups.On("Create", mock.Anything, mock.Anything, mock.Anything).Return(bk, nil)
veleroV1.On("Backups", mock.Anything).Return(backups, nil)
client.On("VeleroV1").Return(veleroV1, nil)
f.On("Client").Return(client, nil)
scheme := runtime.NewScheme()
err := velerov1api.AddToScheme(scheme)
require.NoError(t, err)
client := dynamicfake.NewSimpleDynamicClient(scheme)

f.On("DynamicClient").Return(client, nil)
f.On("Namespace").Return(mock.Anything)
f.On("KubebuilderClient").Return(nil, nil)

//Complete
e := o.Complete(args, f)
assert.NoError(t, e)
require.NoError(t, e)

//Validate
e = o.Validate(cmd, args, f)
assert.Contains(t, e.Error(), "include-resources, exclude-resources and include-cluster-resources are old filter parameters")
assert.Contains(t, e.Error(), "include-cluster-scoped-resources, exclude-cluster-scoped-resources, include-namespace-scoped-resources and exclude-namespace-scoped-resources are new filter parameters.\nThey cannot be used together")
require.Contains(t, e.Error(), "include-resources, exclude-resources and include-cluster-resources are old filter parameters")
require.Contains(t, e.Error(), "include-cluster-scoped-resources, exclude-cluster-scoped-resources, include-namespace-scoped-resources and exclude-namespace-scoped-resources are new filter parameters.\nThey cannot be used together")

//cmd
e = o.Run(cmd, f)
assert.NoError(t, e)
require.NoError(t, e)

//Execute
cmd.SetArgs([]string{"bk-name-exe"})
e = cmd.Execute()
assert.NoError(t, e)
require.NoError(t, e)

// verify all options are set as expected
assert.Equal(t, name, o.Name)
assert.Equal(t, includeNamespaces, o.IncludeNamespaces.String())
assert.Equal(t, excludeNamespaces, o.ExcludeNamespaces.String())
assert.Equal(t, includeResources, o.IncludeResources.String())
assert.Equal(t, excludeResources, o.ExcludeResources.String())
assert.Equal(t, includeClusterScopedResources, o.IncludeClusterScopedResources.String())
assert.Equal(t, excludeClusterScopedResources, o.ExcludeClusterScopedResources.String())
assert.Equal(t, includeNamespaceScopedResources, o.IncludeNamespaceScopedResources.String())
assert.Equal(t, excludeNamespaceScopedResources, o.ExcludeNamespaceScopedResources.String())
assert.Equal(t, true, test.CompareSlice(strings.Split(labels, ","), strings.Split(o.Labels.String(), ",")))
assert.Equal(t, storageLocation, o.StorageLocation)
assert.Equal(t, snapshotLocations, strings.Split(o.SnapshotLocations[0], ",")[0])
assert.Equal(t, selector, o.Selector.String())
assert.Equal(t, orderedResources, o.OrderedResources)
assert.Equal(t, csiSnapshotTimeout, o.CSISnapshotTimeout.String())
assert.Equal(t, itemOperationTimeout, o.ItemOperationTimeout.String())
assert.Equal(t, snapshotVolumes, o.SnapshotVolumes.String())
assert.Equal(t, snapshotMoveData, o.SnapshotMoveData.String())
assert.Equal(t, includeClusterResources, o.IncludeClusterResources.String())
assert.Equal(t, defaultVolumesToFsBackup, o.DefaultVolumesToFsBackup.String())
assert.Equal(t, resPoliciesConfigmap, o.ResPoliciesConfigmap)
assert.Equal(t, dataMover, o.DataMover)
require.Equal(t, name, o.Name)
require.Equal(t, includeNamespaces, o.IncludeNamespaces.String())
require.Equal(t, excludeNamespaces, o.ExcludeNamespaces.String())
require.Equal(t, includeResources, o.IncludeResources.String())
require.Equal(t, excludeResources, o.ExcludeResources.String())
require.Equal(t, includeClusterScopedResources, o.IncludeClusterScopedResources.String())
require.Equal(t, excludeClusterScopedResources, o.ExcludeClusterScopedResources.String())
require.Equal(t, includeNamespaceScopedResources, o.IncludeNamespaceScopedResources.String())
require.Equal(t, excludeNamespaceScopedResources, o.ExcludeNamespaceScopedResources.String())
require.Equal(t, true, test.CompareSlice(strings.Split(labels, ","), strings.Split(o.Labels.String(), ",")))
require.Equal(t, storageLocation, o.StorageLocation)
require.Equal(t, snapshotLocations, strings.Split(o.SnapshotLocations[0], ",")[0])
require.Equal(t, selector, o.Selector.String())
require.Equal(t, orderedResources, o.OrderedResources)
require.Equal(t, csiSnapshotTimeout, o.CSISnapshotTimeout.String())
require.Equal(t, itemOperationTimeout, o.ItemOperationTimeout.String())
require.Equal(t, snapshotVolumes, o.SnapshotVolumes.String())
require.Equal(t, snapshotMoveData, o.SnapshotMoveData.String())
require.Equal(t, includeClusterResources, o.IncludeClusterResources.String())
require.Equal(t, defaultVolumesToFsBackup, o.DefaultVolumesToFsBackup.String())
require.Equal(t, resPoliciesConfigmap, o.ResPoliciesConfigmap)
require.Equal(t, dataMover, o.DataMover)
//assert.Equal(t, true, o.Wait)

// verify oldAndNewFilterParametersUsedTogether
mix := o.oldAndNewFilterParametersUsedTogether()
assert.Equal(t, true, mix)
require.Equal(t, true, mix)
})

t.Run("create a backup create command with specific storage-location setting", func(t *testing.T) {
bsl := "bsl-1"
// create a factory
f := &factorymocks.Factory{}
cmd := NewCreateCommand(f, "")
backups := &velerov1mocks.BackupInterface{}
veleroV1 := &velerov1mocks.VeleroV1Interface{}
client := &versionedmocks.Interface{}
kbclient := clientfake.NewClientBuilder().WithScheme(scheme.Scheme).Build()

bk := &velerov1api.Backup{}
backups.On("Create", mock.Anything, mock.Anything, mock.Anything).Return(bk, nil)
veleroV1.On("Backups", mock.Anything).Return(backups, nil)
client.On("VeleroV1").Return(veleroV1, nil)
f.On("Client").Return(client, nil)
scheme := runtime.NewScheme()
err := velerov1api.AddToScheme(scheme)
require.NoError(t, err)
client := dynamicfake.NewSimpleDynamicClient(scheme)

f.On("DynamicClient").Return(client, nil)
f.On("Namespace").Return(mock.Anything)
f.On("KubebuilderClient").Return(kbclient, nil)

Expand All @@ -301,17 +302,18 @@ func TestCreateCommand(t *testing.T) {
// create a factory
f := &factorymocks.Factory{}
cmd := NewCreateCommand(f, "")
vsls := &velerov1mocks.VolumeSnapshotLocationInterface{}
veleroV1 := &velerov1mocks.VeleroV1Interface{}
client := &versionedmocks.Interface{}
kbclient := clientfake.NewClientBuilder().WithScheme(scheme.Scheme).Build()

vsl := &velerov1api.VolumeSnapshotLocation{}
vsls.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(vsl, nil)
veleroV1.On("VolumeSnapshotLocations", mock.Anything).Return(vsls, nil)
client.On("VeleroV1").Return(veleroV1, nil)
f.On("Client").Return(client, nil)
f.On("Namespace").Return(mock.Anything)
scheme := runtime.NewScheme()
err := velerov1api.AddToScheme(scheme)
require.NoError(t, err)
client := dynamicfake.NewSimpleDynamicClient(scheme)
vsl := builder.ForVolumeSnapshotLocation(cmdtest.VeleroNameSpace, vslName).Result()
vslObjMap, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(vsl)
client.Resource(velerov1api.VolumeSnapshotLocationGVR).Namespace(cmdtest.VeleroNameSpace).Create(context.Background(), &unstructured.Unstructured{Object: vslObjMap}, metav1.CreateOptions{})

f.On("DynamicClient").Return(client, nil)
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
f.On("KubebuilderClient").Return(kbclient, nil)

flags := new(flag.FlagSet)
Expand Down Expand Up @@ -343,21 +345,18 @@ func TestCreateCommand(t *testing.T) {
fromSchedule := "schedule-name-1"
flags.Parse([]string{"--from-schedule", fromSchedule})

backups := &velerov1mocks.BackupInterface{}
bk := &velerov1api.Backup{}
schedules := &velerov1mocks.ScheduleInterface{}
veleroV1 := &velerov1mocks.VeleroV1Interface{}
client := &versionedmocks.Interface{}
kbclient := clientfake.NewClientBuilder().WithScheme(scheme.Scheme).Build()
sd := &velerov1api.Schedule{}

backups.On("Create", mock.Anything, mock.Anything, mock.Anything).Return(bk, nil)
veleroV1.On("Backups", mock.Anything).Return(backups, nil)
schedules.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(sd, nil)
veleroV1.On("Schedules", mock.Anything).Return(schedules, nil)
client.On("VeleroV1").Return(veleroV1, nil)
f.On("Client").Return(client, nil)
f.On("Namespace").Return(mock.Anything)

scheme := runtime.NewScheme()
err := velerov1api.AddToScheme(scheme)
require.NoError(t, err)
client := dynamicfake.NewSimpleDynamicClient(scheme)
schedule := builder.ForSchedule(cmdtest.VeleroNameSpace, fromSchedule).Result()
scheduleObjMap, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(schedule)
client.Resource(velerov1api.ScheduleGVR).Namespace(cmdtest.VeleroNameSpace).Create(context.Background(), &unstructured.Unstructured{Object: scheduleObjMap}, metav1.CreateOptions{})

f.On("DynamicClient").Return(client, nil)
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
f.On("KubebuilderClient").Return(kbclient, nil)

e := o.Complete(args, f)
Expand Down

0 comments on commit 48711f8

Please sign in to comment.