diff --git a/pkg/apis/velero/v1/restore.go b/pkg/apis/velero/v1/restore.go index aab5b35c9..6dfb0a959 100644 --- a/pkg/apis/velero/v1/restore.go +++ b/pkg/apis/velero/v1/restore.go @@ -86,6 +86,12 @@ type RestoreSpec struct { // +nullable RestorePVs *bool `json:"restorePVs,omitempty"` + // RestoreStatus specifies which resources we should restore the status + // field. If nil, no objects are included. Optional. + // +optional + // +nullable + RestoreStatus *RestoreStatusSpec + // PreserveNodePorts specifies whether to restore old nodePorts from backup. // +optional // +nullable @@ -113,6 +119,19 @@ type RestoreHooks struct { Resources []RestoreResourceHookSpec `json:"resources,omitempty"` } +type RestoreStatusSpec struct { + // IncludedResources specifies the resources to which will restore the status. + // If empty, it applies to all resources. + // +optional + // +nullable + IncludedResources []string `json:"includedResources,omitempty"` + + // ExcludedResources specifies the resources to which will not restore the status. + // +optional + // +nullable + ExcludedResources []string `json:"excludedResources,omitempty"` +} + // RestoreResourceHookSpec defines one or more RestoreResrouceHooks that should be executed based on // the rules defined for namespaces, resources, and label selector. type RestoreResourceHookSpec struct { diff --git a/pkg/restore/restore.go b/pkg/restore/restore.go index cbb335f27..3761477be 100644 --- a/pkg/restore/restore.go +++ b/pkg/restore/restore.go @@ -206,6 +206,20 @@ func (kr *kubernetesRestorer) RestoreWithResolvers( req.Restore.Spec.ExcludedResources, ) + // Get resource status includes-excludes. Defaults to excluding all resources + restoreStatusIncludesExcludes := collections.GetResourceIncludesExcludes( + kr.discoveryHelper, + []string{}, + []string{"*"}, + ) + if req.Restore.Spec.RestoreStatus != nil { + restoreStatusIncludesExcludes = collections.GetResourceIncludesExcludes( + kr.discoveryHelper, + req.Restore.Spec.RestoreStatus.IncludedResources, + req.Restore.Spec.RestoreStatus.ExcludedResources, + ) + } + // Get namespace includes-excludes. namespaceIncludesExcludes := collections.NewIncludesExcludes(). Includes(req.Restore.Spec.IncludedNamespaces...). @@ -268,83 +282,85 @@ func (kr *kubernetesRestorer) RestoreWithResolvers( } restoreCtx := &restoreContext{ - backup: req.Backup, - backupReader: req.BackupReader, - restore: req.Restore, - resourceIncludesExcludes: resourceIncludesExcludes, - namespaceIncludesExcludes: namespaceIncludesExcludes, - chosenGrpVersToRestore: make(map[string]ChosenGroupVersion), - selector: selector, - OrSelectors: OrSelectors, - log: req.Log, - dynamicFactory: kr.dynamicFactory, - fileSystem: kr.fileSystem, - namespaceClient: kr.namespaceClient, - restoreItemActions: resolvedActions, - itemSnapshotterActions: resolvedItemSnapshotterActions, - volumeSnapshotterGetter: volumeSnapshotterGetter, - resticRestorer: resticRestorer, - resticErrs: make(chan error), - pvsToProvision: sets.NewString(), - pvRestorer: pvRestorer, - volumeSnapshots: req.VolumeSnapshots, - podVolumeBackups: req.PodVolumeBackups, - resourceTerminatingTimeout: kr.resourceTerminatingTimeout, - resourceClients: make(map[resourceClientKey]client.Dynamic), - restoredItems: make(map[velero.ResourceIdentifier]struct{}), - renamedPVs: make(map[string]string), - pvRenamer: kr.pvRenamer, - discoveryHelper: kr.discoveryHelper, - resourcePriorities: kr.resourcePriorities, - resourceRestoreHooks: resourceRestoreHooks, - hooksErrs: make(chan error), - waitExecHookHandler: waitExecHookHandler, - hooksContext: hooksCtx, - hooksCancelFunc: hooksCancelFunc, - restoreClient: kr.restoreClient, + backup: req.Backup, + backupReader: req.BackupReader, + restore: req.Restore, + resourceIncludesExcludes: resourceIncludesExcludes, + resourceStatusIncludesExcludes: restoreStatusIncludesExcludes, + namespaceIncludesExcludes: namespaceIncludesExcludes, + chosenGrpVersToRestore: make(map[string]ChosenGroupVersion), + selector: selector, + OrSelectors: OrSelectors, + log: req.Log, + dynamicFactory: kr.dynamicFactory, + fileSystem: kr.fileSystem, + namespaceClient: kr.namespaceClient, + restoreItemActions: resolvedActions, + itemSnapshotterActions: resolvedItemSnapshotterActions, + volumeSnapshotterGetter: volumeSnapshotterGetter, + resticRestorer: resticRestorer, + resticErrs: make(chan error), + pvsToProvision: sets.NewString(), + pvRestorer: pvRestorer, + volumeSnapshots: req.VolumeSnapshots, + podVolumeBackups: req.PodVolumeBackups, + resourceTerminatingTimeout: kr.resourceTerminatingTimeout, + resourceClients: make(map[resourceClientKey]client.Dynamic), + restoredItems: make(map[velero.ResourceIdentifier]struct{}), + renamedPVs: make(map[string]string), + pvRenamer: kr.pvRenamer, + discoveryHelper: kr.discoveryHelper, + resourcePriorities: kr.resourcePriorities, + resourceRestoreHooks: resourceRestoreHooks, + hooksErrs: make(chan error), + waitExecHookHandler: waitExecHookHandler, + hooksContext: hooksCtx, + hooksCancelFunc: hooksCancelFunc, + restoreClient: kr.restoreClient, } return restoreCtx.execute() } type restoreContext struct { - backup *velerov1api.Backup - backupReader io.Reader - restore *velerov1api.Restore - restoreDir string - restoreClient velerov1client.RestoresGetter - resourceIncludesExcludes *collections.IncludesExcludes - namespaceIncludesExcludes *collections.IncludesExcludes - chosenGrpVersToRestore map[string]ChosenGroupVersion - selector labels.Selector - OrSelectors []labels.Selector - log logrus.FieldLogger - dynamicFactory client.DynamicFactory - fileSystem filesystem.Interface - namespaceClient corev1.NamespaceInterface - restoreItemActions []framework.RestoreItemResolvedAction - itemSnapshotterActions []framework.ItemSnapshotterResolvedAction - volumeSnapshotterGetter VolumeSnapshotterGetter - resticRestorer restic.Restorer - resticWaitGroup sync.WaitGroup - resticErrs chan error - pvsToProvision sets.String - pvRestorer PVRestorer - volumeSnapshots []*volume.Snapshot - podVolumeBackups []*velerov1api.PodVolumeBackup - resourceTerminatingTimeout time.Duration - resourceClients map[resourceClientKey]client.Dynamic - restoredItems map[velero.ResourceIdentifier]struct{} - renamedPVs map[string]string - pvRenamer func(string) (string, error) - discoveryHelper discovery.Helper - resourcePriorities []string - hooksWaitGroup sync.WaitGroup - hooksErrs chan error - resourceRestoreHooks []hook.ResourceRestoreHook - waitExecHookHandler hook.WaitExecHookHandler - hooksContext go_context.Context - hooksCancelFunc go_context.CancelFunc + backup *velerov1api.Backup + backupReader io.Reader + restore *velerov1api.Restore + restoreDir string + restoreClient velerov1client.RestoresGetter + resourceIncludesExcludes *collections.IncludesExcludes + resourceStatusIncludesExcludes *collections.IncludesExcludes + namespaceIncludesExcludes *collections.IncludesExcludes + chosenGrpVersToRestore map[string]ChosenGroupVersion + selector labels.Selector + OrSelectors []labels.Selector + log logrus.FieldLogger + dynamicFactory client.DynamicFactory + fileSystem filesystem.Interface + namespaceClient corev1.NamespaceInterface + restoreItemActions []framework.RestoreItemResolvedAction + itemSnapshotterActions []framework.ItemSnapshotterResolvedAction + volumeSnapshotterGetter VolumeSnapshotterGetter + resticRestorer restic.Restorer + resticWaitGroup sync.WaitGroup + resticErrs chan error + pvsToProvision sets.String + pvRestorer PVRestorer + volumeSnapshots []*volume.Snapshot + podVolumeBackups []*velerov1api.PodVolumeBackup + resourceTerminatingTimeout time.Duration + resourceClients map[resourceClientKey]client.Dynamic + restoredItems map[velero.ResourceIdentifier]struct{} + renamedPVs map[string]string + pvRenamer func(string) (string, error) + discoveryHelper discovery.Helper + resourcePriorities []string + hooksWaitGroup sync.WaitGroup + hooksErrs chan error + resourceRestoreHooks []hook.ResourceRestoreHook + waitExecHookHandler hook.WaitExecHookHandler + hooksContext go_context.Context + hooksCancelFunc go_context.CancelFunc } type resourceClientKey struct { @@ -1356,6 +1372,16 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso return warnings, errs } + // if it should restore status, run a UpdateStatus + if ctx.resourceStatusIncludesExcludes.ShouldInclude(groupResource.String()) { + updated, err := resourceClient.UpdateStatus(obj, metav1.UpdateOptions{}) + if err != nil { + warnings.Add(namespace, err) + } else { + createdObj = updated + } + } + if groupResource == kuberesource.Pods { pod := new(v1.Pod) if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), pod); err != nil {