Unverified Commit 9dbd238c authored by Bridget McErlean's avatar Bridget McErlean Committed by GitHub
Browse files

Use controller-runtime client to get restic secrets (#3320)


* Use kubebuilder client for fetching restic secrets

Instead of using a SecretInformer for fetching secrets for restic, use
the cached client provided by the controller-runtime manager.

In order to use this client, the scheme for Secrets must be added to the
scheme used by the manager so this is added when creating the manager in
both the velero and restic servers.

This change also refactors some of the tests to add a shared utility for
creating a fake controller-runtime client which is now used among all
tests which use that client. This has been added to ensure that all
tests use the same client with the same scheme.
Signed-off-by: default avatarBridget McErlean <bmcerlean@vmware.com>

* Add builder for SecretKeySelector
Signed-off-by: default avatarBridget McErlean <bmcerlean@vmware.com>
parent 6bdd4ac1
Showing with 121 additions and 210 deletions
+121 -210
/*
Copyright 2019 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -55,3 +55,9 @@ func (b *SecretBuilder) ObjectMeta(opts ...ObjectMetaOpt) *SecretBuilder {
return b
}
// Data sets the Secret data.
func (b *SecretBuilder) Data(data map[string][]byte) *SecretBuilder {
b.object.Data = data
return b
}
/*
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 builder
import (
corev1api "k8s.io/api/core/v1"
)
// SecretKeySelectorBuilder builds SecretKeySelector objects.
type SecretKeySelectorBuilder struct {
object *corev1api.SecretKeySelector
}
// ForSecretKeySelector is the constructor for a SecretKeySelectorBuilder.
func ForSecretKeySelector(name string, key string) *SecretKeySelectorBuilder {
return &SecretKeySelectorBuilder{
object: &corev1api.SecretKeySelector{
LocalObjectReference: corev1api.LocalObjectReference{
Name: name,
},
Key: key,
},
}
}
// Result returns the built SecretKeySelector.
func (b *SecretKeySelectorBuilder) Result() *corev1api.SecretKeySelector {
return b.object
}
......@@ -27,12 +27,12 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
corev1api "k8s.io/api/core/v1"
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/builder"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/util/flag"
......@@ -178,13 +178,8 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error {
CACert: caCertData,
},
},
Config: o.Config.Data(),
Credential: &corev1api.SecretKeySelector{
LocalObjectReference: corev1api.LocalObjectReference{
Name: secretName,
},
Key: secretKey,
},
Config: o.Config.Data(),
Credential: builder.ForSecretKeySelector(secretName, secretKey).Result(),
Default: o.DefaultBackupStorageLocation,
AccessMode: velerov1api.BackupStorageLocationAccessMode(o.AccessMode.String()),
BackupSyncPeriod: backupSyncPeriod,
......
......@@ -25,11 +25,11 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
corev1api "k8s.io/api/core/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/builder"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/util/flag"
......@@ -139,13 +139,8 @@ func (o *SetOptions) Run(c *cobra.Command, f client.Factory) error {
location.Spec.Default = o.DefaultBackupStorageLocation
location.Spec.StorageType.ObjectStorage.CACert = caCertData
for k, v := range o.Credential.Data() {
location.Spec.Credential = &corev1api.SecretKeySelector{
LocalObjectReference: corev1api.LocalObjectReference{
Name: k,
},
Key: v,
}
for name, key := range o.Credential.Data() {
location.Spec.Credential = builder.ForSecretKeySelector(name, key).Result()
break
}
......
/*
Copyright 2020 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -49,7 +49,6 @@ import (
"github.com/vmware-tanzu/velero/pkg/controller"
clientset "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned"
informers "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions"
"github.com/vmware-tanzu/velero/pkg/restic"
"github.com/vmware-tanzu/velero/pkg/util/filesystem"
"github.com/vmware-tanzu/velero/pkg/util/logging"
......@@ -102,7 +101,6 @@ type resticServer struct {
veleroInformerFactory informers.SharedInformerFactory
kubeInformerFactory kubeinformers.SharedInformerFactory
podInformer cache.SharedIndexInformer
secretInformer cache.SharedIndexInformer
logger logrus.FieldLogger
ctx context.Context
cancelFunc context.CancelFunc
......@@ -136,22 +134,6 @@ func newResticServer(logger logrus.FieldLogger, factory client.Factory, metricAd
},
)
// use a stand-alone secrets informer so we can filter to only the restic credentials
// secret(s) within the velero namespace
//
// note: using an informer to access the single secret for all velero-managed
// restic repositories is overkill for now, but will be useful when we move
// to fully-encrypted backups and have unique keys per repository.
secretInformer := corev1informers.NewFilteredSecretInformer(
kubeClient,
factory.Namespace(),
0,
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
func(opts *metav1.ListOptions) {
opts.FieldSelector = fmt.Sprintf("metadata.name=%s", restic.CredentialsSecretName)
},
)
ctx, cancelFunc := context.WithCancel(context.Background())
clientConfig, err := factory.ClientConfig()
......@@ -160,7 +142,9 @@ func newResticServer(logger logrus.FieldLogger, factory client.Factory, metricAd
}
ctrl.SetLogger(zap.New(zap.UseDevMode(true)))
velerov1api.AddToScheme(scheme)
v1.AddToScheme(scheme)
mgr, err := ctrl.NewManager(clientConfig, ctrl.Options{
Scheme: scheme,
})
......@@ -174,7 +158,6 @@ func newResticServer(logger logrus.FieldLogger, factory client.Factory, metricAd
veleroInformerFactory: informers.NewFilteredSharedInformerFactory(veleroClient, 0, factory.Namespace(), nil),
kubeInformerFactory: kubeinformers.NewSharedInformerFactory(kubeClient, 0),
podInformer: podInformer,
secretInformer: secretInformer,
logger: logger,
ctx: ctx,
cancelFunc: cancelFunc,
......@@ -212,7 +195,6 @@ func (s *resticServer) run() {
s.veleroInformerFactory.Velero().V1().PodVolumeBackups(),
s.veleroClient.VeleroV1(),
s.podInformer,
s.secretInformer,
s.kubeInformerFactory.Core().V1().PersistentVolumeClaims(),
s.kubeInformerFactory.Core().V1().PersistentVolumes(),
s.metrics,
......@@ -225,7 +207,6 @@ func (s *resticServer) run() {
s.veleroInformerFactory.Velero().V1().PodVolumeRestores(),
s.veleroClient.VeleroV1(),
s.podInformer,
s.secretInformer,
s.kubeInformerFactory.Core().V1().PersistentVolumeClaims(),
s.kubeInformerFactory.Core().V1().PersistentVolumes(),
s.mgr.GetClient(),
......@@ -235,7 +216,6 @@ func (s *resticServer) run() {
go s.veleroInformerFactory.Start(s.ctx.Done())
go s.kubeInformerFactory.Start(s.ctx.Done())
go s.podInformer.Run(s.ctx.Done())
go s.secretInformer.Run(s.ctx.Done())
// TODO(2.0): presuming all controllers and resources are converted to runtime-controller
// by v2.0, the block from this line and including the `s.mgr.Start() will be
......
......@@ -24,10 +24,10 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
corev1api "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"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/util/flag"
......@@ -113,14 +113,9 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error {
Labels: o.Labels.Data(),
},
Spec: api.VolumeSnapshotLocationSpec{
Provider: o.Provider,
Config: o.Config.Data(),
Credential: &corev1api.SecretKeySelector{
LocalObjectReference: corev1api.LocalObjectReference{
Name: o.secretName,
},
Key: o.secretKey,
},
Provider: o.Provider,
Config: o.Config.Data(),
Credential: builder.ForSecretKeySelector(o.secretName, o.secretKey).Result(),
},
}
......
......@@ -23,11 +23,11 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
corev1api "k8s.io/api/core/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/builder"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/util/flag"
......@@ -99,13 +99,8 @@ func (o *SetOptions) Run(c *cobra.Command, f client.Factory) error {
return errors.WithStack(err)
}
for k, v := range o.Credential.Data() {
location.Spec.Credential = &corev1api.SecretKeySelector{
LocalObjectReference: corev1api.LocalObjectReference{
Name: k,
},
Key: v,
}
for name, key := range o.Credential.Data() {
location.Spec.Credential = builder.ForSecretKeySelector(name, key).Result()
break
}
......
/*
Copyright 2020 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -31,6 +31,7 @@ import (
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
corev1api "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
......@@ -40,10 +41,8 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
corev1informers "k8s.io/client-go/informers/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
snapshotv1beta1api "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1beta1"
snapshotv1beta1client "github.com/kubernetes-csi/external-snapshotter/client/v4/clientset/versioned"
......@@ -286,6 +285,8 @@ func newServer(f client.Factory, config serverConfig, logger *logrus.Logger) (*s
scheme := runtime.NewScheme()
velerov1api.AddToScheme(scheme)
corev1api.AddToScheme(scheme)
mgr, err := ctrl.NewManager(clientConfig, ctrl.Options{
Scheme: scheme,
})
......@@ -483,28 +484,10 @@ func (s *server) initRestic() error {
return err
}
// use a stand-alone secrets informer so we can filter to only the restic credentials
// secret(s) within the velero namespace
//
// note: using an informer to access the single secret for all velero-managed
// restic repositories is overkill for now, but will be useful when we move
// to fully-encrypted backups and have unique keys per repository.
secretsInformer := corev1informers.NewFilteredSecretInformer(
s.kubeClient,
s.namespace,
0,
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
func(opts *metav1.ListOptions) {
opts.FieldSelector = fmt.Sprintf("metadata.name=%s", restic.CredentialsSecretName)
},
)
go secretsInformer.Run(s.ctx.Done())
res, err := restic.NewRepositoryManager(
s.ctx,
s.namespace,
s.veleroClient,
secretsInformer,
s.sharedInformerFactory.Velero().V1().ResticRepositories(),
s.veleroClient.VeleroV1(),
s.mgr.GetClient(),
......
/*
Copyright 2020 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -181,9 +181,9 @@ func TestProcessBackupValidationFailures(t *testing.T) {
var fakeClient kbclient.Client
if test.backupLocation != nil {
fakeClient = newFakeClient(t, test.backupLocation)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t, test.backupLocation)
} else {
fakeClient = newFakeClient(t)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t)
}
c := &backupController{
......@@ -246,7 +246,7 @@ func TestBackupLocationLabel(t *testing.T) {
clientset = fake.NewSimpleClientset(test.backup)
sharedInformers = informers.NewSharedInformerFactory(clientset, 0)
logger = logging.DefaultLogger(logrus.DebugLevel, formatFlag)
fakeClient = newFakeClient(t)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t)
)
apiServer := velerotest.NewAPIServer(t)
......@@ -306,7 +306,7 @@ func TestDefaultBackupTTL(t *testing.T) {
formatFlag := logging.FormatText
var (
clientset = fake.NewSimpleClientset(test.backup)
fakeClient = newFakeClient(t)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t)
logger = logging.DefaultLogger(logrus.DebugLevel, formatFlag)
sharedInformers = informers.NewSharedInformerFactory(clientset, 0)
)
......@@ -783,9 +783,9 @@ func TestProcessBackupCompletions(t *testing.T) {
var fakeClient kbclient.Client
// add the test's backup storage location if it's different than the default
if test.backupLocation != nil && test.backupLocation != defaultBackupLocation {
fakeClient = newFakeClient(t, test.backupLocation)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t, test.backupLocation)
} else {
fakeClient = newFakeClient(t)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t)
}
apiServer := velerotest.NewAPIServer(t)
......
/*
Copyright 2020 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -144,7 +144,7 @@ func setupBackupDeletionControllerTest(t *testing.T, objects ...runtime.Object)
var (
client = fake.NewSimpleClientset(append(objects, req)...)
fakeClient = newFakeClient(t, objects...)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t, objects...)
sharedInformers = informers.NewSharedInformerFactory(client, 0)
volumeSnapshotter = &velerotest.FakeVolumeSnapshotter{SnapshotsTaken: sets.NewString()}
pluginManager = &pluginmocks.Manager{}
......@@ -1112,7 +1112,7 @@ func TestBackupDeletionControllerDeleteExpiredRequests(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
client := fake.NewSimpleClientset()
fakeClient := newFakeClient(t)
fakeClient := velerotest.NewFakeControllerRuntimeClient(t)
sharedInformers := informers.NewSharedInformerFactory(client, 0)
controller := NewBackupDeletionController(
......
/*
Copyright 2017, 2020 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -335,7 +335,7 @@ func TestBackupSyncControllerRun(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
var (
client = fake.NewSimpleClientset()
fakeClient = newFakeClient(t)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t)
sharedInformers = informers.NewSharedInformerFactory(client, 0)
pluginManager = &pluginmocks.Manager{}
backupStores = make(map[string]*persistencemocks.BackupStore)
......@@ -558,7 +558,7 @@ func TestDeleteOrphanedBackups(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
var (
client = fake.NewSimpleClientset()
fakeClient = newFakeClient(t)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t)
sharedInformers = informers.NewSharedInformerFactory(client, 0)
)
......@@ -652,7 +652,7 @@ func TestStorageLabelsInDeleteOrphanedBackups(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
var (
client = fake.NewSimpleClientset()
fakeClient = newFakeClient(t)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t)
sharedInformers = informers.NewSharedInformerFactory(client, 0)
)
......
/*
Copyright 2017 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -246,9 +246,9 @@ func TestProcessDownloadRequest(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
var fakeClient client.Client
if tc.backupLocation != nil {
fakeClient = newFakeClient(t, tc.backupLocation)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t, tc.backupLocation)
} else {
fakeClient = newFakeClient(t)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t)
}
harness := newDownloadRequestTestHarness(t, fakeClient)
......
/*
Copyright 2017, 2019 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -251,9 +251,9 @@ func TestGCControllerProcessQueueItem(t *testing.T) {
var fakeClient kbclient.Client
if test.backupLocation != nil {
fakeClient = newFakeClient(t, test.backupLocation)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t, test.backupLocation)
} else {
fakeClient = newFakeClient(t)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t)
}
controller := NewGCController(
......
/*
Copyright 2018, 2019 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -54,7 +54,6 @@ type podVolumeBackupController struct {
podVolumeBackupClient velerov1client.PodVolumeBackupsGetter
podVolumeBackupLister listers.PodVolumeBackupLister
secretLister corev1listers.SecretLister
podLister corev1listers.PodLister
pvcLister corev1listers.PersistentVolumeClaimLister
pvLister corev1listers.PersistentVolumeLister
......@@ -73,7 +72,6 @@ func NewPodVolumeBackupController(
podVolumeBackupInformer informers.PodVolumeBackupInformer,
podVolumeBackupClient velerov1client.PodVolumeBackupsGetter,
podInformer cache.SharedIndexInformer,
secretInformer cache.SharedIndexInformer,
pvcInformer corev1informers.PersistentVolumeClaimInformer,
pvInformer corev1informers.PersistentVolumeInformer,
metrics *metrics.ServerMetrics,
......@@ -85,7 +83,6 @@ func NewPodVolumeBackupController(
podVolumeBackupClient: podVolumeBackupClient,
podVolumeBackupLister: podVolumeBackupInformer.Lister(),
podLister: corev1listers.NewPodLister(podInformer.GetIndexer()),
secretLister: corev1listers.NewSecretLister(secretInformer.GetIndexer()),
pvcLister: pvcInformer.Lister(),
pvLister: pvInformer.Lister(),
kbClient: kbClient,
......@@ -101,7 +98,6 @@ func NewPodVolumeBackupController(
c.cacheSyncWaiters,
podVolumeBackupInformer.Informer().HasSynced,
podInformer.HasSynced,
secretInformer.HasSynced,
pvcInformer.Informer().HasSynced,
)
c.processBackupFunc = c.processBackup
......@@ -225,7 +221,7 @@ func (c *podVolumeBackupController) processBackup(req *velerov1api.PodVolumeBack
log.WithField("path", path).Debugf("Found path matching glob")
// temp creds
credentialsFile, err := restic.TempCredentialsFile(c.secretLister, req.Namespace, req.Spec.Pod.Namespace, c.fileSystem)
credentialsFile, err := restic.TempCredentialsFile(c.kbClient, req.Namespace, req.Spec.Pod.Namespace, c.fileSystem)
if err != nil {
log.WithError(err).Error("Error creating temp restic credentials file")
return c.fail(req, errors.Wrap(err, "error creating temp restic credentials file").Error(), log)
......
/*
Copyright 2020 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -56,7 +56,6 @@ type podVolumeRestoreController struct {
podVolumeRestoreClient velerov1client.PodVolumeRestoresGetter
podVolumeRestoreLister listers.PodVolumeRestoreLister
podLister corev1listers.PodLister
secretLister corev1listers.SecretLister
pvcLister corev1listers.PersistentVolumeClaimLister
pvLister corev1listers.PersistentVolumeLister
backupLocationInformer k8scache.Informer
......@@ -74,7 +73,6 @@ func NewPodVolumeRestoreController(
podVolumeRestoreInformer informers.PodVolumeRestoreInformer,
podVolumeRestoreClient velerov1client.PodVolumeRestoresGetter,
podInformer cache.SharedIndexInformer,
secretInformer cache.SharedIndexInformer,
pvcInformer corev1informers.PersistentVolumeClaimInformer,
pvInformer corev1informers.PersistentVolumeInformer,
kbClient client.Client,
......@@ -85,7 +83,6 @@ func NewPodVolumeRestoreController(
podVolumeRestoreClient: podVolumeRestoreClient,
podVolumeRestoreLister: podVolumeRestoreInformer.Lister(),
podLister: corev1listers.NewPodLister(podInformer.GetIndexer()),
secretLister: corev1listers.NewSecretLister(secretInformer.GetIndexer()),
pvcLister: pvcInformer.Lister(),
pvLister: pvInformer.Lister(),
kbClient: kbClient,
......@@ -100,7 +97,6 @@ func NewPodVolumeRestoreController(
c.cacheSyncWaiters,
podVolumeRestoreInformer.Informer().HasSynced,
podInformer.HasSynced,
secretInformer.HasSynced,
pvcInformer.Informer().HasSynced,
)
c.processRestoreFunc = c.processRestore
......@@ -304,7 +300,7 @@ func (c *podVolumeRestoreController) processRestore(req *velerov1api.PodVolumeRe
return c.failRestore(req, errors.Wrap(err, "error getting volume directory name").Error(), log)
}
credsFile, err := restic.TempCredentialsFile(c.secretLister, req.Namespace, req.Spec.Pod.Namespace, c.fileSystem)
credsFile, err := restic.TempCredentialsFile(c.kbClient, req.Namespace, req.Spec.Pod.Namespace, c.fileSystem)
if err != nil {
log.WithError(err).Error("Error creating temp restic credentials file")
return c.failRestore(req, errors.Wrap(err, "error creating temp restic credentials file").Error(), log)
......
/*
Copyright 2020 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -94,7 +94,7 @@ func TestFetchBackupInfo(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
var (
client = fake.NewSimpleClientset()
fakeClient = newFakeClient(t)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t)
restorer = &fakeRestorer{}
sharedInformers = informers.NewSharedInformerFactory(client, 0)
logger = velerotest.NewLogger()
......@@ -409,7 +409,7 @@ func TestProcessQueueItem(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
var (
client = fake.NewSimpleClientset()
fakeClient = newFakeClient(t)
fakeClient = velerotest.NewFakeControllerRuntimeClient(t)
restorer = &fakeRestorer{}
sharedInformers = informers.NewSharedInformerFactory(client, 0)
logger = velerotest.NewLogger()
......
/*
Copyright 2020 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -27,17 +27,13 @@ import (
"github.com/vmware-tanzu/velero/pkg/persistence"
persistencemocks "github.com/vmware-tanzu/velero/pkg/persistence/mocks"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"sigs.k8s.io/controller-runtime/pkg/manager"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/stretchr/testify/require"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"k8s.io/client-go/kubernetes/scheme"
......@@ -98,6 +94,7 @@ type testEnvironment struct {
// This function should be called only once for each package you're running tests within,
// usually the environment is initialized in a suite_test.go file within a `BeforeSuite` ginkgo block.
func newTestEnvironment() *testEnvironment {
// scheme.Scheme is initialized with all native Kubernetes types
err := velerov1api.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
......@@ -133,12 +130,6 @@ func (t *testEnvironment) stop() error {
return env.Stop()
}
func newFakeClient(t *testing.T, initObjs ...runtime.Object) client.Client {
err := velerov1api.AddToScheme(scheme.Scheme)
require.NoError(t, err)
return fake.NewFakeClientWithScheme(scheme.Scheme, initObjs...)
}
type fakeSingleObjectBackupStoreGetter struct {
store persistence.BackupStore
}
......
/*
Copyright 2018 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -29,12 +29,13 @@ import (
corev1api "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
corev1listers "k8s.io/client-go/listers/core/v1"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/builder"
velerov1listers "github.com/vmware-tanzu/velero/pkg/generated/listers/velero/v1"
"github.com/vmware-tanzu/velero/pkg/label"
"github.com/vmware-tanzu/velero/pkg/util/filesystem"
"github.com/vmware-tanzu/velero/pkg/util/kube"
)
const (
......@@ -241,14 +242,14 @@ func GetSnapshotsInBackup(backup *velerov1api.Backup, podVolumeBackupLister vele
// encryption key for the given repo and returns its path. The
// caller should generally call os.Remove() to remove the file
// when done with it.
func TempCredentialsFile(secretLister corev1listers.SecretLister, veleroNamespace, repoName string, fs filesystem.Interface) (string, error) {
secretGetter := NewListerSecretGetter(secretLister)
func TempCredentialsFile(client kbclient.Client, veleroNamespace, repoName string, fs filesystem.Interface) (string, error) {
// For now, all restic repos share the same key so we don't need the repoName to fetch it.
// When we move to full-backup encryption, we'll likely have a separate key per restic repo
// (all within the Velero server's namespace) so GetRepositoryKey will need to take the repo
// name as an argument as well.
repoKey, err := GetRepositoryKey(secretGetter, veleroNamespace)
// (all within the Velero server's namespace) so repoKeySelector will need to select the key
// for that repo.
repoKeySelector := builder.ForSecretKeySelector(CredentialsSecretName, CredentialsKey).Result()
repoKey, err := kube.GetSecretKey(client, veleroNamespace, repoKeySelector)
if err != nil {
return "", err
}
......@@ -261,7 +262,7 @@ func TempCredentialsFile(secretLister corev1listers.SecretLister, veleroNamespac
if _, err := file.Write(repoKey); err != nil {
// nothing we can do about an error closing the file here, and we're
// already returning an error about the write failing.
file.Close()
_ = file.Close()
return "", errors.WithStack(err)
}
......
/*
Copyright 2018 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -22,17 +22,10 @@ import (
"sort"
"testing"
"k8s.io/apimachinery/pkg/runtime"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1api "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/scheme"
corev1listers "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
k8sfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/builder"
......@@ -352,10 +345,9 @@ func TestGetSnapshotsInBackup(t *testing.T) {
func TestTempCredentialsFile(t *testing.T) {
var (
secretInformer = cache.NewSharedIndexInformer(nil, new(corev1api.Secret), 0, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
secretLister = corev1listers.NewSecretLister(secretInformer.GetIndexer())
fs = velerotest.NewFakeFileSystem()
secret = &corev1api.Secret{
fakeClient = velerotest.NewFakeControllerRuntimeClient(t)
fs = velerotest.NewFakeFileSystem()
secret = &corev1api.Secret{
ObjectMeta: metav1.ObjectMeta{
Namespace: "velero",
Name: CredentialsSecretName,
......@@ -366,15 +358,15 @@ func TestTempCredentialsFile(t *testing.T) {
}
)
// secret not in lister: expect an error
fileName, err := TempCredentialsFile(secretLister, "velero", "default", fs)
// secret not in server: expect an error
fileName, err := TempCredentialsFile(fakeClient, "velero", "default", fs)
assert.Error(t, err)
// now add secret to lister
require.NoError(t, secretInformer.GetStore().Add(secret))
// now add secret
require.NoError(t, fakeClient.Create(context.Background(), secret))
// secret in lister: expect temp file to be created with password
fileName, err = TempCredentialsFile(secretLister, "velero", "default", fs)
// secret in server: expect temp file to be created with password
fileName, err = TempCredentialsFile(fakeClient, "velero", "default", fs)
require.NoError(t, err)
contents, err := fs.ReadFile(fileName)
......@@ -400,7 +392,7 @@ func TestTempCACertFile(t *testing.T) {
}
)
fakeClient := newFakeClient(t)
fakeClient := velerotest.NewFakeControllerRuntimeClient(t)
fakeClient.Create(context.Background(), bsl)
// expect temp file to be created with cacert value
......@@ -645,9 +637,3 @@ func TestIsPVBMatchPod(t *testing.T) {
}
}
func newFakeClient(t *testing.T, initObjs ...runtime.Object) client.Client {
err := velerov1api.AddToScheme(scheme.Scheme)
require.NoError(t, err)
return k8sfake.NewFakeClientWithScheme(scheme.Scheme, initObjs...)
}
/*
Copyright 2018 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -24,7 +24,6 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
corev1listers "k8s.io/client-go/listers/core/v1"
)
const (
......@@ -62,53 +61,3 @@ func EnsureCommonRepositoryKey(secretClient corev1client.SecretsGetter, namespac
return nil
}
type SecretGetter interface {
GetSecret(namespace, name string) (*corev1api.Secret, error)
}
type clientSecretGetter struct {
client corev1client.SecretsGetter
}
func NewClientSecretGetter(client corev1client.SecretsGetter) SecretGetter {
return &clientSecretGetter{client: client}
}
func (c *clientSecretGetter) GetSecret(namespace, name string) (*corev1api.Secret, error) {
secret, err := c.client.Secrets(namespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return nil, errors.WithStack(err)
}
return secret, nil
}
type listerSecretGetter struct {
lister corev1listers.SecretLister
}
func NewListerSecretGetter(lister corev1listers.SecretLister) SecretGetter {
return &listerSecretGetter{lister: lister}
}
func (l *listerSecretGetter) GetSecret(namespace, name string) (*corev1api.Secret, error) {
secret, err := l.lister.Secrets(namespace).Get(name)
if err != nil {
return nil, errors.WithStack(err)
}
return secret, nil
}
func GetRepositoryKey(secretGetter SecretGetter, namespace string) ([]byte, error) {
secret, err := secretGetter.GetSecret(namespace, CredentialsSecretName)
if err != nil {
return nil, err
}
key, found := secret.Data[CredentialsKey]
if !found {
return nil, errors.Errorf("%q secret is missing data for key %q", CredentialsSecretName, CredentialsKey)
}
return key, nil
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment