design/Implemented/resource-status-restore.md
This design proposes a way to enhance Velero’s restore functionality by enabling object-level resource status restoration through annotations. Currently, Velero allows restoring resource statuses only at a resource type level, which lacks granularity of restoring the status of specific resources. By introducing an annotation that controllers can set on individual resource objects, this design aims to improve flexibility and autonomy for users/resource-controllers, providing a more way to enable resource status restore.
Velero provides the restoreStatus field in the Restore API to specify resource types for status restoration. However, this feature is limited to resource types as a whole, lacking the granularity needed to restore specific objects of a resource type. Resource controllers, especially those managing custom resources with external dependencies, may need to restore status on a per-object basis based on internal logic and dependencies.
This design adds an annotation-based approach to allow controllers to specify status restoration at the object level, enabling Velero to handle status restores more flexibly.
restoreStatus configuration.velero.io/restore-status: true annotation on the resource.restoreStatus.includedResourcesrestoreStatus.includedResourcesrestoreStatus.includedResources field within the Restore custom resource.velero.io/restore-status: false by the user.restoreStatus.includedResources because annotation is false and it takes precedence.velero.io/restore-status annotation behave as they currently do: Velero skips their status restoration unless the resource type is specified in the restoreStatus.includedResources field.Object-Level Status Restore Annotation: We are introducing the velero.io/restore-status annotation at the resource object level to mark specific objects for status restoration.
true: Indicates that the status should be restored for this objectfalse: Skip restoring status for this specific objectRestore logic precedence:
true or false).restoreStatus.includedResources is only used when annotations are invalid or missing.Velero Restore Logic Update: During a restore operation, Velero will:
velero.io/restore-status annotation will be set on individual resource objects by users/controllers as needed:metadata:
annotations:
velero.io/restore-status: "true"
restoreStatus.includedResources spec to determine resource types eligible for status restoration.velero.io/restore-status annotation.true: Restore the status of the objectfalse: Skip restoring the status of the objectrestoreStatus.includedResources configurationWe are targeting the implementation of this design for Velero 1.16 release.
Current restoreStatus logic resides here: https://github.com/vmware-tanzu/velero/blob/32a8c62920ad96c70f1465252c0197b83d5fa6b6/pkg/restore/restore.go#L1652
The modified logic would look somewhat like:
// Determine whether to restore status from resource type configuration
shouldRestoreStatus := ctx.resourceStatusIncludesExcludes != nil && ctx.resourceStatusIncludesExcludes.ShouldInclude(groupResource.String())
// Check for object-level annotation
annotations := obj.GetAnnotations()
objectAnnotation := annotations["velero.io/restore-status"]
annotationValid := objectAnnotation == "true" || objectAnnotation == "false"
// Determine restore behavior based on annotation precedence
shouldRestoreStatus = (annotationValid && objectAnnotation == "true") || (!annotationValid && shouldRestoreStatus)
ctx.log.Debugf("status field for %s: exists: %v, should restore: %v (by annotation: %v)", newGR, statusFieldExists, shouldRestoreStatus, annotationValid)
if shouldRestoreStatus && statusFieldExists {
if err := unstructured.SetNestedField(obj.Object, objStatus, "status"); err != nil {
ctx.log.Errorf("Could not set status field %s: %v", kube.NamespaceAndName(obj), err)
errs.Add(namespace, err)
return warnings, errs, itemExists
}
obj.SetResourceVersion(createdObj.GetResourceVersion())
updated, err := resourceClient.UpdateStatus(obj, metav1.UpdateOptions{})
if err != nil {
ctx.log.Infof("Status field update failed %s: %v", kube.NamespaceAndName(obj), err)
warnings.Add(namespace, err)
} else {
createdObj = updated
}
}