mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-02-03 10:32:09 +00:00
* Ensure PVs and PVCs remain bound when doing a restore (#3007) * Only remove the UID from a PV's claimRef The UID is the only part of a claimRef that might prevent it from being rebound correctly on a restore. The namespace and name within the claimRef should be preserved in order to ensure that the PV is claimed by the correct PVC on restore. Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Remap PVs claimRef.namespace on relevant restores When remapping namespaces, any included PVs need to have their claimRef updated to point remapped namespaces to the new namespace name in order to be bound to the correct PVC. Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Update tests and ensure claimRef namespace remaps Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Remove lowercased uid field from unstructured PV Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Fix issues that prevented PVs from being restored Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Add changelog Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Dynamically reprovision volumes without snapshots Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Update test for lower case uid field Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Remove stray debugging print statement Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Fix typo, remove extra code, add tests. Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * restore proper lowercase/plural CRD resource (#2949) * restore proper lowercase/plural CRD resource This commit restores the proper resource string "customresourcedefinitions" for CRD. The prior change to "CustomResourceDefinition" was made because this was being used in another place to populate the CRD "Kind" field in remap_crd_version_action.go -- there, just use the correct Kind string instead of pulling from Resource. Signed-off-by: Scott Seago <sseago@redhat.com> * add changelog Signed-off-by: Scott Seago <sseago@redhat.com> * create CRB with velero-<namespace> (#2886) * create CRB with velero-<namespace> This will allow creating multiple instances of velero, across two different namespaces Signed-off-by: Alay Patel <alay1431@gmail.com> * add changelog Signed-off-by: Alay Patel <alay1431@gmail.com> * add package var DefaultVeleroNamespace and use it wherever needed Signed-off-by: Alay Patel <alay1431@gmail.com> * Fix BSL controller to avoid invoking init() on all BSLs regardless of ValidationFrequency (#2992) Signed-off-by: Bett, Antony <antony.bett@dell.com> * Fix version cmd getting nil pointer (#2996) Signed-off-by: Carlisia <carlisia@vmware.com> * Changelogs for v1.5.2 Signed-off-by: Nolan Brubaker <brubakern@vmware.com> Co-authored-by: Scott Seago <sseago@redhat.com> Co-authored-by: Alay Patel <alay1431@gmail.com> Co-authored-by: Antony S Bett <antony.bett@dell.com> Co-authored-by: Carlisia Thompson <carlisia@vmware.com>
170 lines
6.6 KiB
Go
170 lines
6.6 KiB
Go
/*
|
|
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 controller
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"sigs.k8s.io/cluster-api/util/patch"
|
|
ctrl "sigs.k8s.io/controller-runtime"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
|
|
"github.com/vmware-tanzu/velero/internal/storage"
|
|
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
|
"github.com/vmware-tanzu/velero/pkg/persistence"
|
|
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt"
|
|
)
|
|
|
|
// BackupStorageLocationReconciler reconciles a BackupStorageLocation object
|
|
type BackupStorageLocationReconciler struct {
|
|
Ctx context.Context
|
|
Client client.Client
|
|
Scheme *runtime.Scheme
|
|
DefaultBackupLocationInfo storage.DefaultBackupLocationInfo
|
|
// use variables to refer to these functions so they can be
|
|
// replaced with fakes for testing.
|
|
NewPluginManager func(logrus.FieldLogger) clientmgmt.Manager
|
|
NewBackupStore func(*velerov1api.BackupStorageLocation, persistence.ObjectStoreGetter, logrus.FieldLogger) (persistence.BackupStore, error)
|
|
|
|
Log logrus.FieldLogger
|
|
}
|
|
|
|
// +kubebuilder:rbac:groups=velero.io,resources=backupstoragelocations,verbs=get;list;watch;create;update;patch;delete
|
|
// +kubebuilder:rbac:groups=velero.io,resources=backupstoragelocations/status,verbs=get;update;patch
|
|
func (r *BackupStorageLocationReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
|
log := r.Log.WithField("controller", "backupstoragelocation")
|
|
|
|
log.Info("Checking for existing backup locations ready to be verified; there needs to be at least 1 backup location available")
|
|
|
|
locationList, err := storage.ListBackupStorageLocations(r.Ctx, r.Client, req.Namespace)
|
|
if err != nil {
|
|
log.WithError(err).Error("No backup storage locations found, at least one is required")
|
|
return ctrl.Result{Requeue: true}, err
|
|
}
|
|
|
|
pluginManager := r.NewPluginManager(log)
|
|
defer pluginManager.CleanupClients()
|
|
|
|
var defaultFound bool
|
|
var unavailableErrors []string
|
|
var anyVerified bool
|
|
for i := range locationList.Items {
|
|
location := &locationList.Items[i]
|
|
log := r.Log.WithField("controller", "backupstoragelocation").WithField("backupstoragelocation", location.Name)
|
|
|
|
if location.Name == r.DefaultBackupLocationInfo.StorageLocation {
|
|
defaultFound = true
|
|
}
|
|
|
|
if !storage.IsReadyToValidate(location.Spec.ValidationFrequency, location.Status.LastValidationTime, r.DefaultBackupLocationInfo, log) {
|
|
log.Debug("Backup location not ready to be validated")
|
|
continue
|
|
}
|
|
|
|
backupStore, err := r.NewBackupStore(location, pluginManager, log)
|
|
if err != nil {
|
|
log.WithError(err).Error("Error getting a backup store")
|
|
continue
|
|
}
|
|
|
|
// Initialize the patch helper.
|
|
patchHelper, err := patch.NewHelper(location, r.Client)
|
|
if err != nil {
|
|
log.WithError(err).Error("Error getting a patch helper to update this resource")
|
|
continue
|
|
}
|
|
|
|
log.Debug("Verifying backup storage location")
|
|
anyVerified = true
|
|
if err := backupStore.IsValid(); err != nil {
|
|
log.Debug("Backup location verified, not valid")
|
|
unavailableErrors = append(unavailableErrors, errors.Wrapf(err, "Backup location %q is unavailable", location.Name).Error())
|
|
|
|
if location.Name == r.DefaultBackupLocationInfo.StorageLocation {
|
|
log.Warnf("The specified default backup location named %q is unavailable; for convenience, be sure to configure it properly or make another backup location that is available the default", r.DefaultBackupLocationInfo.StorageLocation)
|
|
}
|
|
|
|
location.Status.Phase = velerov1api.BackupStorageLocationPhaseUnavailable
|
|
} else {
|
|
log.Debug("Backup location verified and it is valid")
|
|
location.Status.Phase = velerov1api.BackupStorageLocationPhaseAvailable
|
|
}
|
|
location.Status.LastValidationTime = &metav1.Time{Time: time.Now().UTC()}
|
|
if err := patchHelper.Patch(r.Ctx, location); err != nil {
|
|
log.WithError(err).Error("Error updating backup location phase")
|
|
}
|
|
}
|
|
|
|
if !anyVerified {
|
|
log.Info("No backup locations were ready to be verified")
|
|
}
|
|
|
|
r.logReconciledPhase(defaultFound, locationList, unavailableErrors)
|
|
|
|
return ctrl.Result{Requeue: true}, nil
|
|
}
|
|
|
|
func (r *BackupStorageLocationReconciler) logReconciledPhase(defaultFound bool, locationList velerov1api.BackupStorageLocationList, errs []string) {
|
|
var availableBSLs []*velerov1api.BackupStorageLocation
|
|
var unAvailableBSLs []*velerov1api.BackupStorageLocation
|
|
var unknownBSLs []*velerov1api.BackupStorageLocation
|
|
log := r.Log.WithField("controller", "backupstoragelocation")
|
|
|
|
for i, location := range locationList.Items {
|
|
phase := location.Status.Phase
|
|
switch phase {
|
|
case velerov1api.BackupStorageLocationPhaseAvailable:
|
|
availableBSLs = append(availableBSLs, &locationList.Items[i])
|
|
case velerov1api.BackupStorageLocationPhaseUnavailable:
|
|
unAvailableBSLs = append(unAvailableBSLs, &locationList.Items[i])
|
|
default:
|
|
unknownBSLs = append(unknownBSLs, &locationList.Items[i])
|
|
}
|
|
}
|
|
|
|
numAvailable := len(availableBSLs)
|
|
numUnavailable := len(unAvailableBSLs)
|
|
numUnknown := len(unknownBSLs)
|
|
|
|
if numUnavailable+numUnknown == len(locationList.Items) { // no available BSL
|
|
if len(errs) > 0 {
|
|
log.Errorf("Current backup storage locations available/unavailable/unknown: %v/%v/%v, %s)", numAvailable, numUnavailable, numUnknown, strings.Join(errs, "; "))
|
|
} else {
|
|
log.Errorf("Current backup storage locations available/unavailable/unknown: %v/%v/%v)", numAvailable, numUnavailable, numUnknown)
|
|
}
|
|
} else if numUnavailable > 0 { // some but not all BSL unavailable
|
|
log.Warnf("Invalid backup locations detected: available/unavailable/unknown: %v/%v/%v, %s)", numAvailable, numUnavailable, numUnknown, strings.Join(errs, "; "))
|
|
}
|
|
|
|
if !defaultFound {
|
|
log.Warnf("The specified default backup location named %q was not found; for convenience, be sure to create one or make another backup location that is available the default", r.DefaultBackupLocationInfo.StorageLocation)
|
|
}
|
|
}
|
|
|
|
func (r *BackupStorageLocationReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
|
return ctrl.NewControllerManagedBy(mgr).
|
|
For(&velerov1api.BackupStorageLocation{}).
|
|
Complete(r)
|
|
}
|