Repository navigation
Description
Problem / motivation
RestoreJob.spec.options is a single shared, driver-opaque runtime.RawExtension (api/backups/v1alpha1/restorejob_types.go), and each strategy driver in internal/backupcontroller/ decodes it into its own typed struct. The CRD contract is uniform, but the behavior of the default drivers around that field is not — which is confusing and unpredictable for tenants who expect the same field to behave the same way regardless of the database.
Current state on main:
| Driver | Options it reads | Malformed spec.options |
|---|---|---|
| CNPG (Postgres) | recoveryTime, restoreTimeoutSeconds, walArchiveTimeoutSeconds |
permissive — log event + fall back to defaults (parseCNPGRestoreOptions, cnpgstrategy_controller.go:718) |
| MariaDB | restoreTimeoutSeconds |
permissive — log event + defaults (mariadbstrategy_controller.go:501) |
| etcd | restoreTimeoutSeconds |
strict — terminal Failed (etcdstrategy_controller.go:662) |
| FoundationDB | restoreTimeoutSeconds |
strict — terminal Failed (foundationdbstrategy_controller.go:860) |
| Altinity (ClickHouse) | none — spec.options is never read |
option is silently ignored entirely |
Two concrete predictability problems fall out of this:
-
Malformed-options handling is inconsistent. The same bad JSON in
spec.optionsfails the restore on etcd/FoundationDB but is silently swallowed (restore proceeds with defaults) on CNPG/MariaDB. A tenant cannot predict whether a typo aborts or is ignored. -
Unsupported options are silently dropped. Altinity does not read
spec.optionsat all, so a tenant who setsrestoreTimeoutSeconds(supported everywhere else) orrecoveryTime(expecting PITR) on a ClickHouseRestoreJobgets a silent no-op — no error, no event, no condition. The restore just quietly ignores their intent. The commonrestoreTimeoutSecondsknob is honored by 4 of 5 default drivers but not ClickHouse.
Proposed solution
Give the default drivers one uniform, predictable contract for spec.options:
-
One shared malformed-options policy. Pick a single behavior for all default drivers and apply it via a shared helper. Recommendation: fail fast — a malformed
spec.optionsbecomes a terminalFailedwith a clear message + Warning event (the etcd/FDB behavior), because silently restoring with defaults after ignoring a tenant's explicit override is the more surprising outcome. (If permissive is preferred instead, make it uniform — the point is one policy, not two.) -
A shared
CommonRestoreOptionshonored by every driver. The Velero driver already models this pattern (velerostrategy_controller.go:92). Extract a common struct (at minimumrestoreTimeoutSeconds) embedded by every strategy so the common knobs are defined and parsed once and work identically on ClickHouse too. -
Surface unsupported/ignored options instead of dropping them. When a tenant sets an option a given driver does not implement (e.g.
recoveryTime/ PITR on ClickHouse or MariaDB, which have no point-in-time recovery), emit a Warning event / set a condition —"recoveryTime (PITR) is not supported for ClickHouse and was ignored"— rather than silently no-op'ing. Predictable > silent.
Net effect: same field, same validation, same failure mode across all default drivers; capability differences (e.g. only CNPG supports PITR) are reported explicitly instead of discovered by surprise.
Scope check
- This affects a single component / package (
internal/backupcontroller/+ the sharedapi/backups/v1alpha1options contract) - I can describe the expected behavior concretely
Alternatives considered
- Leave as-is / document the differences. Rejected: the whole selling point of the shared
backups.cozystack.ioCRD is a uniform API; per-driver quirks in the same field undercut that and surface as tenant support tickets. - Per-driver typed option subschemas on the CRD instead of one opaque blob. Heavier change to the API surface and arguably a design-proposal; this issue keeps the opaque-blob model and only unifies how drivers parse/validate/report it.
Additional context
- Shared spec:
api/backups/v1alpha1/restorejob_types.go(RestoreJobSpec.Options *runtime.RawExtension,+kubebuilder:pruning:PreserveUnknownFields). - Option structs:
CNPGRestoreOptions(cnpgstrategy_controller.go:1721),MariaDBRestoreOptions(mariadbstrategy_controller.go:849),EtcdRestoreOptions(etcdstrategy_controller.go:1406),FoundationDBRestoreOptions(foundationdbstrategy_controller.go:1240), VeleroCommonRestoreOptions/RestoreOptions(velerostrategy_controller.go:92). - Altinity driver (
altinitystrategy_controller.go) contains no reference torestoreJob.Spec.Options.
Activity