Skip signing a download URL when no artifacts can exist yet - #10252
Skip signing a download URL when no artifacts can exist yet#10252Ralthos wants to merge 4 commits into
Conversation
👷 Deploy request for velero pending review.Visit the deploys page to approve it
|
5127854 to
9f9499f
Compare
|
Both good catches. Thank you. The coverage test. You are right, and it was worse than you describe: the assertion compares a slice I wrote by hand against its own length, so it could never fail for any reason. It has been replaced with one that reads the The abandoned request. The symptom is real and I had understated it. The CLI polls until its own timeout and then reports: For this case that message points at the wrong thing entirely. The BSL is fine; the backup never ran. So the change swaps a fast wrong answer for a slow wrong answer, which is not obviously an improvement for anyone driving it from the CLI. Setting a terminal phase is the right shape. The obstacle is that there is no phase to set: // +kubebuilder:validation:Enum=New;Processed
type DownloadRequestPhase stringAdding @kaovilai, three options as I see them:
I did not want to pick between those on your behalf. Happy to write whichever you prefer. |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Adding enum imo is non breaking. removing enum is breaking. WTAL at the approaches later and give more thoughts later. |
02e84fc to
9c03d00
Compare
|
@kaovilai thanks, that settles it. I have taken option 1.
The reason option 2 is not enough is worth recording. Setting @Ayush4958's point about the CLI is handled in the same commit rather than deferred. Checking the phase in the CLI before creating the request would work too, and I did consider it. I did not do that because it puts the rule in one caller: Two behaviour tests cover this, asserting on the phase and the exact message a client would read. I checked they fail when the message assignment is removed, since the last version of this test could not fail at all. CRD regenerated, |
f575a7f to
930dce3
Compare
930dce3 to
63a53ec
Compare
|
rerunning tests.. github was kinda down today |
Reported in velero-io#10232: a DownloadRequest for a backup that never ran still reaches Processed with a signed URL, and fetching it returns 404. The controller already has the backup, and the restore for restore targets, in hand before it signs, so checking the phase costs no extra call to the object store. The check is deliberately narrow. It refuses only the pre-execution phases, where nothing has been written for any target kind: New, Queued, ReadyToStart and FailedValidation for backups, New and FailedValidation for restores. InProgress onwards may hold a partial log or other artifacts, and Deleting may still hold all of them, so those keep the behaviour callers have today. That matters because velero backup download has no client side phase check of its own, unlike backup logs and restore logs. Reusing the allowlist from pkg/cmd/cli/backup/logs.go would have changed what backup download can fetch; this does not. A backup with an empty phase is left alone as well, since that state is transient and the caller can retry. Refs velero-io#10232 Signed-off-by: saral <ilovegojo2580@gmail.com>
The previous test built a slice of phases by hand and asserted its own length, so it passed no matter what the API did. Adding a fourteenth backup phase would not have failed it. This reads the status.phase enum out of the generated CRDs, via the exported v1crds.CRDs that pkg/install already uses. The enum comes from the same kubebuilder markers as the Go constants, so a phase added to the API fails here until it is classified. Verified by removing Deleting from the expectations, which now fails with 'BackupPhase "Deleting" is served by the CRD but not classified'. Signed-off-by: saral <ilovegojo2580@gmail.com>
golangci-lint runs misspell, which flags behaviour as a misspelling of behavior. Comments only, no functional change. Signed-off-by: saral <ilovegojo2580@gmail.com>
The guard added in the previous commit left the request at New with no URL, so the CLI polled until its own timeout and then reported that the backup storage location may be unavailable. The BSL is fine; the backup never ran. DownloadRequestPhase gains Failed and DownloadRequestStatus gains Message. The controller sets both where it refuses, and the CLI stops as soon as it sees the phase and surfaces the message instead of its generic timeout error. Adding an enum value is additive, per the direction on the PR discussion. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: saral <ilovegojo2580@gmail.com>
63a53ec to
b79df65
Compare
Ayush4958
left a comment
There was a problem hiding this comment.
CLI polling now aborts correctly on the Failed phase
Hardcoded test array replaced with dynamic CRD OpenAPI schema parsing
LGTM
Thank you for contributing to Velero!
Please add a summary of your change
Follows #10232, where the answer was "let's do free first". This is the free half: the controller already has the backup, and the restore for restore targets, in hand before it signs, so checking the phase adds no call to the object store.
A
DownloadRequestwhose target never ran now stops atNewwith no URL, so nothing hands a caller a link that 404s.Does your change fix a particular issue?
Refs #10232.
Please indicate you've done the following:
Three things worth flagging. Two of them are decisions, not mechanics.
The guard is narrower than the CLI's allowlist, on purpose.
pkg/cmd/cli/backup/logs.gopermits five phases and refuses the rest, and reusing that list in the controller was my first instinct. It would have been wrong.velero backup downloadhas no client side phase check at all, so a controller side guard built on the log allowlist would have changed whatbackup downloadcan fetch, and the phases in which a tarball is available are not the phases in which a log is.So this refuses only the pre-execution phases, where nothing exists for any target kind:
New,Queued,ReadyToStart,FailedValidationNew,FailedValidationInProgressonwards may hold a partial log or other artifacts, andDeletingmay still hold all of them, so those sign exactly as they do today. The only requests that change behaviour are ones that could never have succeeded.An empty phase is left alone. A backup that has not been reconciled yet has
phase: "", and that state is transient, so blocking it would trade a 404 for a spurious refusal during a race.Where the check lives. In the controller, next to where the backup and restore are already loaded.
GetDownloadURLinpkg/persistencehas the target kind but not the object, so putting it there would mean fetching the backup a second time and would stop being free.On testing:
backupPhaseHasNoArtifactsandrestorePhaseHasNoArtifactsare covered exhaustively, one case per phase the API defines, plus a guard test that fails if a phase is added later without updating either table.I could not run the
TestAPIsenvtest suite locally, since it needs control plane binaries I do not have on this machine. It fails the same way on a clean checkout ofmainhere, so I do not believe this change affects it, but CI is the real check.go test ./pkg/controller/ -run 'TestBackupPhaseHasNoArtifacts|TestRestorePhaseHasNoArtifacts|TestPhaseTablesCoverAllPhases'passes, 26 subtestsgofmt -sclean