2018-02-28 01:35:35 +00:00
/ *
2019-03-20 19:32:48 +00:00
Copyright 2018 the Velero contributors .
2018-02-28 01:35:35 +00:00
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 restic
import (
"context"
"sync"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
corev1api "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/cache"
2019-09-30 21:26:56 +00:00
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/label"
"github.com/vmware-tanzu/velero/pkg/util/boolptr"
2018-02-28 01:35:35 +00:00
)
2019-08-06 20:17:36 +00:00
type RestoreData struct {
Restore * velerov1api . Restore
Pod * corev1api . Pod
PodVolumeBackups [ ] * velerov1api . PodVolumeBackup
SourceNamespace , BackupLocation string
}
2018-02-28 01:35:35 +00:00
// Restorer can execute restic restores of volumes in a pod.
type Restorer interface {
// RestorePodVolumes restores all annotated volumes in a pod.
2019-08-06 20:17:36 +00:00
RestorePodVolumes ( RestoreData ) [ ] error
2018-02-28 01:35:35 +00:00
}
type restorer struct {
ctx context . Context
repoManager * repositoryManager
2018-06-22 19:07:23 +00:00
repoEnsurer * repositoryEnsurer
2018-02-28 01:35:35 +00:00
resultsLock sync . Mutex
2019-01-25 03:33:07 +00:00
results map [ string ] chan * velerov1api . PodVolumeRestore
2018-02-28 01:35:35 +00:00
}
2018-06-15 03:24:01 +00:00
func newRestorer (
ctx context . Context ,
rm * repositoryManager ,
2018-06-22 19:07:23 +00:00
repoEnsurer * repositoryEnsurer ,
2018-06-15 03:24:01 +00:00
podVolumeRestoreInformer cache . SharedIndexInformer ,
2018-06-22 19:07:23 +00:00
log logrus . FieldLogger ,
2018-06-15 03:24:01 +00:00
) * restorer {
2018-02-28 01:35:35 +00:00
r := & restorer {
ctx : ctx ,
repoManager : rm ,
2018-06-22 19:07:23 +00:00
repoEnsurer : repoEnsurer ,
2018-06-15 03:24:01 +00:00
2019-01-25 03:33:07 +00:00
results : make ( map [ string ] chan * velerov1api . PodVolumeRestore ) ,
2018-02-28 01:35:35 +00:00
}
podVolumeRestoreInformer . AddEventHandler (
cache . ResourceEventHandlerFuncs {
UpdateFunc : func ( _ , obj interface { } ) {
2019-01-25 03:33:07 +00:00
pvr := obj . ( * velerov1api . PodVolumeRestore )
2018-02-28 01:35:35 +00:00
2019-01-25 03:33:07 +00:00
if pvr . Status . Phase == velerov1api . PodVolumeRestorePhaseCompleted || pvr . Status . Phase == velerov1api . PodVolumeRestorePhaseFailed {
2018-02-28 01:35:35 +00:00
r . resultsLock . Lock ( )
2018-06-22 19:07:23 +00:00
defer r . resultsLock . Unlock ( )
resChan , ok := r . results [ resultsKey ( pvr . Spec . Pod . Namespace , pvr . Spec . Pod . Name ) ]
if ! ok {
log . Errorf ( "No results channel found for pod %s/%s to send pod volume restore %s/%s on" , pvr . Spec . Pod . Namespace , pvr . Spec . Pod . Name , pvr . Namespace , pvr . Name )
return
}
resChan <- pvr
2018-02-28 01:35:35 +00:00
}
} ,
} ,
)
return r
}
2019-08-06 20:17:36 +00:00
func ( r * restorer ) RestorePodVolumes ( data RestoreData ) [ ] error {
volumesToRestore := GetVolumeBackupsForPod ( data . PodVolumeBackups , data . Pod )
2018-02-28 01:35:35 +00:00
if len ( volumesToRestore ) == 0 {
return nil
}
2019-08-06 20:17:36 +00:00
repo , err := r . repoEnsurer . EnsureRepo ( r . ctx , data . Restore . Namespace , data . SourceNamespace , data . BackupLocation )
2018-06-15 03:24:01 +00:00
if err != nil {
return [ ] error { err }
}
2018-06-22 19:07:23 +00:00
// get a single non-exclusive lock since we'll wait for all individual
// restores to be complete before releasing it.
2018-09-25 20:20:58 +00:00
r . repoManager . repoLocker . Lock ( repo . Name )
defer r . repoManager . repoLocker . Unlock ( repo . Name )
2018-06-22 19:07:23 +00:00
2019-01-25 03:33:07 +00:00
resultsChan := make ( chan * velerov1api . PodVolumeRestore )
2018-02-28 01:35:35 +00:00
r . resultsLock . Lock ( )
2019-08-06 20:17:36 +00:00
r . results [ resultsKey ( data . Pod . Namespace , data . Pod . Name ) ] = resultsChan
2018-02-28 01:35:35 +00:00
r . resultsLock . Unlock ( )
var (
errs [ ] error
numRestores int
)
for volume , snapshot := range volumesToRestore {
2019-08-06 20:17:36 +00:00
volumeRestore := newPodVolumeRestore ( data . Restore , data . Pod , data . BackupLocation , volume , snapshot , repo . Spec . ResticIdentifier )
2018-02-28 01:35:35 +00:00
2019-01-25 03:33:07 +00:00
if err := errorOnly ( r . repoManager . veleroClient . VeleroV1 ( ) . PodVolumeRestores ( volumeRestore . Namespace ) . Create ( volumeRestore ) ) ; err != nil {
2018-02-28 01:35:35 +00:00
errs = append ( errs , errors . WithStack ( err ) )
continue
}
numRestores ++
}
ForEachVolume :
for i := 0 ; i < numRestores ; i ++ {
select {
case <- r . ctx . Done ( ) :
errs = append ( errs , errors . New ( "timed out waiting for all PodVolumeRestores to complete" ) )
break ForEachVolume
case res := <- resultsChan :
2019-01-25 03:33:07 +00:00
if res . Status . Phase == velerov1api . PodVolumeRestorePhaseFailed {
2018-02-28 01:35:35 +00:00
errs = append ( errs , errors . Errorf ( "pod volume restore failed: %s" , res . Status . Message ) )
}
}
}
r . resultsLock . Lock ( )
2019-08-06 20:17:36 +00:00
delete ( r . results , resultsKey ( data . Pod . Namespace , data . Pod . Name ) )
2018-02-28 01:35:35 +00:00
r . resultsLock . Unlock ( )
return errs
}
2019-08-06 20:17:36 +00:00
func newPodVolumeRestore ( restore * velerov1api . Restore , pod * corev1api . Pod , backupLocation , volume , snapshot , repoIdentifier string ) * velerov1api . PodVolumeRestore {
2019-01-25 03:33:07 +00:00
return & velerov1api . PodVolumeRestore {
2018-02-28 01:35:35 +00:00
ObjectMeta : metav1 . ObjectMeta {
Namespace : restore . Namespace ,
GenerateName : restore . Name + "-" ,
OwnerReferences : [ ] metav1 . OwnerReference {
{
2019-01-25 03:33:07 +00:00
APIVersion : velerov1api . SchemeGroupVersion . String ( ) ,
2018-02-28 01:35:35 +00:00
Kind : "Restore" ,
Name : restore . Name ,
UID : restore . UID ,
Controller : boolptr . True ( ) ,
} ,
} ,
Labels : map [ string ] string {
2019-04-23 23:58:59 +00:00
velerov1api . RestoreNameLabel : label . GetValidName ( restore . Name ) ,
2019-01-25 03:33:07 +00:00
velerov1api . RestoreUIDLabel : string ( restore . UID ) ,
velerov1api . PodUIDLabel : string ( pod . UID ) ,
2018-02-28 01:35:35 +00:00
} ,
} ,
2019-01-25 03:33:07 +00:00
Spec : velerov1api . PodVolumeRestoreSpec {
2018-02-28 01:35:35 +00:00
Pod : corev1api . ObjectReference {
Kind : "Pod" ,
Namespace : pod . Namespace ,
Name : pod . Name ,
UID : pod . UID ,
} ,
2018-09-25 21:46:29 +00:00
Volume : volume ,
SnapshotID : snapshot ,
BackupStorageLocation : backupLocation ,
RepoIdentifier : repoIdentifier ,
2018-02-28 01:35:35 +00:00
} ,
}
}