mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-09-20 06:54:32 +00:00
Merge branch 'main' into resourcemodifier
Signed-off-by: Anshul Ahuja <anshul.ahu@gmail.com>
This commit is contained in:
@@ -22,13 +22,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
kubeerrs "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
@@ -36,9 +34,8 @@ 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"
|
||||
"github.com/vmware-tanzu/velero/pkg/util/kube"
|
||||
)
|
||||
|
||||
func NewCreateCommand(f client.Factory, use string) *cobra.Command {
|
||||
@@ -107,7 +104,7 @@ type CreateOptions struct {
|
||||
CSISnapshotTimeout time.Duration
|
||||
ItemOperationTimeout time.Duration
|
||||
ResPoliciesConfigmap string
|
||||
client veleroclient.Interface
|
||||
client kbclient.WithWatch
|
||||
}
|
||||
|
||||
func NewCreateOptions() *CreateOptions {
|
||||
@@ -171,7 +168,7 @@ func (o *CreateOptions) Validate(c *cobra.Command, args []string, f client.Facto
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := f.KubebuilderClient()
|
||||
client, err := f.KubebuilderWatchClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -203,7 +200,8 @@ 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 {
|
||||
snapshotLocation := new(velerov1api.VolumeSnapshotLocation)
|
||||
if err := o.client.Get(context.TODO(), kbclient.ObjectKey{Namespace: f.Namespace(), Name: loc}, snapshotLocation); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -216,7 +214,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.KubebuilderWatchClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -238,7 +236,6 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error {
|
||||
fmt.Println("Creating backup from schedule, all other filters are ignored.")
|
||||
}
|
||||
|
||||
var backupInformer cache.SharedIndexInformer
|
||||
var updates chan *velerov1api.Backup
|
||||
if o.Wait {
|
||||
stop := make(chan struct{})
|
||||
@@ -246,12 +243,17 @@ 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)
|
||||
|
||||
lw := kube.InternalLW{
|
||||
Client: o.client,
|
||||
Namespace: f.Namespace(),
|
||||
ObjectList: new(velerov1api.BackupList),
|
||||
}
|
||||
backupInformer := cache.NewSharedInformer(&lw, &velerov1api.Backup{}, time.Second)
|
||||
backupInformer.AddEventHandler(
|
||||
cache.FilteringResourceEventHandler{
|
||||
FilterFunc: func(obj interface{}) bool {
|
||||
backup, ok := obj.(*velerov1api.Backup)
|
||||
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
@@ -275,10 +277,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{})
|
||||
err = o.client.Create(context.TODO(), backup, &kbclient.CreateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -341,7 +344,8 @@ 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{})
|
||||
schedule := new(velerov1api.Schedule)
|
||||
err := o.client.Get(context.TODO(), kbclient.ObjectKey{Namespace: namespace, Name: o.FromSchedule}, schedule)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -23,24 +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/runtime"
|
||||
controllerclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
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"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
)
|
||||
|
||||
func TestCreateOptions_BuildBackup(t *testing.T) {
|
||||
@@ -77,27 +74,31 @@ 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 = velerotest.NewFakeControllerRuntimeClient(t).(controllerclient.WithWatch)
|
||||
|
||||
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{})
|
||||
o.client.Create(context.TODO(), schedule, &kbclient.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())
|
||||
})
|
||||
@@ -145,6 +146,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{}
|
||||
|
||||
@@ -160,7 +162,7 @@ func TestCreateCommand(t *testing.T) {
|
||||
excludeClusterScopedResources := "MutatingWebhookConfiguration,APIService"
|
||||
includeNamespaceScopedResources := "Endpoints,Event,PodTemplate"
|
||||
excludeNamespaceScopedResources := "Secret,MultiClusterIngress"
|
||||
labels := "c=foo,b=woo"
|
||||
labels := "c=foo"
|
||||
storageLocation := "bsl-name-1"
|
||||
snapshotLocations := "region=minio"
|
||||
selector := "a=pod"
|
||||
@@ -203,81 +205,68 @@ 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)
|
||||
client := velerotest.NewFakeControllerRuntimeClient(t).(kbclient.WithWatch)
|
||||
|
||||
f.On("Namespace").Return(mock.Anything)
|
||||
f.On("KubebuilderClient").Return(nil, nil)
|
||||
f.On("KubebuilderWatchClient").Return(client, 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()
|
||||
kbclient := velerotest.NewFakeControllerRuntimeClient(t).(kbclient.WithWatch)
|
||||
|
||||
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)
|
||||
f.On("Namespace").Return(mock.Anything)
|
||||
f.On("KubebuilderClient").Return(kbclient, nil)
|
||||
f.On("KubebuilderWatchClient").Return(kbclient, nil)
|
||||
|
||||
flags := new(flag.FlagSet)
|
||||
o := NewCreateOptions()
|
||||
@@ -301,18 +290,14 @@ 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()
|
||||
kbclient := velerotest.NewFakeControllerRuntimeClient(t).(kbclient.WithWatch)
|
||||
|
||||
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)
|
||||
f.On("KubebuilderClient").Return(kbclient, nil)
|
||||
vsl := builder.ForVolumeSnapshotLocation(cmdtest.VeleroNameSpace, vslName).Result()
|
||||
|
||||
kbclient.Create(cmd.Context(), vsl, &controllerclient.CreateOptions{})
|
||||
|
||||
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
|
||||
f.On("KubebuilderWatchClient").Return(kbclient, nil)
|
||||
|
||||
flags := new(flag.FlagSet)
|
||||
o := NewCreateOptions()
|
||||
@@ -343,22 +328,13 @@ 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{}
|
||||
kbclient := velerotest.NewFakeControllerRuntimeClient(t).(kbclient.WithWatch)
|
||||
|
||||
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)
|
||||
f.On("KubebuilderClient").Return(kbclient, nil)
|
||||
schedule := builder.ForSchedule(cmdtest.VeleroNameSpace, fromSchedule).Result()
|
||||
kbclient.Create(context.Background(), schedule, &controllerclient.CreateOptions{})
|
||||
|
||||
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
|
||||
f.On("KubebuilderWatchClient").Return(kbclient, nil)
|
||||
|
||||
e := o.Complete(args, f)
|
||||
assert.NoError(t, e)
|
||||
|
||||
@@ -25,12 +25,14 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
kubeerrs "k8s.io/apimachinery/pkg/util/errors"
|
||||
controllerclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/backup"
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
|
||||
"github.com/vmware-tanzu/velero/pkg/label"
|
||||
)
|
||||
|
||||
// NewDeleteCommand creates a new command that deletes a backup.
|
||||
@@ -82,7 +84,8 @@ func Run(o *cli.DeleteOptions) error {
|
||||
switch {
|
||||
case len(o.Names) > 0:
|
||||
for _, name := range o.Names {
|
||||
backup, err := o.Client.VeleroV1().Backups(o.Namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
||||
backup := new(velerov1api.Backup)
|
||||
err := o.Client.Get(context.TODO(), controllerclient.ObjectKey{Namespace: o.Namespace, Name: name}, backup)
|
||||
if err != nil {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
continue
|
||||
@@ -91,17 +94,22 @@ func Run(o *cli.DeleteOptions) error {
|
||||
backups = append(backups, backup)
|
||||
}
|
||||
default:
|
||||
selector := labels.Everything().String()
|
||||
selector := labels.Everything()
|
||||
if o.Selector.LabelSelector != nil {
|
||||
selector = o.Selector.String()
|
||||
convertedSelector, err := metav1.LabelSelectorAsSelector(o.Selector.LabelSelector)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
selector = convertedSelector
|
||||
}
|
||||
|
||||
res, err := o.Client.VeleroV1().Backups(o.Namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: selector})
|
||||
backupList := new(velerov1api.BackupList)
|
||||
err := o.Client.List(context.TODO(), backupList, &controllerclient.ListOptions{LabelSelector: selector, Namespace: o.Namespace})
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
for i := range res.Items {
|
||||
backups = append(backups, &res.Items[i])
|
||||
for i := range backupList.Items {
|
||||
backups = append(backups, &backupList.Items[i])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,9 +120,11 @@ func Run(o *cli.DeleteOptions) error {
|
||||
|
||||
// create a backup deletion request for each
|
||||
for _, b := range backups {
|
||||
deleteRequest := backup.NewDeleteBackupRequest(b.Name, string(b.UID))
|
||||
deleteRequest := builder.ForDeleteBackupRequest(o.Namespace, "").BackupName(b.Name).
|
||||
ObjectMeta(builder.WithLabels(velerov1api.BackupNameLabel, label.GetValidName(b.Name),
|
||||
velerov1api.BackupUIDLabel, string(b.UID)), builder.WithGenerateName(b.Name+"-")).Result()
|
||||
|
||||
if _, err := o.Client.VeleroV1().DeleteBackupRequests(o.Namespace).Create(context.TODO(), deleteRequest, metav1.CreateOptions{}); err != nil {
|
||||
if err := o.Client.Create(context.TODO(), deleteRequest, &controllerclient.CreateOptions{}); err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -17,68 +17,60 @@ limitations under the License.
|
||||
package backup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
controllerclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
|
||||
cmdtest "github.com/vmware-tanzu/velero/pkg/cmd/test"
|
||||
versionedmocks "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/mocks"
|
||||
velerov1mocks "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1/mocks"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
)
|
||||
|
||||
func TestDeleteCommand(t *testing.T) {
|
||||
backupName := "backup-name-1"
|
||||
backup1 := "backup-name-1"
|
||||
backup2 := "backup-name-2"
|
||||
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
|
||||
deleteBackupRequest := &velerov1mocks.DeleteBackupRequestInterface{}
|
||||
backups := &velerov1mocks.BackupInterface{}
|
||||
veleroV1 := &velerov1mocks.VeleroV1Interface{}
|
||||
client := &versionedmocks.Interface{}
|
||||
bk := &velerov1api.Backup{}
|
||||
dbr := &velerov1api.DeleteBackupRequest{}
|
||||
backups.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(bk, nil)
|
||||
deleteBackupRequest.On("Create", mock.Anything, mock.Anything, mock.Anything).Return(dbr, nil)
|
||||
veleroV1.On("DeleteBackupRequests", mock.Anything).Return(deleteBackupRequest, nil)
|
||||
veleroV1.On("Backups", mock.Anything).Return(backups, nil)
|
||||
client.On("VeleroV1").Return(veleroV1, nil)
|
||||
f.On("Client").Return(client, nil)
|
||||
f.On("Namespace").Return(mock.Anything)
|
||||
client := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
client.Create(context.Background(), builder.ForBackup(cmdtest.VeleroNameSpace, backup1).Result(), &controllerclient.CreateOptions{})
|
||||
client.Create(context.Background(), builder.ForBackup("default", backup2).Result(), &controllerclient.CreateOptions{})
|
||||
|
||||
f.On("KubebuilderClient").Return(client, nil)
|
||||
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
|
||||
|
||||
// create command
|
||||
c := NewDeleteCommand(f, "velero backup delete")
|
||||
c.SetArgs([]string{backupName})
|
||||
assert.Equal(t, "Delete backups", c.Short)
|
||||
c.SetArgs([]string{backup1, backup2})
|
||||
require.Equal(t, "Delete backups", c.Short)
|
||||
|
||||
o := cli.NewDeleteOptions("backup")
|
||||
flags := new(flag.FlagSet)
|
||||
o.BindFlags(flags)
|
||||
flags.Parse([]string{"--confirm"})
|
||||
|
||||
args := []string{"bk1", "bk2"}
|
||||
args := []string{backup1, backup2}
|
||||
|
||||
bk.Name = backupName
|
||||
e := o.Complete(f, args)
|
||||
assert.Equal(t, e, nil)
|
||||
require.Equal(t, nil, e)
|
||||
|
||||
e = o.Validate(c, f, args)
|
||||
assert.Equal(t, e, nil)
|
||||
require.Equal(t, nil, e)
|
||||
|
||||
e = Run(o)
|
||||
assert.Equal(t, e, nil)
|
||||
Run(o)
|
||||
|
||||
e = c.Execute()
|
||||
assert.Equal(t, e, nil)
|
||||
require.Equal(t, nil, e)
|
||||
|
||||
if os.Getenv(cmdtest.CaptureFlag) == "1" {
|
||||
return
|
||||
@@ -87,10 +79,7 @@ func TestDeleteCommand(t *testing.T) {
|
||||
cmd := exec.Command(os.Args[0], []string{"-test.run=TestDeleteCommand"}...)
|
||||
cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag))
|
||||
stdout, _, err := veleroexec.RunCommand(cmd)
|
||||
|
||||
if err == nil {
|
||||
assert.Contains(t, stdout, fmt.Sprintf("Request to delete backup \"%s\" submitted successfully.", backupName))
|
||||
return
|
||||
if err != nil {
|
||||
require.Contains(t, stdout, fmt.Sprintf("backups.velero.io \"%s\" not found.", backup2))
|
||||
}
|
||||
t.Fatalf("process ran with err %v, want backups by get()", err)
|
||||
}
|
||||
|
||||
@@ -21,14 +21,14 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
snapshotv1client "github.com/kubernetes-csi/external-snapshotter/client/v4/clientset/versioned"
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
controllerclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
pkgbackup "github.com/vmware-tanzu/velero/pkg/backup"
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
|
||||
@@ -54,9 +54,6 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
|
||||
Use: use + " [NAME1] [NAME2] [NAME...]",
|
||||
Short: "Describe backups",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
veleroClient, err := f.Client()
|
||||
cmd.CheckError(err)
|
||||
|
||||
kbClient, err := f.KubebuilderClient()
|
||||
cmd.CheckError(err)
|
||||
|
||||
@@ -64,29 +61,37 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
|
||||
cmd.CheckError(fmt.Errorf("invalid output format '%s'. valid value are 'plaintext, json'", outputFormat))
|
||||
}
|
||||
|
||||
var backups *velerov1api.BackupList
|
||||
backups := new(velerov1api.BackupList)
|
||||
if len(args) > 0 {
|
||||
backups = new(velerov1api.BackupList)
|
||||
for _, name := range args {
|
||||
backup, err := veleroClient.VeleroV1().Backups(f.Namespace()).Get(context.TODO(), name, metav1.GetOptions{})
|
||||
backup := new(velerov1api.Backup)
|
||||
err := kbClient.Get(context.TODO(), controllerclient.ObjectKey{Namespace: f.Namespace(), Name: name}, backup)
|
||||
cmd.CheckError(err)
|
||||
backups.Items = append(backups.Items, *backup)
|
||||
}
|
||||
} else {
|
||||
backups, err = veleroClient.VeleroV1().Backups(f.Namespace()).List(context.TODO(), listOptions)
|
||||
parsedSelector, err := labels.Parse(listOptions.LabelSelector)
|
||||
cmd.CheckError(err)
|
||||
err = kbClient.List(context.TODO(), backups, &controllerclient.ListOptions{LabelSelector: parsedSelector, Namespace: f.Namespace()})
|
||||
cmd.CheckError(err)
|
||||
}
|
||||
|
||||
first := true
|
||||
for i, backup := range backups.Items {
|
||||
deleteRequestListOptions := pkgbackup.NewDeleteBackupRequestListOptions(backup.Name, string(backup.UID))
|
||||
deleteRequestList, err := veleroClient.VeleroV1().DeleteBackupRequests(f.Namespace()).List(context.TODO(), deleteRequestListOptions)
|
||||
deleteRequestList := new(velerov1api.DeleteBackupRequestList)
|
||||
err := kbClient.List(context.TODO(), deleteRequestList, &controllerclient.ListOptions{
|
||||
Namespace: f.Namespace(),
|
||||
LabelSelector: labels.SelectorFromSet(map[string]string{velerov1api.BackupNameLabel: label.GetValidName(backup.Name), velerov1api.BackupUIDLabel: string(backup.UID)}),
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error getting DeleteBackupRequests for backup %s: %v\n", backup.Name, err)
|
||||
}
|
||||
|
||||
opts := label.NewListOptionsForBackup(backup.Name)
|
||||
podVolumeBackupList, err := veleroClient.VeleroV1().PodVolumeBackups(f.Namespace()).List(context.TODO(), opts)
|
||||
podVolumeBackupList := new(velerov1api.PodVolumeBackupList)
|
||||
err = kbClient.List(context.TODO(), podVolumeBackupList, &controllerclient.ListOptions{
|
||||
Namespace: f.Namespace(),
|
||||
LabelSelector: labels.SelectorFromSet(map[string]string{velerov1api.BackupNameLabel: label.GetValidName(backup.Name)}),
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error getting PodVolumeBackups for backup %s: %v\n", backup.Name, err)
|
||||
}
|
||||
@@ -101,6 +106,7 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
|
||||
csiClient, err = snapshotv1client.NewForConfig(clientConfig)
|
||||
cmd.CheckError(err)
|
||||
|
||||
opts := label.NewListOptionsForBackup(backup.Name)
|
||||
vscList, err = csiClient.SnapshotV1().VolumeSnapshotContents().List(context.TODO(), opts)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error getting VolumeSnapshotContent objects for backup %s: %v\n", backup.Name, err)
|
||||
@@ -110,10 +116,10 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
|
||||
// structured output only applies to a single backup in case of OOM
|
||||
// To describe the list of backups in structured format, users could iterate over the list and describe backup one after another.
|
||||
if len(backups.Items) == 1 && outputFormat != "plaintext" {
|
||||
s := output.DescribeBackupInSF(context.Background(), kbClient, &backups.Items[i], deleteRequestList.Items, podVolumeBackupList.Items, vscList.Items, details, veleroClient, insecureSkipTLSVerify, caCertFile, outputFormat)
|
||||
s := output.DescribeBackupInSF(context.Background(), kbClient, &backups.Items[i], deleteRequestList.Items, podVolumeBackupList.Items, vscList.Items, details, insecureSkipTLSVerify, caCertFile, outputFormat)
|
||||
fmt.Print(s)
|
||||
} else {
|
||||
s := output.DescribeBackup(context.Background(), kbClient, &backups.Items[i], deleteRequestList.Items, podVolumeBackupList.Items, vscList.Items, details, veleroClient, insecureSkipTLSVerify, caCertFile)
|
||||
s := output.DescribeBackup(context.Background(), kbClient, &backups.Items[i], deleteRequestList.Items, podVolumeBackupList.Items, vscList.Items, details, insecureSkipTLSVerify, caCertFile)
|
||||
if first {
|
||||
first = false
|
||||
fmt.Print(s)
|
||||
|
||||
@@ -17,55 +17,37 @@ limitations under the License.
|
||||
package backup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"k8s.io/client-go/rest"
|
||||
controllerclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
cmdtest "github.com/vmware-tanzu/velero/pkg/cmd/test"
|
||||
"github.com/vmware-tanzu/velero/pkg/features"
|
||||
versionedmocks "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/mocks"
|
||||
velerov1mocks "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1/mocks"
|
||||
"github.com/vmware-tanzu/velero/pkg/test"
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
)
|
||||
|
||||
func TestNewDescribeCommand(t *testing.T) {
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
|
||||
backups := &velerov1mocks.BackupInterface{}
|
||||
veleroV1 := &velerov1mocks.VeleroV1Interface{}
|
||||
client := &versionedmocks.Interface{}
|
||||
clientConfig := rest.Config{}
|
||||
|
||||
deleteBackupRequest := &velerov1mocks.DeleteBackupRequestInterface{}
|
||||
bk := &velerov1api.Backup{}
|
||||
bkList := &velerov1api.BackupList{}
|
||||
deleteBackupRequestList := &velerov1api.DeleteBackupRequestList{}
|
||||
podVolumeBackups := &velerov1mocks.PodVolumeBackupInterface{}
|
||||
podVolumeBackupList := &velerov1api.PodVolumeBackupList{}
|
||||
|
||||
backupName := "bk-describe-1"
|
||||
bk.Name = backupName
|
||||
testBackup := builder.ForBackup(cmdtest.VeleroNameSpace, backupName).Result()
|
||||
|
||||
clientConfig := rest.Config{}
|
||||
kbClient := test.NewFakeControllerRuntimeClient(t)
|
||||
kbClient.Create(context.Background(), testBackup, &controllerclient.CreateOptions{})
|
||||
|
||||
backups.On("List", mock.Anything, mock.Anything).Return(bkList, nil)
|
||||
backups.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(bk, nil)
|
||||
veleroV1.On("Backups", mock.Anything).Return(backups, nil)
|
||||
deleteBackupRequest.On("List", mock.Anything, mock.Anything).Return(deleteBackupRequestList, nil)
|
||||
veleroV1.On("DeleteBackupRequests", mock.Anything).Return(deleteBackupRequest, nil)
|
||||
podVolumeBackups.On("List", mock.Anything, mock.Anything).Return(podVolumeBackupList, nil)
|
||||
veleroV1.On("PodVolumeBackups", mock.Anything, mock.Anything).Return(podVolumeBackups, nil)
|
||||
client.On("VeleroV1").Return(veleroV1, nil)
|
||||
f.On("ClientConfig").Return(&clientConfig, nil)
|
||||
f.On("Client").Return(client, nil)
|
||||
f.On("Namespace").Return(mock.Anything)
|
||||
f.On("KubebuilderClient").Return(nil, nil)
|
||||
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
|
||||
f.On("KubebuilderClient").Return(kbClient, nil)
|
||||
|
||||
// create command
|
||||
c := NewDescribeCommand(f, "velero backup describe")
|
||||
@@ -74,7 +56,7 @@ func TestNewDescribeCommand(t *testing.T) {
|
||||
features.NewFeatureFlagSet("EnableCSI")
|
||||
defer features.NewFeatureFlagSet()
|
||||
|
||||
c.SetArgs([]string{"bk1"})
|
||||
c.SetArgs([]string{backupName})
|
||||
e := c.Execute()
|
||||
assert.NoError(t, e)
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
controllerclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
@@ -84,10 +84,11 @@ func (o *DownloadOptions) BindFlags(flags *pflag.FlagSet) {
|
||||
}
|
||||
|
||||
func (o *DownloadOptions) Validate(c *cobra.Command, args []string, f client.Factory) error {
|
||||
veleroClient, err := f.Client()
|
||||
kbClient, err := f.KubebuilderClient()
|
||||
cmd.CheckError(err)
|
||||
|
||||
if _, err := veleroClient.VeleroV1().Backups(f.Namespace()).Get(context.TODO(), o.Name, metav1.GetOptions{}); err != nil {
|
||||
backup := new(velerov1api.Backup)
|
||||
if err := kbClient.Get(context.TODO(), controllerclient.ObjectKey{Namespace: f.Namespace(), Name: o.Name}, backup); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package backup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -25,35 +26,27 @@ import (
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
cmdtest "github.com/vmware-tanzu/velero/pkg/cmd/test"
|
||||
"github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/scheme"
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
versionedmocks "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/mocks"
|
||||
velerov1mocks "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1/mocks"
|
||||
cmdtest "github.com/vmware-tanzu/velero/pkg/cmd/test"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
)
|
||||
|
||||
func TestNewDownloadCommand(t *testing.T) {
|
||||
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
|
||||
backups := &velerov1mocks.BackupInterface{}
|
||||
veleroV1 := &velerov1mocks.VeleroV1Interface{}
|
||||
client := &versionedmocks.Interface{}
|
||||
bk := &velerov1api.Backup{}
|
||||
kbclient := fake.NewClientBuilder().WithScheme(scheme.Scheme).Build()
|
||||
backupName := "backup-1"
|
||||
kbclient := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
err := kbclient.Create(context.Background(), builder.ForBackup(cmdtest.VeleroNameSpace, backupName).Result())
|
||||
require.NoError(t, err)
|
||||
err = kbclient.Create(context.Background(), builder.ForBackup(cmdtest.VeleroNameSpace, "bk-to-be-download").Result())
|
||||
require.NoError(t, err)
|
||||
|
||||
backups.On("Get", 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)
|
||||
f.On("Namespace").Return(mock.Anything)
|
||||
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
|
||||
f.On("KubebuilderClient").Return(kbclient, nil)
|
||||
|
||||
// create command
|
||||
@@ -78,7 +71,6 @@ func TestNewDownloadCommand(t *testing.T) {
|
||||
flags.Parse([]string{fmt.Sprintf("--insecure-skip-tls-verify=%s", strconv.FormatBool(insecureSkipTlsVerify))})
|
||||
flags.Parse([]string{"--cacert", cacert})
|
||||
|
||||
backupName := "backup-1"
|
||||
args := []string{backupName, "arg2"}
|
||||
|
||||
e := o.Complete(args)
|
||||
@@ -105,7 +97,7 @@ func TestNewDownloadCommand(t *testing.T) {
|
||||
_, stderr, err := veleroexec.RunCommand(cmd)
|
||||
|
||||
if err != nil {
|
||||
assert.Contains(t, stderr, "download request download url timeout")
|
||||
require.Contains(t, stderr, "download request download url timeout")
|
||||
return
|
||||
}
|
||||
t.Fatalf("process ran with err %v, want backup delete successfully", err)
|
||||
|
||||
@@ -21,6 +21,8 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
@@ -38,19 +40,24 @@ func NewGetCommand(f client.Factory, use string) *cobra.Command {
|
||||
err := output.ValidateFlags(c)
|
||||
cmd.CheckError(err)
|
||||
|
||||
veleroClient, err := f.Client()
|
||||
kbClient, err := f.KubebuilderClient()
|
||||
cmd.CheckError(err)
|
||||
|
||||
var backups *api.BackupList
|
||||
backups := new(api.BackupList)
|
||||
if len(args) > 0 {
|
||||
backups = new(api.BackupList)
|
||||
for _, name := range args {
|
||||
backup, err := veleroClient.VeleroV1().Backups(f.Namespace()).Get(context.TODO(), name, metav1.GetOptions{})
|
||||
backup := new(api.Backup)
|
||||
err := kbClient.Get(context.TODO(), kbclient.ObjectKey{Namespace: f.Namespace(), Name: name}, backup)
|
||||
cmd.CheckError(err)
|
||||
backups.Items = append(backups.Items, *backup)
|
||||
}
|
||||
} else {
|
||||
backups, err = veleroClient.VeleroV1().Backups(f.Namespace()).List(context.TODO(), listOptions)
|
||||
parsedSelector, err := labels.Parse(listOptions.LabelSelector)
|
||||
cmd.CheckError(err)
|
||||
err = kbClient.List(context.TODO(), backups, &kbclient.ListOptions{
|
||||
LabelSelector: parsedSelector,
|
||||
Namespace: f.Namespace(),
|
||||
})
|
||||
cmd.CheckError(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package backup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -24,15 +25,14 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
cmdtest "github.com/vmware-tanzu/velero/pkg/cmd/test"
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
versionedmocks "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/mocks"
|
||||
velerov1mocks "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1/mocks"
|
||||
cmdtest "github.com/vmware-tanzu/velero/pkg/cmd/test"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
)
|
||||
|
||||
func TestNewGetCommand(t *testing.T) {
|
||||
@@ -41,18 +41,16 @@ func TestNewGetCommand(t *testing.T) {
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
|
||||
backups := &velerov1mocks.BackupInterface{}
|
||||
veleroV1 := &velerov1mocks.VeleroV1Interface{}
|
||||
client := &versionedmocks.Interface{}
|
||||
bk := &velerov1api.Backup{}
|
||||
bkList := &velerov1api.BackupList{}
|
||||
client := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
|
||||
backups.On("List", mock.Anything, mock.Anything).Return(bkList, nil)
|
||||
backups.On("Get", 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)
|
||||
f.On("Namespace").Return(mock.Anything)
|
||||
for _, backupName := range args {
|
||||
backup := builder.ForBackup(cmdtest.VeleroNameSpace, backupName).ObjectMeta(builder.WithLabels("abc", "abc")).Result()
|
||||
err := client.Create(context.Background(), backup, &kbclient.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
f.On("KubebuilderClient").Return(client, nil)
|
||||
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
|
||||
|
||||
// create command
|
||||
c := NewGetCommand(f, "velero backup get")
|
||||
@@ -69,6 +67,28 @@ func TestNewGetCommand(t *testing.T) {
|
||||
cmd := exec.Command(os.Args[0], []string{"-test.run=TestNewGetCommand"}...)
|
||||
cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag))
|
||||
stdout, _, err := veleroexec.RunCommand(cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
if err == nil {
|
||||
output := strings.Split(stdout, "\n")
|
||||
i := 0
|
||||
for _, line := range output {
|
||||
if strings.Contains(line, "New") {
|
||||
i++
|
||||
}
|
||||
}
|
||||
assert.Equal(t, len(args), i)
|
||||
}
|
||||
|
||||
d := NewGetCommand(f, "velero backup get")
|
||||
c.SetArgs([]string{"-l", "abc=abc"})
|
||||
e = d.Execute()
|
||||
assert.NoError(t, e)
|
||||
|
||||
cmd = exec.Command(os.Args[0], []string{"-test.run=TestNewGetCommand"}...)
|
||||
cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag))
|
||||
stdout, _, err = veleroexec.RunCommand(cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
if err == nil {
|
||||
output := strings.Split(stdout, "\n")
|
||||
@@ -79,7 +99,5 @@ func TestNewGetCommand(t *testing.T) {
|
||||
}
|
||||
}
|
||||
assert.Equal(t, len(args), i)
|
||||
return
|
||||
}
|
||||
t.Fatalf("process ran with err %v, want backups by get()", err)
|
||||
}
|
||||
|
||||
+64
-30
@@ -23,8 +23,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
@@ -32,51 +33,84 @@ import (
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd/util/downloadrequest"
|
||||
)
|
||||
|
||||
func NewLogsCommand(f client.Factory) *cobra.Command {
|
||||
type LogsOptions struct {
|
||||
Timeout time.Duration
|
||||
InsecureSkipTLSVerify bool
|
||||
CaCertFile string
|
||||
Client kbclient.Client
|
||||
BackupName string
|
||||
}
|
||||
|
||||
func NewLogsOptions() LogsOptions {
|
||||
config, err := client.LoadConfig()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "WARNING: Error reading config file: %v\n", err)
|
||||
}
|
||||
|
||||
timeout := time.Minute
|
||||
insecureSkipTLSVerify := false
|
||||
caCertFile := config.CACertFile()
|
||||
return LogsOptions{
|
||||
Timeout: time.Minute,
|
||||
InsecureSkipTLSVerify: false,
|
||||
CaCertFile: config.CACertFile(),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LogsOptions) BindFlags(flags *pflag.FlagSet) {
|
||||
flags.DurationVar(&l.Timeout, "timeout", l.Timeout, "How long to wait to receive logs.")
|
||||
flags.BoolVar(&l.InsecureSkipTLSVerify, "insecure-skip-tls-verify", l.InsecureSkipTLSVerify, "If true, the object store's TLS certificate will not be checked for validity. This is insecure and susceptible to man-in-the-middle attacks. Not recommended for production.")
|
||||
flags.StringVar(&l.CaCertFile, "cacert", l.CaCertFile, "Path to a certificate bundle to use when verifying TLS connections.")
|
||||
}
|
||||
|
||||
func (l *LogsOptions) Run(c *cobra.Command, f client.Factory) error {
|
||||
backup := new(velerov1api.Backup)
|
||||
err := l.Client.Get(context.TODO(), kbclient.ObjectKey{Namespace: f.Namespace(), Name: l.BackupName}, backup)
|
||||
if apierrors.IsNotFound(err) {
|
||||
return fmt.Errorf("backup %q does not exist", l.BackupName)
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("error checking for backup %q: %v", l.BackupName, err)
|
||||
}
|
||||
|
||||
switch backup.Status.Phase {
|
||||
case velerov1api.BackupPhaseCompleted, velerov1api.BackupPhasePartiallyFailed, velerov1api.BackupPhaseFailed, velerov1api.BackupPhaseWaitingForPluginOperations, velerov1api.BackupPhaseWaitingForPluginOperationsPartiallyFailed:
|
||||
// terminal and waiting for plugin operations phases, do nothing.
|
||||
default:
|
||||
return fmt.Errorf("logs for backup %q are not available until it's finished processing, please wait "+
|
||||
"until the backup has a phase of Completed or Failed and try again", l.BackupName)
|
||||
}
|
||||
|
||||
err = downloadrequest.Stream(context.Background(), l.Client, f.Namespace(), l.BackupName, velerov1api.DownloadTargetKindBackupLog, os.Stdout, l.Timeout, l.InsecureSkipTLSVerify, l.CaCertFile)
|
||||
return err
|
||||
}
|
||||
|
||||
func (l *LogsOptions) Complete(args []string, f client.Factory) error {
|
||||
if len(args) > 0 {
|
||||
l.BackupName = args[0]
|
||||
}
|
||||
|
||||
kbClient, err := f.KubebuilderClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l.Client = kbClient
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewLogsCommand(f client.Factory) *cobra.Command {
|
||||
l := NewLogsOptions()
|
||||
|
||||
c := &cobra.Command{
|
||||
Use: "logs BACKUP",
|
||||
Short: "Get backup logs",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
backupName := args[0]
|
||||
|
||||
veleroClient, err := f.Client()
|
||||
err := l.Complete(args, f)
|
||||
cmd.CheckError(err)
|
||||
|
||||
kbClient, err := f.KubebuilderClient()
|
||||
cmd.CheckError(err)
|
||||
|
||||
backup, err := veleroClient.VeleroV1().Backups(f.Namespace()).Get(context.TODO(), backupName, metav1.GetOptions{})
|
||||
if apierrors.IsNotFound(err) {
|
||||
cmd.Exit("Backup %q does not exist.", backupName)
|
||||
} else if err != nil {
|
||||
cmd.Exit("Error checking for backup %q: %v", backupName, err)
|
||||
}
|
||||
|
||||
switch backup.Status.Phase {
|
||||
case velerov1api.BackupPhaseCompleted, velerov1api.BackupPhasePartiallyFailed, velerov1api.BackupPhaseFailed, velerov1api.BackupPhaseWaitingForPluginOperations, velerov1api.BackupPhaseWaitingForPluginOperationsPartiallyFailed:
|
||||
// terminal and waiting for plugin operations phases, do nothing.
|
||||
default:
|
||||
cmd.Exit("Logs for backup %q are not available until it's finished processing. Please wait "+
|
||||
"until the backup has a phase of Completed or Failed and try again.", backupName)
|
||||
}
|
||||
|
||||
err = downloadrequest.Stream(context.Background(), kbClient, f.Namespace(), backupName, velerov1api.DownloadTargetKindBackupLog, os.Stdout, timeout, insecureSkipTLSVerify, caCertFile)
|
||||
err = l.Run(c, f)
|
||||
cmd.CheckError(err)
|
||||
},
|
||||
}
|
||||
|
||||
c.Flags().DurationVar(&timeout, "timeout", timeout, "How long to wait to receive logs.")
|
||||
c.Flags().BoolVar(&insecureSkipTLSVerify, "insecure-skip-tls-verify", insecureSkipTLSVerify, "If true, the object store's TLS certificate will not be checked for validity. This is insecure and susceptible to man-in-the-middle attacks. Not recommended for production.")
|
||||
c.Flags().StringVar(&caCertFile, "cacert", caCertFile, "Path to a certificate bundle to use when verifying TLS connections.")
|
||||
l.BindFlags(c.Flags())
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
+130
-40
@@ -17,62 +17,152 @@ limitations under the License.
|
||||
package backup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
"github.com/stretchr/testify/require"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
cmdtest "github.com/vmware-tanzu/velero/pkg/cmd/test"
|
||||
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"
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
)
|
||||
|
||||
func TestNewLogsCommand(t *testing.T) {
|
||||
backupName := "bk-logs-1"
|
||||
t.Run("Flag test", func(t *testing.T) {
|
||||
l := NewLogsOptions()
|
||||
flags := new(flag.FlagSet)
|
||||
l.BindFlags(flags)
|
||||
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
timeout := "1m0s"
|
||||
insecureSkipTLSVerify := "true"
|
||||
caCertFile := "testing"
|
||||
|
||||
backups := &velerov1mocks.BackupInterface{}
|
||||
veleroV1 := &velerov1mocks.VeleroV1Interface{}
|
||||
client := &versionedmocks.Interface{}
|
||||
bk := &velerov1api.Backup{}
|
||||
bkList := &velerov1api.BackupList{}
|
||||
kbclient := fake.NewClientBuilder().WithScheme(scheme.Scheme).Build()
|
||||
flags.Parse([]string{"--timeout", timeout})
|
||||
flags.Parse([]string{"--insecure-skip-tls-verify", insecureSkipTLSVerify})
|
||||
flags.Parse([]string{"--cacert", caCertFile})
|
||||
|
||||
backups.On("List", mock.Anything, mock.Anything).Return(bkList, nil)
|
||||
backups.On("Get", 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)
|
||||
f.On("Namespace").Return(mock.Anything)
|
||||
f.On("KubebuilderClient").Return(kbclient, nil)
|
||||
require.Equal(t, timeout, l.Timeout.String())
|
||||
require.Equal(t, insecureSkipTLSVerify, strconv.FormatBool(l.InsecureSkipTLSVerify))
|
||||
require.Equal(t, caCertFile, l.CaCertFile)
|
||||
})
|
||||
|
||||
c := NewLogsCommand(f)
|
||||
assert.Equal(t, "Get backup logs", c.Short)
|
||||
t.Run("Backup not complete test", func(t *testing.T) {
|
||||
backupName := "bk-logs-1"
|
||||
|
||||
if os.Getenv(cmdtest.CaptureFlag) == "1" {
|
||||
c.SetArgs([]string{backupName})
|
||||
e := c.Execute()
|
||||
assert.NoError(t, e)
|
||||
return
|
||||
}
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
|
||||
cmd := exec.Command(os.Args[0], []string{"-test.run=TestNewLogsCommand"}...)
|
||||
cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag))
|
||||
_, stderr, err := veleroexec.RunCommand(cmd)
|
||||
kbClient := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
backup := builder.ForBackup(cmdtest.VeleroNameSpace, backupName).Result()
|
||||
err := kbClient.Create(context.Background(), backup, &kbclient.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
if err != nil {
|
||||
assert.Contains(t, stderr, fmt.Sprintf("Logs for backup \"%s\" are not available until it's finished processing", backupName))
|
||||
return
|
||||
}
|
||||
t.Fatalf("process ran with err %v, want backup delete successfully", err)
|
||||
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
|
||||
f.On("KubebuilderClient").Return(kbClient, nil)
|
||||
|
||||
c := NewLogsCommand(f)
|
||||
assert.Equal(t, "Get backup logs", c.Short)
|
||||
|
||||
l := NewLogsOptions()
|
||||
flags := new(flag.FlagSet)
|
||||
l.BindFlags(flags)
|
||||
err = l.Complete([]string{backupName}, f)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = l.Run(c, f)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), fmt.Sprintf("logs for backup \"%s\" are not available until it's finished processing", backupName))
|
||||
})
|
||||
|
||||
t.Run("Backup not exist test", func(t *testing.T) {
|
||||
backupName := "not-exist"
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
|
||||
kbClient := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
|
||||
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
|
||||
f.On("KubebuilderClient").Return(kbClient, nil)
|
||||
|
||||
c := NewLogsCommand(f)
|
||||
assert.Equal(t, "Get backup logs", c.Short)
|
||||
|
||||
l := NewLogsOptions()
|
||||
flags := new(flag.FlagSet)
|
||||
l.BindFlags(flags)
|
||||
err := l.Complete([]string{backupName}, f)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = l.Run(c, f)
|
||||
require.Error(t, err)
|
||||
|
||||
require.Equal(t, fmt.Sprintf("backup \"%s\" does not exist", backupName), err.Error())
|
||||
|
||||
c.Execute()
|
||||
})
|
||||
|
||||
t.Run("Normal backup log test", func(t *testing.T) {
|
||||
backupName := "bk-logs-1"
|
||||
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
|
||||
kbClient := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
backup := builder.ForBackup(cmdtest.VeleroNameSpace, backupName).Phase(velerov1api.BackupPhaseCompleted).Result()
|
||||
err := kbClient.Create(context.Background(), backup, &kbclient.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
|
||||
f.On("KubebuilderClient").Return(kbClient, nil)
|
||||
|
||||
c := NewLogsCommand(f)
|
||||
assert.Equal(t, "Get backup logs", c.Short)
|
||||
|
||||
l := NewLogsOptions()
|
||||
flags := new(flag.FlagSet)
|
||||
l.BindFlags(flags)
|
||||
err = l.Complete([]string{backupName}, f)
|
||||
require.NoError(t, err)
|
||||
|
||||
timeout := time.After(3 * time.Second)
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
err = l.Run(c, f)
|
||||
require.Error(t, err)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-timeout:
|
||||
t.Skip("Test didn't finish in time, because BSL is not in Available state.")
|
||||
case <-done:
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Invalid client test", func(t *testing.T) {
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
|
||||
kbClient := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
|
||||
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
|
||||
|
||||
c := NewLogsCommand(f)
|
||||
assert.Equal(t, "Get backup logs", c.Short)
|
||||
|
||||
l := NewLogsOptions()
|
||||
flags := new(flag.FlagSet)
|
||||
l.BindFlags(flags)
|
||||
|
||||
f.On("KubebuilderClient").Return(kbClient, fmt.Errorf("test error"))
|
||||
err := l.Complete([]string{""}, f)
|
||||
require.Equal(t, "test error", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -29,16 +29,9 @@ import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
veleroflag "github.com/vmware-tanzu/velero/pkg/cmd/util/flag"
|
||||
"github.com/vmware-tanzu/velero/pkg/test"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
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"
|
||||
veleroflag "github.com/vmware-tanzu/velero/pkg/cmd/util/flag"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
)
|
||||
|
||||
func TestBuildBackupStorageLocationSetsNamespace(t *testing.T) {
|
||||
@@ -149,16 +142,7 @@ func TestCreateCommand_Run(t *testing.T) {
|
||||
|
||||
args := []string{name, "arg2"}
|
||||
|
||||
backups := &velerov1mocks.BackupInterface{}
|
||||
veleroV1 := &velerov1mocks.VeleroV1Interface{}
|
||||
client := &versionedmocks.Interface{}
|
||||
bk := &velerov1api.Backup{}
|
||||
kbclient := fake.NewClientBuilder().WithScheme(scheme.Scheme).Build()
|
||||
|
||||
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)
|
||||
kbclient := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
f.On("Namespace").Return(mock.Anything)
|
||||
f.On("KubebuilderClient").Return(kbclient, nil)
|
||||
|
||||
@@ -179,7 +163,7 @@ func TestCreateCommand_Run(t *testing.T) {
|
||||
assert.Equal(t, backupSyncPeriod, o.BackupSyncPeriod.String())
|
||||
assert.Equal(t, validationFrequency, o.ValidationFrequency.String())
|
||||
assert.Equal(t, true, reflect.DeepEqual(bslConfig, o.Config))
|
||||
assert.Equal(t, true, test.CompareSlice(strings.Split(labels, ","), strings.Split(o.Labels.String(), ",")))
|
||||
assert.Equal(t, true, velerotest.CompareSlice(strings.Split(labels, ","), strings.Split(o.Labels.String(), ",")))
|
||||
assert.Equal(t, caCertFile, o.CACertFile)
|
||||
assert.Equal(t, accessMode, o.AccessMode.String())
|
||||
|
||||
|
||||
@@ -26,14 +26,11 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
|
||||
cmdtest "github.com/vmware-tanzu/velero/pkg/cmd/test"
|
||||
versionedmocks "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/mocks"
|
||||
"github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/scheme"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
)
|
||||
|
||||
@@ -41,9 +38,7 @@ func TestNewDeleteCommand(t *testing.T) {
|
||||
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
client := &versionedmocks.Interface{}
|
||||
kbclient := fake.NewClientBuilder().WithScheme(scheme.Scheme).Build()
|
||||
f.On("Client").Return(client, nil)
|
||||
kbclient := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
f.On("Namespace").Return(mock.Anything)
|
||||
f.On("KubebuilderClient").Return(kbclient, nil)
|
||||
|
||||
@@ -86,9 +81,7 @@ func TestDeleteFunctions(t *testing.T) {
|
||||
//t.Run("create the other create command with fromSchedule option for Run() other branches", func(t *testing.T) {
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
client := &versionedmocks.Interface{}
|
||||
kbclient := fake.NewClientBuilder().WithScheme(scheme.Scheme).Build()
|
||||
f.On("Client").Return(client, nil)
|
||||
kbclient := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
f.On("Namespace").Return(mock.Anything)
|
||||
f.On("KubebuilderClient").Return(kbclient, nil)
|
||||
|
||||
|
||||
@@ -24,11 +24,10 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"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/scheme"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
)
|
||||
|
||||
@@ -36,7 +35,7 @@ func TestNewGetCommand(t *testing.T) {
|
||||
bkList := []string{"b1", "b2"}
|
||||
|
||||
f := &factorymocks.Factory{}
|
||||
kbclient := fake.NewClientBuilder().WithScheme(scheme.Scheme).Build()
|
||||
kbclient := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
f.On("Namespace").Return(mock.Anything)
|
||||
f.On("KubebuilderClient").Return(kbclient, nil)
|
||||
|
||||
|
||||
@@ -27,16 +27,10 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
cmdtest "github.com/vmware-tanzu/velero/pkg/cmd/test"
|
||||
veleroflag "github.com/vmware-tanzu/velero/pkg/cmd/util/flag"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
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"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
)
|
||||
|
||||
@@ -44,16 +38,9 @@ func TestNewSetCommand(t *testing.T) {
|
||||
backupName := "arg2"
|
||||
// create a config for factory
|
||||
f := &factorymocks.Factory{}
|
||||
backups := &velerov1mocks.BackupInterface{}
|
||||
veleroV1 := &velerov1mocks.VeleroV1Interface{}
|
||||
client := &versionedmocks.Interface{}
|
||||
bk := &velerov1api.Backup{}
|
||||
kbclient := fake.NewClientBuilder().WithScheme(scheme.Scheme).Build()
|
||||
|
||||
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)
|
||||
kbclient := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
|
||||
f.On("Namespace").Return(mock.Anything)
|
||||
f.On("KubebuilderClient").Return(kbclient, nil)
|
||||
|
||||
@@ -97,16 +84,9 @@ func TestSetCommand_Execute(t *testing.T) {
|
||||
if os.Getenv(cmdtest.CaptureFlag) == "1" {
|
||||
// create a config for factory
|
||||
f := &factorymocks.Factory{}
|
||||
backups := &velerov1mocks.BackupInterface{}
|
||||
veleroV1 := &velerov1mocks.VeleroV1Interface{}
|
||||
client := &versionedmocks.Interface{}
|
||||
bk := &velerov1api.Backup{}
|
||||
kbclient := fake.NewClientBuilder().WithScheme(scheme.Scheme).Build()
|
||||
|
||||
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)
|
||||
kbclient := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
|
||||
f.On("Namespace").Return(mock.Anything)
|
||||
f.On("KubebuilderClient").Return(kbclient, nil)
|
||||
|
||||
|
||||
@@ -25,16 +25,16 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
controllerclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
clientset "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned"
|
||||
)
|
||||
|
||||
// DeleteOptions contains parameters used for deleting a restore.
|
||||
type DeleteOptions struct {
|
||||
*SelectOptions
|
||||
Confirm bool
|
||||
Client clientset.Interface
|
||||
Client controllerclient.Client
|
||||
Namespace string
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func NewDeleteOptions(singularTypeName string) *DeleteOptions {
|
||||
// Complete fills in the correct values for all the options.
|
||||
func (o *DeleteOptions) Complete(f client.Factory, args []string) error {
|
||||
o.Namespace = f.Namespace()
|
||||
client, err := f.Client()
|
||||
client, err := f.KubebuilderClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -71,20 +71,23 @@ const (
|
||||
// files will be written to
|
||||
defaultCredentialsDirectory = "/tmp/credentials"
|
||||
|
||||
defaultResourceTimeout = 10 * time.Minute
|
||||
defaultResourceTimeout = 10 * time.Minute
|
||||
defaultDataMoverPrepareTimeout = 30 * time.Minute
|
||||
)
|
||||
|
||||
type nodeAgentServerConfig struct {
|
||||
metricsAddress string
|
||||
resourceTimeout time.Duration
|
||||
metricsAddress string
|
||||
resourceTimeout time.Duration
|
||||
dataMoverPrepareTimeout time.Duration
|
||||
}
|
||||
|
||||
func NewServerCommand(f client.Factory) *cobra.Command {
|
||||
logLevelFlag := logging.LogLevelFlag(logrus.InfoLevel)
|
||||
formatFlag := logging.NewFormatFlag()
|
||||
config := nodeAgentServerConfig{
|
||||
metricsAddress: defaultMetricsAddress,
|
||||
resourceTimeout: defaultResourceTimeout,
|
||||
metricsAddress: defaultMetricsAddress,
|
||||
resourceTimeout: defaultResourceTimeout,
|
||||
dataMoverPrepareTimeout: defaultDataMoverPrepareTimeout,
|
||||
}
|
||||
|
||||
command := &cobra.Command{
|
||||
@@ -110,6 +113,7 @@ func NewServerCommand(f client.Factory) *cobra.Command {
|
||||
command.Flags().Var(logLevelFlag, "log-level", fmt.Sprintf("The level at which to log. Valid values are %s.", strings.Join(logLevelFlag.AllowedValues(), ", ")))
|
||||
command.Flags().Var(formatFlag, "log-format", fmt.Sprintf("The format for log output. Valid values are %s.", strings.Join(formatFlag.AllowedValues(), ", ")))
|
||||
command.Flags().DurationVar(&config.resourceTimeout, "resource-timeout", config.resourceTimeout, "How long to wait for resource processes which are not covered by other specific timeout parameters. Default is 10 minutes.")
|
||||
command.Flags().DurationVar(&config.dataMoverPrepareTimeout, "data-mover-prepare-timeout", config.dataMoverPrepareTimeout, "How long to wait for preparing a DataUpload/DataDownload. Default is 30 minutes.")
|
||||
|
||||
return command
|
||||
}
|
||||
@@ -220,9 +224,9 @@ func (s *nodeAgentServer) run() {
|
||||
s.logger.Fatalf("Failed to start metric server for node agent at [%s]: %v", s.metricsAddress, err)
|
||||
}
|
||||
}()
|
||||
s.metrics = metrics.NewPodVolumeMetrics()
|
||||
s.metrics = metrics.NewNodeMetrics()
|
||||
s.metrics.RegisterAllMetrics()
|
||||
s.metrics.InitPodVolumeMetricsForNode(s.nodeName)
|
||||
s.metrics.InitMetricsForNode(s.nodeName)
|
||||
|
||||
s.markInProgressCRsFailed()
|
||||
|
||||
@@ -256,11 +260,15 @@ func (s *nodeAgentServer) run() {
|
||||
s.logger.WithError(err).Fatal("Unable to create the pod volume restore controller")
|
||||
}
|
||||
|
||||
if err = controller.NewDataUploadReconciler(s.mgr.GetClient(), s.kubeClient, s.csiSnapshotClient.SnapshotV1(), repoEnsurer, clock.RealClock{}, credentialGetter, s.nodeName, s.fileSystem, s.logger).SetupWithManager(s.mgr); err != nil {
|
||||
dataUploadReconciler := controller.NewDataUploadReconciler(s.mgr.GetClient(), s.kubeClient, s.csiSnapshotClient.SnapshotV1(), repoEnsurer, clock.RealClock{}, credentialGetter, s.nodeName, s.fileSystem, s.config.dataMoverPrepareTimeout, s.logger, s.metrics)
|
||||
s.markDataUploadsCancel(dataUploadReconciler)
|
||||
if err = dataUploadReconciler.SetupWithManager(s.mgr); err != nil {
|
||||
s.logger.WithError(err).Fatal("Unable to create the data upload controller")
|
||||
}
|
||||
|
||||
if err = controller.NewDataDownloadReconciler(s.mgr.GetClient(), s.kubeClient, repoEnsurer, credentialGetter, s.nodeName, s.logger).SetupWithManager(s.mgr); err != nil {
|
||||
dataDownloadReconciler := controller.NewDataDownloadReconciler(s.mgr.GetClient(), s.kubeClient, repoEnsurer, credentialGetter, s.nodeName, s.config.dataMoverPrepareTimeout, s.logger, s.metrics)
|
||||
s.markDataDownloadsCancel(dataDownloadReconciler)
|
||||
if err = dataDownloadReconciler.SetupWithManager(s.mgr); err != nil {
|
||||
s.logger.WithError(err).Fatal("Unable to create the data download controller")
|
||||
}
|
||||
|
||||
@@ -333,6 +341,62 @@ func (s *nodeAgentServer) markInProgressCRsFailed() {
|
||||
s.markInProgressPVRsFailed(client)
|
||||
}
|
||||
|
||||
func (s *nodeAgentServer) markDataUploadsCancel(r *controller.DataUploadReconciler) {
|
||||
// the function is called before starting the controller manager, the embedded client isn't ready to use, so create a new one here
|
||||
client, err := ctrlclient.New(s.mgr.GetConfig(), ctrlclient.Options{Scheme: s.mgr.GetScheme()})
|
||||
if err != nil {
|
||||
s.logger.WithError(errors.WithStack(err)).Error("failed to create client")
|
||||
return
|
||||
}
|
||||
if dataUploads, err := r.FindDataUploads(s.ctx, client, s.namespace); err != nil {
|
||||
s.logger.WithError(errors.WithStack(err)).Error("failed to find data downloads")
|
||||
} else {
|
||||
for i := range dataUploads {
|
||||
du := dataUploads[i]
|
||||
if du.Status.Phase == velerov2alpha1api.DataUploadPhaseAccepted ||
|
||||
du.Status.Phase == velerov2alpha1api.DataUploadPhasePrepared ||
|
||||
du.Status.Phase == velerov2alpha1api.DataUploadPhaseInProgress {
|
||||
updated := du.DeepCopy()
|
||||
updated.Spec.Cancel = true
|
||||
updated.Status.Message = fmt.Sprintf("found a dataupload with status %q during the node-agent starting, mark it as cancel", du.Status.Phase)
|
||||
if err := client.Patch(s.ctx, updated, ctrlclient.MergeFrom(&du)); err != nil {
|
||||
s.logger.WithError(errors.WithStack(err)).Errorf("failed to mark datadownload %q cancel", du.GetName())
|
||||
continue
|
||||
}
|
||||
s.logger.WithField("dataupload", du.GetName()).Warn(du.Status.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *nodeAgentServer) markDataDownloadsCancel(r *controller.DataDownloadReconciler) {
|
||||
// the function is called before starting the controller manager, the embedded client isn't ready to use, so create a new one here
|
||||
client, err := ctrlclient.New(s.mgr.GetConfig(), ctrlclient.Options{Scheme: s.mgr.GetScheme()})
|
||||
if err != nil {
|
||||
s.logger.WithError(errors.WithStack(err)).Error("failed to create client")
|
||||
return
|
||||
}
|
||||
if dataDownloads, err := r.FindDataDownloads(s.ctx, client, s.namespace); err != nil {
|
||||
s.logger.WithError(errors.WithStack(err)).Error("failed to find data downloads")
|
||||
} else {
|
||||
for i := range dataDownloads {
|
||||
dd := dataDownloads[i]
|
||||
if dd.Status.Phase == velerov2alpha1api.DataDownloadPhaseAccepted ||
|
||||
dd.Status.Phase == velerov2alpha1api.DataDownloadPhasePrepared ||
|
||||
dd.Status.Phase == velerov2alpha1api.DataDownloadPhaseInProgress {
|
||||
updated := dd.DeepCopy()
|
||||
updated.Spec.Cancel = true
|
||||
updated.Status.Message = fmt.Sprintf("found a datadownload with status %q during the node-agent starting, mark it as cancel", dd.Status.Phase)
|
||||
if err := client.Patch(s.ctx, updated, ctrlclient.MergeFrom(dd)); err != nil {
|
||||
s.logger.WithError(errors.WithStack(err)).Errorf("failed to mark datadownload %q cancel", dd.GetName())
|
||||
continue
|
||||
}
|
||||
s.logger.WithField("datadownload", dd.GetName()).Warn(dd.Status.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *nodeAgentServer) markInProgressPVBsFailed(client ctrlclient.Client) {
|
||||
pvbs := &velerov1api.PodVolumeBackupList{}
|
||||
if err := client.List(s.ctx, pvbs, &ctrlclient.MatchingFields{"metadata.namespace": s.namespace}); err != nil {
|
||||
|
||||
@@ -27,7 +27,9 @@ import (
|
||||
"github.com/spf13/pflag"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/vmware-tanzu/velero/internal/resourcemodifiers"
|
||||
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
@@ -35,9 +37,8 @@ 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/boolptr"
|
||||
"github.com/vmware-tanzu/velero/pkg/util/kube"
|
||||
)
|
||||
|
||||
func NewCreateCommand(f client.Factory, use string) *cobra.Command {
|
||||
@@ -96,8 +97,7 @@ type CreateOptions struct {
|
||||
AllowPartiallyFailed flag.OptionalBool
|
||||
ItemOperationTimeout time.Duration
|
||||
ResourceModifierConfigMap string
|
||||
|
||||
client veleroclient.Interface
|
||||
client kbclient.WithWatch
|
||||
}
|
||||
|
||||
func NewCreateOptions() *CreateOptions {
|
||||
@@ -158,7 +158,7 @@ func (o *CreateOptions) Complete(args []string, f client.Factory) error {
|
||||
o.RestoreName = fmt.Sprintf("%s-%s", sourceName, time.Now().Format("20060102150405"))
|
||||
}
|
||||
|
||||
client, err := f.Client()
|
||||
client, err := f.KubebuilderWatchClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -191,15 +191,20 @@ func (o *CreateOptions) Validate(c *cobra.Command, args []string, f client.Facto
|
||||
|
||||
switch {
|
||||
case o.BackupName != "":
|
||||
if _, err := o.client.VeleroV1().Backups(f.Namespace()).Get(context.TODO(), o.BackupName, metav1.GetOptions{}); err != nil {
|
||||
backup := new(api.Backup)
|
||||
if err := o.client.Get(context.TODO(), kbclient.ObjectKey{Namespace: f.Namespace(), Name: o.BackupName}, backup); err != nil {
|
||||
return err
|
||||
}
|
||||
case o.ScheduleName != "":
|
||||
backupItems, err := o.client.VeleroV1().Backups(f.Namespace()).List(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("%s=%s", api.ScheduleNameLabel, o.ScheduleName)})
|
||||
backupList := new(api.BackupList)
|
||||
err := o.client.List(context.TODO(), backupList, &kbclient.ListOptions{
|
||||
LabelSelector: labels.SelectorFromSet(map[string]string{api.ScheduleNameLabel: o.ScheduleName}),
|
||||
Namespace: f.Namespace(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(backupItems.Items) == 0 {
|
||||
if len(backupList.Items) == 0 {
|
||||
return errors.Errorf("No backups found for the schedule %s", o.ScheduleName)
|
||||
}
|
||||
}
|
||||
@@ -253,14 +258,18 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error {
|
||||
// PartiallyFailed backup for the provided schedule, and use that specific backup
|
||||
// to restore from.
|
||||
if o.ScheduleName != "" && boolptr.IsSetToTrue(o.AllowPartiallyFailed.Value) {
|
||||
backups, err := o.client.VeleroV1().Backups(f.Namespace()).List(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("%s=%s", api.ScheduleNameLabel, o.ScheduleName)})
|
||||
backupList := new(api.BackupList)
|
||||
err := o.client.List(context.TODO(), backupList, &kbclient.ListOptions{
|
||||
LabelSelector: labels.SelectorFromSet(map[string]string{api.ScheduleNameLabel: o.ScheduleName}),
|
||||
Namespace: f.Namespace(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if we find a Completed or PartiallyFailed backup for the schedule, restore specifically from that backup. If we don't
|
||||
// find one, proceed as-is -- the Velero server will handle validation.
|
||||
if backup := mostRecentBackup(backups.Items, api.BackupPhaseCompleted, api.BackupPhasePartiallyFailed); backup != nil {
|
||||
if backup := mostRecentBackup(backupList.Items, api.BackupPhaseCompleted, api.BackupPhasePartiallyFailed); backup != nil {
|
||||
// TODO(sk): this is kind of a hack -- we should revisit this and probably
|
||||
// move this logic to the server side or otherwise solve this problem.
|
||||
o.BackupName = backup.Name
|
||||
@@ -314,7 +323,6 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var restoreInformer cache.SharedIndexInformer
|
||||
var updates chan *api.Restore
|
||||
if o.Wait {
|
||||
stop := make(chan struct{})
|
||||
@@ -322,7 +330,12 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error {
|
||||
|
||||
updates = make(chan *api.Restore)
|
||||
|
||||
restoreInformer = v1.NewRestoreInformer(o.client, f.Namespace(), 0, nil)
|
||||
lw := kube.InternalLW{
|
||||
Client: o.client,
|
||||
Namespace: f.Namespace(),
|
||||
ObjectList: new(api.RestoreList),
|
||||
}
|
||||
restoreInformer := cache.NewSharedInformer(&lw, &api.Restore{}, time.Second)
|
||||
|
||||
restoreInformer.AddEventHandler(
|
||||
cache.FilteringResourceEventHandler{
|
||||
@@ -354,7 +367,7 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error {
|
||||
go restoreInformer.Run(stop)
|
||||
}
|
||||
|
||||
restore, err := o.client.VeleroV1().Restores(restore.Namespace).Create(context.TODO(), restore, metav1.CreateOptions{})
|
||||
err := o.client.Create(context.TODO(), restore, &kbclient.CreateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
Copyright 2020 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.
|
||||
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 restore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
controllerclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
cmdtest "github.com/vmware-tanzu/velero/pkg/cmd/test"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
)
|
||||
|
||||
func TestIsResourcePolicyValid(t *testing.T) {
|
||||
require.True(t, isResourcePolicyValid(string(velerov1api.PolicyTypeNone)))
|
||||
require.True(t, isResourcePolicyValid(string(velerov1api.PolicyTypeUpdate)))
|
||||
require.False(t, isResourcePolicyValid(""))
|
||||
}
|
||||
|
||||
func TestMostRecentBackup(t *testing.T) {
|
||||
backups := []velerov1api.Backup{
|
||||
*builder.ForBackup(cmdtest.VeleroNameSpace, "backup0").StartTimestamp(time.Now().Add(3 * time.Second)).Phase(velerov1api.BackupPhaseDeleting).Result(),
|
||||
*builder.ForBackup(cmdtest.VeleroNameSpace, "backup1").StartTimestamp(time.Now().Add(time.Second)).Phase(velerov1api.BackupPhaseCompleted).Result(),
|
||||
*builder.ForBackup(cmdtest.VeleroNameSpace, "backup2").StartTimestamp(time.Now().Add(2 * time.Second)).Phase(velerov1api.BackupPhasePartiallyFailed).Result(),
|
||||
}
|
||||
|
||||
expectedBackup := builder.ForBackup(cmdtest.VeleroNameSpace, "backup2").StartTimestamp(time.Now().Add(2 * time.Second)).Phase(velerov1api.BackupPhasePartiallyFailed).Result()
|
||||
|
||||
resultBackup := mostRecentBackup(backups, velerov1api.BackupPhaseCompleted, velerov1api.BackupPhasePartiallyFailed)
|
||||
|
||||
require.Equal(t, expectedBackup.Name, resultBackup.Name)
|
||||
}
|
||||
|
||||
func TestCreateCommand(t *testing.T) {
|
||||
name := "nameToBeCreated"
|
||||
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{}
|
||||
|
||||
// create command
|
||||
cmd := NewCreateCommand(f, "")
|
||||
require.Equal(t, "Create a restore", cmd.Short)
|
||||
|
||||
backupName := "backup1"
|
||||
scheduleName := "schedule1"
|
||||
restoreVolumes := "true"
|
||||
preserveNodePorts := "true"
|
||||
labels := "c=foo"
|
||||
includeNamespaces := "app1,app2"
|
||||
excludeNamespaces := "pod1,pod2,pod3"
|
||||
existingResourcePolicy := "none"
|
||||
includeResources := "sc,sts"
|
||||
excludeResources := "job"
|
||||
statusIncludeResources := "sc,sts"
|
||||
statusExcludeResources := "job"
|
||||
namespaceMappings := "a:b"
|
||||
selector := "foo=bar"
|
||||
includeClusterResources := "true"
|
||||
allowPartiallyFailed := "true"
|
||||
itemOperationTimeout := "10m0s"
|
||||
|
||||
flags := new(pflag.FlagSet)
|
||||
o := NewCreateOptions()
|
||||
o.BindFlags(flags)
|
||||
|
||||
flags.Parse([]string{"--from-backup", backupName})
|
||||
flags.Parse([]string{"--from-schedule", scheduleName})
|
||||
flags.Parse([]string{"--restore-volumes", restoreVolumes})
|
||||
flags.Parse([]string{"--preserve-nodeports", preserveNodePorts})
|
||||
flags.Parse([]string{"--labels", labels})
|
||||
flags.Parse([]string{"--existing-resource-policy", existingResourcePolicy})
|
||||
flags.Parse([]string{"--include-namespaces", includeNamespaces})
|
||||
flags.Parse([]string{"--exclude-namespaces", excludeNamespaces})
|
||||
flags.Parse([]string{"--include-resources", includeResources})
|
||||
flags.Parse([]string{"--exclude-resources", excludeResources})
|
||||
flags.Parse([]string{"--status-include-resources", statusIncludeResources})
|
||||
flags.Parse([]string{"--status-exclude-resources", statusExcludeResources})
|
||||
flags.Parse([]string{"--namespace-mappings", namespaceMappings})
|
||||
flags.Parse([]string{"--selector", selector})
|
||||
flags.Parse([]string{"--include-cluster-resources", includeClusterResources})
|
||||
flags.Parse([]string{"--allow-partially-failed", allowPartiallyFailed})
|
||||
flags.Parse([]string{"--item-operation-timeout", itemOperationTimeout})
|
||||
|
||||
client := velerotest.NewFakeControllerRuntimeClient(t).(kbclient.WithWatch)
|
||||
|
||||
f.On("Namespace").Return(mock.Anything)
|
||||
f.On("KubebuilderWatchClient").Return(client, nil)
|
||||
|
||||
//Complete
|
||||
e := o.Complete(args, f)
|
||||
require.NoError(t, e)
|
||||
|
||||
//Validate
|
||||
e = o.Validate(cmd, args, f)
|
||||
require.Contains(t, e.Error(), "either a backup or schedule must be specified, but not both")
|
||||
|
||||
//cmd
|
||||
e = o.Run(cmd, f)
|
||||
require.NoError(t, e)
|
||||
|
||||
require.Equal(t, backupName, o.BackupName)
|
||||
require.Equal(t, scheduleName, o.ScheduleName)
|
||||
require.Equal(t, restoreVolumes, o.RestoreVolumes.String())
|
||||
require.Equal(t, preserveNodePorts, o.PreserveNodePorts.String())
|
||||
require.Equal(t, labels, o.Labels.String())
|
||||
require.Equal(t, includeNamespaces, o.IncludeNamespaces.String())
|
||||
require.Equal(t, excludeNamespaces, o.ExcludeNamespaces.String())
|
||||
require.Equal(t, existingResourcePolicy, o.ExistingResourcePolicy)
|
||||
require.Equal(t, includeResources, o.IncludeResources.String())
|
||||
require.Equal(t, excludeResources, o.ExcludeResources.String())
|
||||
|
||||
require.Equal(t, statusIncludeResources, o.StatusIncludeResources.String())
|
||||
require.Equal(t, statusExcludeResources, o.StatusExcludeResources.String())
|
||||
require.Equal(t, namespaceMappings, o.NamespaceMappings.String())
|
||||
require.Equal(t, selector, o.Selector.String())
|
||||
require.Equal(t, includeClusterResources, o.IncludeClusterResources.String())
|
||||
require.Equal(t, allowPartiallyFailed, o.AllowPartiallyFailed.String())
|
||||
require.Equal(t, itemOperationTimeout, o.ItemOperationTimeout.String())
|
||||
|
||||
})
|
||||
|
||||
t.Run("create a restore from schedule", func(t *testing.T) {
|
||||
f := &factorymocks.Factory{}
|
||||
c := NewCreateCommand(f, "")
|
||||
require.Equal(t, "Create a restore", c.Short)
|
||||
flags := new(pflag.FlagSet)
|
||||
o := NewCreateOptions()
|
||||
o.BindFlags(flags)
|
||||
|
||||
fromSchedule := "schedule-name-1"
|
||||
flags.Parse([]string{"--from-schedule", fromSchedule})
|
||||
|
||||
kbclient := velerotest.NewFakeControllerRuntimeClient(t).(kbclient.WithWatch)
|
||||
schedule := builder.ForSchedule(cmdtest.VeleroNameSpace, fromSchedule).Result()
|
||||
require.NoError(t, kbclient.Create(context.Background(), schedule, &controllerclient.CreateOptions{}))
|
||||
backup := builder.ForBackup(cmdtest.VeleroNameSpace, "test-backup").FromSchedule(schedule).Phase(velerov1api.BackupPhaseCompleted).Result()
|
||||
require.NoError(t, kbclient.Create(context.Background(), backup, &controllerclient.CreateOptions{}))
|
||||
|
||||
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
|
||||
f.On("KubebuilderWatchClient").Return(kbclient, nil)
|
||||
|
||||
require.NoError(t, o.Complete(args, f))
|
||||
require.NoError(t, o.Validate(c, []string{}, f))
|
||||
require.NoError(t, o.Run(c, f))
|
||||
})
|
||||
|
||||
t.Run("create a restore from not-existed backup", func(t *testing.T) {
|
||||
f := &factorymocks.Factory{}
|
||||
c := NewCreateCommand(f, "")
|
||||
require.Equal(t, "Create a restore", c.Short)
|
||||
flags := new(pflag.FlagSet)
|
||||
o := NewCreateOptions()
|
||||
o.BindFlags(flags)
|
||||
nonExistedBackupName := "not-exist"
|
||||
|
||||
flags.Parse([]string{"--wait", "true"})
|
||||
flags.Parse([]string{"--from-backup", nonExistedBackupName})
|
||||
|
||||
kbclient := velerotest.NewFakeControllerRuntimeClient(t).(kbclient.WithWatch)
|
||||
|
||||
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
|
||||
f.On("KubebuilderWatchClient").Return(kbclient, nil)
|
||||
|
||||
require.NoError(t, o.Complete(nil, f))
|
||||
err := o.Validate(c, []string{}, f)
|
||||
require.Equal(t, "backups.velero.io \"not-exist\" not found", err.Error())
|
||||
})
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
kubeerrs "k8s.io/apimachinery/pkg/util/errors"
|
||||
controllerclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
@@ -76,7 +77,8 @@ func Run(o *cli.DeleteOptions) error {
|
||||
switch {
|
||||
case len(o.Names) > 0:
|
||||
for _, name := range o.Names {
|
||||
restore, err := o.Client.VeleroV1().Restores(o.Namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
||||
restore := new(velerov1api.Restore)
|
||||
err := o.Client.Get(context.TODO(), controllerclient.ObjectKey{Namespace: o.Namespace, Name: name}, restore)
|
||||
if err != nil {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
continue
|
||||
@@ -84,27 +86,39 @@ func Run(o *cli.DeleteOptions) error {
|
||||
restores = append(restores, restore)
|
||||
}
|
||||
default:
|
||||
selector := labels.Everything().String()
|
||||
selector := labels.Everything()
|
||||
if o.Selector.LabelSelector != nil {
|
||||
selector = o.Selector.String()
|
||||
convertedSelector, err := metav1.LabelSelectorAsSelector(o.Selector.LabelSelector)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
selector = convertedSelector
|
||||
}
|
||||
res, err := o.Client.VeleroV1().Restores(o.Namespace).List(context.TODO(), metav1.ListOptions{
|
||||
restoreList := new(velerov1api.RestoreList)
|
||||
err := o.Client.List(context.TODO(), restoreList, &controllerclient.ListOptions{
|
||||
Namespace: o.Namespace,
|
||||
LabelSelector: selector,
|
||||
})
|
||||
if err != nil {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
}
|
||||
|
||||
for i := range res.Items {
|
||||
restores = append(restores, &res.Items[i])
|
||||
for i := range restoreList.Items {
|
||||
restores = append(restores, &restoreList.Items[i])
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
fmt.Println("errs: ", errs)
|
||||
return kubeerrs.NewAggregate(errs)
|
||||
}
|
||||
|
||||
if len(restores) == 0 {
|
||||
fmt.Println("No restores found")
|
||||
return nil
|
||||
}
|
||||
for _, r := range restores {
|
||||
err := o.Client.VeleroV1().Restores(r.Namespace).Delete(context.TODO(), r.Name, metav1.DeleteOptions{})
|
||||
err := o.Client.Delete(context.TODO(), r, &controllerclient.DeleteOptions{})
|
||||
if err != nil {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
continue
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
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.
|
||||
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 restore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
"github.com/stretchr/testify/require"
|
||||
controllerclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
|
||||
cmdtest "github.com/vmware-tanzu/velero/pkg/cmd/test"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
)
|
||||
|
||||
func TestDeleteCommand(t *testing.T) {
|
||||
restore1 := "restore-name-1"
|
||||
restore2 := "restore-name-2"
|
||||
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
|
||||
client := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
client.Create(context.Background(), builder.ForRestore(cmdtest.VeleroNameSpace, restore1).Result(), &controllerclient.CreateOptions{})
|
||||
client.Create(context.Background(), builder.ForRestore("default", restore2).Result(), &controllerclient.CreateOptions{})
|
||||
|
||||
f.On("KubebuilderClient").Return(client, nil)
|
||||
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
|
||||
|
||||
// create command
|
||||
c := NewDeleteCommand(f, "velero restore delete")
|
||||
c.SetArgs([]string{restore1, restore2})
|
||||
require.Equal(t, "Delete restores", c.Short)
|
||||
|
||||
o := cli.NewDeleteOptions("restore")
|
||||
flags := new(flag.FlagSet)
|
||||
o.BindFlags(flags)
|
||||
flags.Parse([]string{"--confirm"})
|
||||
|
||||
args := []string{restore1, restore2}
|
||||
|
||||
e := o.Complete(f, args)
|
||||
require.Equal(t, nil, e)
|
||||
|
||||
e = o.Validate(c, f, args)
|
||||
require.Equal(t, nil, e)
|
||||
|
||||
Run(o)
|
||||
|
||||
e = c.Execute()
|
||||
require.Equal(t, nil, e)
|
||||
|
||||
if os.Getenv(cmdtest.CaptureFlag) == "1" {
|
||||
return
|
||||
}
|
||||
|
||||
cmd := exec.Command(os.Args[0], []string{"-test.run=TestDeleteCommand"}...)
|
||||
cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag))
|
||||
stdout, _, err := veleroexec.RunCommand(cmd)
|
||||
if err != nil {
|
||||
require.Contains(t, stdout, fmt.Sprintf("restores.velero.io \"%s\" not found.", restore2))
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,8 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
controllerclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
@@ -48,34 +50,37 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
|
||||
Use: use + " [NAME1] [NAME2] [NAME...]",
|
||||
Short: "Describe restores",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
veleroClient, err := f.Client()
|
||||
cmd.CheckError(err)
|
||||
|
||||
kbClient, err := f.KubebuilderClient()
|
||||
cmd.CheckError(err)
|
||||
|
||||
var restores *velerov1api.RestoreList
|
||||
restoreList := new(velerov1api.RestoreList)
|
||||
if len(args) > 0 {
|
||||
restores = new(velerov1api.RestoreList)
|
||||
for _, name := range args {
|
||||
restore, err := veleroClient.VeleroV1().Restores(f.Namespace()).Get(context.TODO(), name, metav1.GetOptions{})
|
||||
restore := new(velerov1api.Restore)
|
||||
err := kbClient.Get(context.TODO(), controllerclient.ObjectKey{Namespace: f.Namespace(), Name: name}, restore)
|
||||
cmd.CheckError(err)
|
||||
restores.Items = append(restores.Items, *restore)
|
||||
restoreList.Items = append(restoreList.Items, *restore)
|
||||
}
|
||||
} else {
|
||||
restores, err = veleroClient.VeleroV1().Restores(f.Namespace()).List(context.TODO(), listOptions)
|
||||
parsedSelector, err := labels.Parse(listOptions.LabelSelector)
|
||||
cmd.CheckError(err)
|
||||
|
||||
err = kbClient.List(context.TODO(), restoreList, &controllerclient.ListOptions{LabelSelector: parsedSelector, Namespace: f.Namespace()})
|
||||
cmd.CheckError(err)
|
||||
}
|
||||
|
||||
first := true
|
||||
for i, restore := range restores.Items {
|
||||
opts := newPodVolumeRestoreListOptions(restore.Name)
|
||||
podvolumeRestoreList, err := veleroClient.VeleroV1().PodVolumeRestores(f.Namespace()).List(context.TODO(), opts)
|
||||
for i, restore := range restoreList.Items {
|
||||
podVolumeRestoreList := new(velerov1api.PodVolumeRestoreList)
|
||||
err = kbClient.List(context.TODO(), podVolumeRestoreList, &controllerclient.ListOptions{
|
||||
Namespace: f.Namespace(),
|
||||
LabelSelector: labels.SelectorFromSet(map[string]string{velerov1api.BackupNameLabel: label.GetValidName(restore.Name)}),
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error getting PodVolumeRestores for restore %s: %v\n", restore.Name, err)
|
||||
}
|
||||
|
||||
s := output.DescribeRestore(context.Background(), kbClient, &restores.Items[i], podvolumeRestoreList.Items, details, veleroClient, insecureSkipTLSVerify, caCertFile)
|
||||
s := output.DescribeRestore(context.Background(), kbClient, &restoreList.Items[i], podVolumeRestoreList.Items, details, insecureSkipTLSVerify, caCertFile)
|
||||
if first {
|
||||
first = false
|
||||
fmt.Print(s)
|
||||
@@ -94,11 +99,3 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// newPodVolumeRestoreListOptions creates a ListOptions with a label selector configured to
|
||||
// find PodVolumeRestores for the restore identified by name.
|
||||
func newPodVolumeRestoreListOptions(name string) metav1.ListOptions {
|
||||
return metav1.ListOptions{
|
||||
LabelSelector: fmt.Sprintf("%s=%s", velerov1api.RestoreNameLabel, label.GetValidName(name)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
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.
|
||||
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 restore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/client-go/rest"
|
||||
controllerclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
cmdtest "github.com/vmware-tanzu/velero/pkg/cmd/test"
|
||||
"github.com/vmware-tanzu/velero/pkg/features"
|
||||
"github.com/vmware-tanzu/velero/pkg/test"
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
)
|
||||
|
||||
func TestNewDescribeCommand(t *testing.T) {
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
restoreName := "restore-describe-1"
|
||||
testRestore := builder.ForRestore(cmdtest.VeleroNameSpace, restoreName).Result()
|
||||
|
||||
clientConfig := rest.Config{}
|
||||
kbClient := test.NewFakeControllerRuntimeClient(t)
|
||||
kbClient.Create(context.Background(), testRestore, &controllerclient.CreateOptions{})
|
||||
|
||||
f.On("ClientConfig").Return(&clientConfig, nil)
|
||||
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
|
||||
f.On("KubebuilderClient").Return(kbClient, nil)
|
||||
|
||||
// create command
|
||||
c := NewDescribeCommand(f, "velero restore describe")
|
||||
assert.Equal(t, "Describe restores", c.Short)
|
||||
|
||||
features.NewFeatureFlagSet("EnableCSI")
|
||||
defer features.NewFeatureFlagSet()
|
||||
|
||||
c.SetArgs([]string{restoreName})
|
||||
e := c.Execute()
|
||||
assert.NoError(t, e)
|
||||
|
||||
if os.Getenv(cmdtest.CaptureFlag) == "1" {
|
||||
return
|
||||
}
|
||||
cmd := exec.Command(os.Args[0], []string{"-test.run=TestNewDescribeCommand"}...)
|
||||
cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag))
|
||||
stdout, _, err := veleroexec.RunCommand(cmd)
|
||||
|
||||
if err == nil {
|
||||
assert.Contains(t, stdout, fmt.Sprintf("Name: %s", restoreName))
|
||||
return
|
||||
}
|
||||
t.Fatalf("process ran with err %v, want backups by get()", err)
|
||||
}
|
||||
@@ -21,6 +21,8 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
controllerclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
@@ -38,19 +40,22 @@ func NewGetCommand(f client.Factory, use string) *cobra.Command {
|
||||
err := output.ValidateFlags(c)
|
||||
cmd.CheckError(err)
|
||||
|
||||
veleroClient, err := f.Client()
|
||||
kbClient, err := f.KubebuilderClient()
|
||||
cmd.CheckError(err)
|
||||
|
||||
var restores *api.RestoreList
|
||||
restores := new(api.RestoreList)
|
||||
if len(args) > 0 {
|
||||
restores = new(api.RestoreList)
|
||||
for _, name := range args {
|
||||
restore, err := veleroClient.VeleroV1().Restores(f.Namespace()).Get(context.TODO(), name, metav1.GetOptions{})
|
||||
restore := new(api.Restore)
|
||||
err := kbClient.Get(context.TODO(), controllerclient.ObjectKey{Namespace: f.Namespace(), Name: name}, restore)
|
||||
cmd.CheckError(err)
|
||||
restores.Items = append(restores.Items, *restore)
|
||||
}
|
||||
} else {
|
||||
restores, err = veleroClient.VeleroV1().Restores(f.Namespace()).List(context.TODO(), listOptions)
|
||||
parsedSelector, err := labels.Parse(listOptions.LabelSelector)
|
||||
cmd.CheckError(err)
|
||||
|
||||
err = kbClient.List(context.TODO(), restores, &controllerclient.ListOptions{LabelSelector: parsedSelector, Namespace: f.Namespace()})
|
||||
cmd.CheckError(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
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.
|
||||
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 restore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
cmdtest "github.com/vmware-tanzu/velero/pkg/cmd/test"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
)
|
||||
|
||||
func TestNewGetCommand(t *testing.T) {
|
||||
args := []string{"b1", "b2", "b3"}
|
||||
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
|
||||
client := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
|
||||
for _, restoreName := range args {
|
||||
restore := builder.ForRestore(cmdtest.VeleroNameSpace, restoreName).ObjectMeta(builder.WithLabels("abc", "abc")).Result()
|
||||
err := client.Create(context.Background(), restore, &kbclient.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
f.On("KubebuilderClient").Return(client, nil)
|
||||
f.On("Namespace").Return(cmdtest.VeleroNameSpace)
|
||||
|
||||
// create command
|
||||
c := NewGetCommand(f, "velero restore get")
|
||||
require.Equal(t, "Get restores", c.Short)
|
||||
|
||||
c.SetArgs(args)
|
||||
e := c.Execute()
|
||||
require.NoError(t, e)
|
||||
|
||||
if os.Getenv(cmdtest.CaptureFlag) == "1" {
|
||||
return
|
||||
}
|
||||
|
||||
cmd := exec.Command(os.Args[0], []string{"-test.run=TestNewGetCommand"}...)
|
||||
cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag))
|
||||
stdout, _, err := veleroexec.RunCommand(cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
if err == nil {
|
||||
output := strings.Split(stdout, "\n")
|
||||
i := 0
|
||||
for _, line := range output {
|
||||
if strings.Contains(line, "New") {
|
||||
i++
|
||||
}
|
||||
}
|
||||
require.Equal(t, len(args), i)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
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.
|
||||
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 restore
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
cmdtest "github.com/vmware-tanzu/velero/pkg/cmd/test"
|
||||
)
|
||||
|
||||
func TestNewLogsCommand(t *testing.T) {
|
||||
t.Run("Flag test", func(t *testing.T) {
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
|
||||
c := NewLogsCommand(f)
|
||||
require.Equal(t, "Get restore logs", c.Short)
|
||||
flags := new(flag.FlagSet)
|
||||
|
||||
timeout := "1m0s"
|
||||
insecureSkipTLSVerify := "true"
|
||||
caCertFile := "testing"
|
||||
|
||||
flags.Parse([]string{"--timeout", timeout})
|
||||
flags.Parse([]string{"--insecure-skip-tls-verify", insecureSkipTLSVerify})
|
||||
flags.Parse([]string{"--cacert", caCertFile})
|
||||
|
||||
if os.Getenv(cmdtest.CaptureFlag) == "1" {
|
||||
c.SetArgs([]string{"test"})
|
||||
e := c.Execute()
|
||||
assert.NoError(t, e)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
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.
|
||||
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 restore
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
)
|
||||
|
||||
func TestNewRestoreCommand(t *testing.T) {
|
||||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
|
||||
// create command
|
||||
cmd := NewCommand(f)
|
||||
assert.Equal(t, "Work with restores", cmd.Short)
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
kubeerrs "k8s.io/apimachinery/pkg/util/errors"
|
||||
controllerclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
@@ -76,7 +77,8 @@ func Run(o *cli.DeleteOptions) error {
|
||||
switch {
|
||||
case len(o.Names) > 0:
|
||||
for _, name := range o.Names {
|
||||
schedule, err := o.Client.VeleroV1().Schedules(o.Namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
||||
schedule := new(velerov1api.Schedule)
|
||||
err := o.Client.Get(context.TODO(), controllerclient.ObjectKey{Namespace: o.Namespace, Name: name}, schedule)
|
||||
if err != nil {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
continue
|
||||
@@ -84,19 +86,25 @@ func Run(o *cli.DeleteOptions) error {
|
||||
schedules = append(schedules, schedule)
|
||||
}
|
||||
default:
|
||||
selector := labels.Everything().String()
|
||||
selector := labels.Everything()
|
||||
if o.Selector.LabelSelector != nil {
|
||||
selector = o.Selector.String()
|
||||
convertedSelector, err := metav1.LabelSelectorAsSelector(o.Selector.LabelSelector)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
selector = convertedSelector
|
||||
}
|
||||
res, err := o.Client.VeleroV1().Schedules(o.Namespace).List(context.TODO(), metav1.ListOptions{
|
||||
scheduleList := new(velerov1api.ScheduleList)
|
||||
err := o.Client.List(context.TODO(), scheduleList, &controllerclient.ListOptions{
|
||||
Namespace: o.Namespace,
|
||||
LabelSelector: selector,
|
||||
})
|
||||
if err != nil {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
}
|
||||
|
||||
for i := range res.Items {
|
||||
schedules = append(schedules, &res.Items[i])
|
||||
for i := range scheduleList.Items {
|
||||
schedules = append(schedules, &scheduleList.Items[i])
|
||||
}
|
||||
}
|
||||
if len(schedules) == 0 {
|
||||
@@ -105,7 +113,7 @@ func Run(o *cli.DeleteOptions) error {
|
||||
}
|
||||
|
||||
for _, s := range schedules {
|
||||
err := o.Client.VeleroV1().Schedules(s.Namespace).Delete(context.TODO(), s.Name, metav1.DeleteOptions{})
|
||||
err := o.Client.Delete(context.TODO(), s, &controllerclient.DeleteOptions{})
|
||||
if err != nil {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
continue
|
||||
|
||||
@@ -25,12 +25,11 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
"github.com/vmware-tanzu/velero/pkg/buildinfo"
|
||||
"github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/scheme"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
)
|
||||
|
||||
func TestPrintVersion(t *testing.T) {
|
||||
@@ -83,7 +82,7 @@ func TestPrintVersion(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var (
|
||||
kbClient = fake.NewClientBuilder().WithScheme(scheme.Scheme).Build()
|
||||
kbClient = velerotest.NewFakeControllerRuntimeClient(t)
|
||||
serverStatusGetter = new(mockServerStatusGetter)
|
||||
buf = new(bytes.Buffer)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user