feat: model a machine that fails to reach started (image-pull failure injection) (#61)#62
Merged
Merged
Conversation
…re injection) (#61) The lifecycle advancer only ever drove a machine to `started`; `StateFailed` was defined but never set, so a Machines-API client's deploy-failure path couldn't be tested. A machine whose `config.image` is the sentinel `mudflaps/unpullable` (bare, or with a `:tag`/`@digest`) now settles into `failed` instead of `started` on its next boot transition — modeling a boot-time image-pull failure ("unable to pull image, canceling deploy"). The boot transition (`settle`) reads the machine's latest config when it fires, so an update to a real image beforehand still boots. A client that polls `.../wait?state=started` sees a deploy that never comes up: the wait times out (`408`, never a false `started`) and `GET` shows `state: failed`. Everything stays deterministic on the injected clock. Real flaps has no such magic image; the sentinel is the single injection point. Tests cover the advancer failed-boot path, sentinel matching (tag/digest, nil config, non-matches), update-to-good-image recovery, and the server-level deploy-failure path (create → failed → wait 408). README + fidelity docs note the injection. Staged as 0.5.0.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #61.
What
mudflaps' advancer only ever drove a machine to
started(StateFailedwas defined but never set), so a Machines-API client's deploy-failure path was untestable. This adds a sentinel that makes a machine settle intofailedinstead ofstarted, modeling a boot-time image-pull failure — the shape of this Fly forum report.Mechanism (sentinel image)
A machine whose
config.imageismudflaps/unpullable(bare, or with a:tag/@digest) settles intofailedon its next boot transition — create, start, restart, or an update to that image. Chosen over a control endpoint because the failure rides in the config the client already sends, so no new wire surface.settle, which reads the machine's latest config when it fires — so an update back to a real image before the transition still boots (recovery)..../wait?state=startednever falsely reportsstarted; it times out (408).GET .../machines/{id}reportsstate: failed, and the version history tracks it.Real flaps has no such magic image — mudflaps models the Machines-API state layer, not an image registry, so this is the single injection point that lets an applier (e.g. chant's
flyApply, which polls.../waitforstarted) exercise its failure/cancel/rollback path offline.Scope note
The failure reason as a machine event (issue #61 acceptance item 3, marked "if modeled") is intentionally deferred: mudflaps models no events today, and adding an
eventsarray means committing tofly-go'sMachineEventwire shape, which deserves its own change rather than a best-guess here.state: failed+ the sentinel is a faithful, verifiable failure; the reason-event can layer on later without changing this.Tests
failedfor an unpullable image (step-by-step); sentinel matching across bare/:tag/@digest, non-matches, and nil config; update-to-good-image recovery.failed,GETobserves it,wait?state=started→408(goroutine + clock-advance, mirroring the existing wait-timeout test).go build/go vet/gofmt/golangci-lint(0 issues) /go test -raceall clean.Docs
README feature bullet + a "Deploy-failure injection" section in
docs/fidelity.md(state diagram gainsstarting --> failed,failedadded to the resting-states list). CHANGELOG staged as 0.5.0 (new behavior → minor, pre-1.0).Acceptance
faileddeterministically (sentinel image), on the injected clock.wait?state=startedagainst such a machine does not falsely reportstarted.