Skip to content

bug(backups): RestoreJob targetApplicationRef rename is silently ignored for Velero-backed non-VM apps #3537

Closed

Description

@IvanHunters

Summary

A RestoreJob (backups.cozystack.io/v1alpha1) that requests a rename via
spec.targetApplicationRef.name into a different namespace reports
phase: Succeeded, but the application is restored under the original
name. The requested target name is silently ignored. This affects every
non-VM application backed by the Velero strategy (Postgres, MariaDB,
ClickHouse, MongoDB).

For the same-namespace case the rename is instead hard-rejected, so there is
no working path to restore such an application under a new name via the
Velero strategy.

Observed on backup-controller v1.6.0-rc.4; the same code is present on
main (internal/backupcontroller/velerostrategy_controller.go).

Steps to reproduce

  1. Use a BackupClass that maps Postgres to the Velero strategy.

  2. Create a BackupJob for a Postgres app src and let it complete.

  3. Apply a RestoreJob:

    apiVersion: backups.cozystack.io/v1alpha1
    kind: RestoreJob
    metadata:
      generateName: src-restore-
      namespace: <tenant-namespace>
    spec:
      backupRef:
        name: src-sb
      targetApplicationRef:
        apiGroup: apps.cozystack.io
        kind: Postgres
        name: dst
      options:
        targetNamespace: <other-namespace>

Expected

Either the application is restored as dst, or the RestoreJob fails with a
clear message stating that rename is not supported for this application kind
via the Velero strategy.

Actual

RestoreJob reports phase: Succeeded, but the restored application keeps
the original name src. targetApplicationRef.name has no effect.

For options.targetNamespace equal to the source namespace (or omitted) with
a different targetApplicationRef.name, the RestoreJob fails with:

restoring to the same namespace with a different application name is not
supported due to Velero DataUpload limitations: data is always uploaded to
PVCs with the original name. Use options.targetNamespace to restore into a
different namespace

Root cause

postRestoreRename (velerostrategy_controller.go:1014) is the only place
that applies the rename, and it hardcodes the VMInstance HelmRelease prefix:

sourceHRName := vmNamePrefix + sourceAppName // "vm-instance-src"
targetHRName := vmNamePrefix + target.AppName // "vm-instance-dst"
oldHR, err := hrClient.Get(ctx, sourceHRName, metav1.GetOptions{})
if errors.IsNotFound(err) {
    return nil // silent no-op
}

A Postgres application's HelmRelease is named after the app itself (no
vm-instance- prefix), so the Get returns NotFound, the function returns
nil, and the reconcile proceeds to mark the RestoreJob Succeeded
(velerostrategy_controller.go:719). The rename never happens and no error
is surfaced.

Why this cannot be fixed by just generalizing the HelmRelease name

The VM rename path relies on CDI claim adoption: renamePVC rebinds the
old PV, the DataVolume is deleted with Orphan propagation, and the restored
PVC carries cdi.kubevirt.io/allowClaimAdoption: true so the freshly
rendered DataVolume adopts the existing PVC.

CNPG has no equivalent adoption mechanism. A freshly reconciled
Cluster dst bootstraps a new empty database into new PVCs (dst-1, ...)
instead of adopting the restored volumes, which Velero DataUpload always
writes under the original name. Renaming the HelmRelease (and even the PVCs)
therefore yields an empty dst plus orphaned src volumes.

The correct way to restore a Postgres under a new name is engine-native
recovery (CNPG bootstrap.recovery into a new cluster), i.e. the CNPG
strategy, not the Velero strategy.

Proposed fix

Short term (correctness): make the rename path kind-aware and fail the
RestoreJob explicitly when a rename is requested for a Velero-backed
application kind that does not support it, mirroring the existing
same-namespace guard (velerostrategy_controller.go:604). A silent
Succeeded under the wrong name is worse than an explicit failure.

Longer term (feature): support rename-on-restore for non-VM apps through
engine-native recovery (e.g. CNPG bootstrap.recovery) rather than the
Velero DataUpload path.

Activity

  1. added
    kind/bugCategorizes issue or PR as related to a bug
    area/storageIssues or PRs related to storage (linstor, seaweedfs, bucket, velero, harbor)
    area/databaseIssues or PRs related to managed databases (postgres, mariadb, redis, etcd, kafka, clickhouse)
    triage/acceptedIndicates an issue is ready to be actively worked on
    priority/important-soonMust be staffed and worked on either currently, or very soon, ideally in time for the next release
    and removed
    triage/needs-triageIndicates an issue needs triage by a maintainer
    on Sep 23, 2026
  2. added 2 commits that reference this issue on Sep 24, 2026
    88073bb
    61a7a25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/databaseIssues or PRs related to managed databases (postgres, mariadb, redis, etcd, kafka, clickhouse)area/storageIssues or PRs related to storage (linstor, seaweedfs, bucket, velero, harbor)kind/bugCategorizes issue or PR as related to a bugpriority/important-soonMust be staffed and worked on either currently, or very soon, ideally in time for the next releasetriage/acceptedIndicates an issue is ready to be actively worked on

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions