alloc

package
v0.10.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 11, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package alloc is billet's global capacity allocator.

Every runner is preceded by a LEASE, and a lease exists from the moment capacity is escrowed — before a listener advertises it to GitHub — not from the moment a VM boots. That ordering is the design: each tier is its own scale set with its own advertised maxCapacity, so listeners computing their own would let GitHub fill all of them at once, and reserving on assignment is already too late.

Capacity is a VECTOR — vCPU, memory, per-tier concurrency, per-node macOS licence slots — never a single integer.

Index

Constants

View Source
const (
	// LaunchFailedReason marks a launch that failed after possibly starting
	// something, whose compute is being removed without ever having run a job.
	LaunchFailedReason = "billet:launch-failed"
	// HeldPastLimitReason marks a job an operator's custody bound destroyed.
	HeldPastLimitReason = "billet:held-past-limit"
	// RunnerRetiredReason marks adopted compute whose runner registration was
	// found idle or absent and removed, so it can never run a job.
	RunnerRetiredReason = "billet:runner-retired"
	// ForceReleasedReason marks a lease an operator released with --force, on
	// their own assertion that its compute was gone.
	ForceReleasedReason = "billet:force-released"
)

Failure reasons billet writes for ITSELF, as opposed to the free-form text an external party's warning carries.

A TEARDOWN'S OUTCOME HAS TO SURVIVE THE PROCESS THAT DECIDED IT. A node holds the outcome of a teardown in memory — a launch that failed ambiguously is a job that never ran — while the ledger records only the phase, and the same phase serves a completed job's teardown. A restart adopting that lease would reconstruct `done` for a runner that never started. So the node records why the lease will fail BEFORE it first reports the hold, through the same route an external reason takes, and adoption reads it back.

THE EXACT VALUE IS WHAT MarkFailure KEYS ON, never the prefix. The reason arrives over the wire from a node, so a rule keyed on a prefix anybody can type would let a caller suppress the disruption token an external reclaim must carry; and the reasons below do not all mean the same thing. A launch that never ran and a runner found idle are billet's own conclusions about compute no job was on, so no token is written beside them (`reclaimed` would attribute a failed build to an interruption that never happened). A job destroyed under an operator's custody bound WAS running, and billet ended it, which is a disruption in every sense the attribution report records.

View Source
const (
	EnrollPending  = "pending"
	EnrollApproved = "approved"
	EnrollDenied   = "denied"
)

Enrollment states.

View Source
const (
	PoolRunnerIdle     = "idle"
	PoolRunnerBusy     = "busy"
	PoolRunnerRetiring = "retiring"
	PoolRunnerRetired  = "retired"
)
View Source
const (
	CertEnrolled = "enrolled"
	CertIssued   = "issued"
	CertRenewed  = "renewed"
)

Sources a certificate can come from.

View Source
const BarrierWireVersion = 14

BarrierWireVersion is the oldest wire that can answer an inventory command.

HELD HERE RATHER THAN IMPORTED, because internal/nodeapi imports this package and the dependency cannot go both ways. nodeapi's own constant is the authority; a test there pins the two together so they cannot drift.

View Source
const DefaultLeaseTTL = 90 * time.Second

DefaultLeaseTTL is deliberately generous relative to the heartbeat interval. Reclaiming a lease whose holder is merely slow is worse than holding capacity a little longer: it hands a live job's slot to someone else.

Variables

View Source
var (
	// ErrNoCapacity means the request would exceed a limit. It is an ordinary
	// outcome — the listener advertises less — not a failure.
	ErrNoCapacity = errors.New("alloc: no capacity available")
	// ErrLeaseNotFound means the lease does not exist, or is already terminal.
	ErrLeaseNotFound = errors.New("alloc: lease not found")
	// ErrFenced means the caller's epoch is stale: this lease was reclaimed and
	// handed to someone else. The caller must stop writing entirely.
	ErrFenced = errors.New("alloc: lease was reclaimed by another holder")
	// ErrBadTransition means the requested phase change is not in the state
	// machine.
	ErrBadTransition = errors.New("alloc: invalid phase transition")
	// ErrUnknownTier means the tier is not in the configured catalog.
	ErrUnknownTier = errors.New("alloc: unknown tier")
	// ErrWrongNode means a bind would place a lease on a node other than the one
	// it is pinned to, or rebind one that is already placed.
	ErrWrongNode = errors.New("alloc: lease cannot be bound to that node")
	// ErrConflict means a retry contradicts what was already recorded — the same
	// lease assigned to a different job, or released with a different outcome.
	ErrConflict = errors.New("alloc: retry contradicts the recorded operation")
	// ErrGuestOSNotAllowed means the host does not permit the lease's guest OS.
	// Distinct from ErrWrongNode: the lease is not pinned anywhere, the chosen
	// host simply may not run that kind of guest.
	ErrGuestOSNotAllowed = errors.New("alloc: node does not permit that guest OS")
	// ErrWrongProvider means the node runs a different compute backend than the
	// lease requires — a Firecracker lease cannot run on a Tart host.
	ErrWrongProvider = errors.New("alloc: node runs a different provider")
	// ErrWrongSite means a host reported a different location while it still has
	// work bound to it there. Distinct from ErrWrongProvider because the fix is
	// different: one is a backend change, the other is a machine that moved.
	ErrWrongSite = errors.New("alloc: node reports a different site")
	// ErrNotPlaced means a lease reached a phase that presumes a host without
	// ever being bound to one.
	ErrNotPlaced = errors.New("alloc: lease has no bound node")
	// ErrNotPlaceable means a lease carries too little recorded placement
	// information to verify a host is legal for it — a row predating the
	// columns the checks read. It fails closed rather than skipping the checks.
	ErrNotPlaceable = errors.New("alloc: lease cannot be placed safely")
	// ErrForceRelease means an operator asserted that custody's compute is gone.
	// The node must drop its local proof obligation and terminalize the lease.
	ErrForceRelease = errors.New("alloc: operator requested forced release")
	// ErrFleetHeld means a remote fleet's shared capacity is already claimed — by
	// another host, or by this host's own outstanding work under a different fleet.
	//
	// A SENTINEL RATHER THAN PROSE because the node acts on it: a registration
	// refused this way must not be retried into a loop, since nothing on the refused
	// machine can resolve it — the fix is an operator giving that node its own fleet,
	// moving it to on-demand compute, or decommissioning the host that holds the
	// claim, which proves no compute remains there first.
	//
	// IT IS NOT ABOUT LIVENESS, and the first version's message said it was. A node
	// being unreachable says nothing about whether its builds are still drawing on
	// the fleet — `ForgetEveryNode` marks every host not-live whenever a control
	// plane starts — so a claim that lapsed with liveness would let a differently
	// named node advertise a fleet's whole capacity on top of live work.
	ErrFleetHeld = errors.New("alloc: that fleet's shared capacity is already claimed")
)
View Source
var ErrAdmissionSealed = errors.New("alloc: this deployment is not accepting new work")

ErrAdmissionSealed means the deployment is not accepting new work.

A DISTINCT ERROR, not ErrNoCapacity, because they mean opposite things to a caller: no capacity is a transient fact about a full fleet that the next poll may find changed, while a seal is a decision somebody made and only somebody can undo. A listener that logged "no capacity" while an operator was draining would send them looking at their hardware.

View Source
var ErrBadJoinToken = errors.New("alloc: that join token is not usable")

ErrBadJoinToken means the token is unknown, spent, or past its life.

ONE ERROR FOR ALL THREE, deliberately. Telling a caller which of them applies tells somebody guessing tokens whether they guessed a real one, which is the only feedback that makes guessing worth doing.

View Source
var ErrEnrollmentConflict = errors.New("alloc: another key has already requested this node name")

ErrEnrollmentConflict means a different key already claimed this node name.

A NAME IS CLAIMED BY THE FIRST KEY TO ASK, and a second one is refused rather than overwriting it. The alternative loses the property approval exists for: an operator who compared a fingerprint yesterday would be approving a different machine today, under a name they already trust.

View Source
var ErrForceHeld = errors.New("alloc: a node has taken custody of this lease")

ErrForceHeld means a forced lease has acquired a live holder, so its capacity is not this caller's to return.

A DESTROY THAT ENDED IN CUSTODY IS NOT A DESTROY THAT FINISHED. The node asked its backend to stop the guest and did not get proof it stopped, so it is holding the lease until the compute is provably gone — and terminalising it here would free a slot whose container may still be on the host, which is the overcommit the whole ordering exists to prevent. `billet leases release --force` is the operation for that case, because it goes THROUGH the holder rather than underneath it.

View Source
var ErrNotDecommissionable = errors.New("alloc: this host cannot be decommissioned yet")

ErrNotDecommissionable means a host may not be removed from the fleet's expected set yet, and the message says what would make it removable.

View Source
var ErrParentRevoked = errors.New("alloc: the certificate being renewed has been revoked")

ErrParentRevoked means a renewal was signed by a certificate that has since been taken back.

View Source
var ErrRemoteCostUnavailable = errors.New("remote compute cost report unavailable")

ErrRemoteCostUnavailable means legacy registration data cannot support a fleet cost bound. Capacity and lease status remain valid.

View Source
var ErrWithdrawalStale = errors.New(
	"alloc: that withdrawal names a registration this ledger does not hold")

ErrWithdrawalStale means a withdrawal named a registration this ledger does not hold: the host has registered again since, a different process holds its name, or it was never registered at all. Nothing was changed.

Functions

This section is empty.

Types

type ActionsCache added in v0.8.0

type ActionsCache string

ActionsCache is what the Actions cache interception did for the FIRST CacheService call of a job whose disposition was recorded, as the node saw it.

RECORDED WHEN THE DISPOSITION IS FINAL, not when it is intended: a call the site store failed to answer is retried through GitHub, and what the guest got was a splice, whatever billet set out to do. A job's calls run concurrently, so the one kept is the first completed outcome to take the session's lock and be written, which need not be the call dispatched first or even the one that finished first; any of them is an honest account of a call this job made.

const (
	// ActionsCacheServed means the request was answered from the site store.
	ActionsCacheServed ActionsCache = "served"
	// ActionsCacheSpliced means interception was on and billet handed the
	// request to GitHub for a reason other than the kill switch: the policy
	// could not be read, the client was not one billet serves locally, or the
	// local handler failed. It says what billet did with the call, not what
	// GitHub answered; an upstream that could not be reached is GitHub's
	// unavailability, and the path fails open on it by design.
	ActionsCacheSpliced ActionsCache = "spliced"
	// ActionsCacheDisabled means the central kill switch refused the request.
	ActionsCacheDisabled ActionsCache = "disabled"
	// ActionsCacheUnavailable means billet answered the request with a failure
	// of its own and handed nothing to GitHub: a call bound to a reservation
	// only billet holds that failed locally, or a request billet refused before
	// reading it.
	ActionsCacheUnavailable ActionsCache = "unavailable"
	// ActionsCacheOff means the session had no interception at all: the tier does
	// not intercept, or the work was untrusted.
	ActionsCacheOff ActionsCache = "off"
	// ActionsCacheUnused means interception was on and the session closed
	// without a CacheService request ever arriving.
	ActionsCacheUnused ActionsCache = "unused"
)

func (ActionsCache) Valid added in v0.8.0

func (c ActionsCache) Valid() bool

Valid reports whether this is a token billet may write.

type Allocator

type Allocator struct {
	// contains filtered or unexported fields
}

Allocator hands out and reclaims capacity. Safe for concurrent use: every decision is one transaction against the single-writer state store, so a read-decide-record sequence cannot interleave with another.

func New

func New(db *state.DB, limits Limits, tiers []config.Tier, opts ...Option) (*Allocator, error)

New builds an allocator over the given tier catalog.

func (*Allocator) AcknowledgePoolRunner

func (a *Allocator) AcknowledgePoolRunner(ctx context.Context, tier string, requestID int64) error

AcknowledgePoolRunner records that GitHub cannot redeliver the completion. The row is removed immediately only when physical settlement already landed.

func (*Allocator) ActiveRunnerLeases

func (a *Allocator) ActiveRunnerLeases(ctx context.Context, tier string) (int, error)

ActiveRunnerLeases reports tier capacity assigned to a runner GitHub can still route a job to. It includes restart-adopted compute that predates the durable pool_runners journal, so aggregate scale reconciliation does not replace a runner the node is still holding.

It counts every non-terminal lease EXCEPT one whose GitHub registration has been removed (`deregistered`, set when RemoveRunner succeeds). Phase alone cannot make this distinction: a completed-job teardown has been deregistered and must stop counting, or its lingering compute-destroy retry over-counts against the assignment deficit and drops a freshly acquired job; an ambiguous-launch custody teardown or a reaped-but-still-registered idle runner has NOT been deregistered and must keep counting, or the grow loop launches a replacement against a runner GitHub can still schedule — a double-schedule whose losing side is also a dropped job. The deregistration signal is what separates the two.

func (*Allocator) Admission

func (a *Allocator) Admission(ctx context.Context) (state.Admission, error)

Admission reports whether the deployment is accepting new work.

On the read-only pool: a status command must not reserve the single writer slot to answer a question, and this one is asked by every operator wondering why their jobs are queueing.

func (*Allocator) AdmissionGeneration

func (a *Allocator) AdmissionGeneration(ctx context.Context) (int64, bool, error)

AdmissionGeneration is the generation a compute barrier is scoped to, and whether the deployment is refusing work at it.

BOTH, BECAUSE EITHER ALONE IS A LOOPHOLE. The generation moves on every seal and every resume, so comparing it catches a deployment that was reopened — including one reopened and resealed, which a boolean would miss entirely. The boolean catches the other direction: a barrier requested against an OPEN deployment, which no billet command does today and which would otherwise be serviced as if it meant something.

func (*Allocator) Advance

func (a *Allocator) Advance(ctx context.Context, leaseID string, epoch int64, to Phase) error

Advance moves a lease to the next phase, refusing anything the state machine does not allow.

func (*Allocator) AgeQuarantineForTest

func (a *Allocator) AgeQuarantineForTest(ctx context.Context, leaseID string) error

AgeQuarantineForTest pushes a quarantined lease past the grace, so a test can reach the settled case without a clock.

func (*Allocator) Assign

func (a *Allocator) Assign(ctx context.Context, leaseID string, epoch, runID, requestID int64) error

Assign binds a reserved lease to a GitHub job.

Retrying with the SAME job is idempotent. Retrying with a DIFFERENT job is ErrConflict, not success: an escrowed slot holds one job, and returning nil while keeping the original would leave the caller believing a job is scheduled that nothing will run.

func (*Allocator) AttributedFailures

func (a *Allocator) AttributedFailures(
	ctx context.Context, since time.Time, limit int,
) ([]AttributedFailure, error)

AttributedFailures lists jobs that did not succeed while billet's own infrastructure was disrupted, newest first.

ON THE READ-ONLY POOL. An operator asks this while the control plane is working, and a report must never reserve the single writer slot.

WINDOWED ON result_at RATHER THAN finished_at, which is written when the LEASE terminalizes and stays empty for as long as a destroy is retrying — a job whose teardown is wedged is exactly one worth reporting.

The provisional inventory marker is stripped from Detail: it is billet's own bookkeeping sentinel rather than an explanation, and the disruption token already says what it means.

func (*Allocator) Bind

func (a *Allocator) Bind(ctx context.Context, leaseID string, epoch int64, node string) error

Bind records which node is running a lease.

A lease pinned to a node may only bind to THAT node: without the check, a macOS lease pinned to one Mac could bind to another while its licence slot stayed charged to the first, and the second host would accept guests beyond Apple's limit with every individual decision looking correct.

Rebinding elsewhere is refused rather than silently overwritten; repeating the same bind is idempotent, because a node retrying after a lost response must not be told its own success was a conflict.

func (*Allocator) BumpDispatch

func (a *Allocator) BumpDispatch(ctx context.Context, node string) (int64, error)

BumpDispatch advances a host's launch-dispatch fence and returns the new value.

IT COUNTS LAUNCHES, NOT COMMANDS. A destroy, sweep, tend or inventory cannot create compute, so charging them would void proofs for no reason.

The CALLER's ordering is the invariant, not this function: the plane advances this BEFORE the launch becomes reachable in a node's queue, under one hold of its mutex. A bump taken outside that hold can be observed by a barrier that is then queued AHEAD of the launch, and the acknowledgement would be accepted with a launch still to run.

func (*Allocator) CertRevoked

func (a *Allocator) CertRevoked(ctx context.Context, serial string) (bool, error)

CertRevoked reports whether a certificate has been withdrawn.

FAILS CLOSED IS NOT AN OPTION HERE, and that is worth being explicit about: a database error returns the error rather than a verdict, and the caller refuses the request. Answering "not revoked" on a failed read would make an unreadable ledger equivalent to an empty one, which is the whole check switched off by a transient fault.

func (*Allocator) CertRevokedFor

func (a *Allocator) CertRevokedFor(
	ctx context.Context, node, serial string, issuedAt time.Time,
) (bool, error)

CertRevokedFor reports whether a certificate has been withdrawn, by serial or by the cutoff its node carries.

issuedAt IS WHEN THE CERTIFICATE WAS MINTED, which is NOT its NotBefore.

Every certificate billet issues is valid from an hour before it was created, so that a node whose clock is behind the control plane's does not reject what it was just handed. Reading NotBefore as the issuance moment therefore places every certificate an hour earlier than it really is — and a replacement issued within an hour of a revocation would fall before the cutoff and be refused, which turns a revocation into a permanent ban on the node name. The caller adds wirecert.ClockSkew back before calling.

func (*Allocator) CodeBuildRegistrationPaths

func (a *Allocator) CodeBuildRegistrationPaths(ctx context.Context) ([]RegistrationPath, error)

CodeBuildRegistrationPaths lists every codebuild host the ledger has ever seen and the path each stages registrations under.

func (*Allocator) ComputeBarrierInForce

func (a *Allocator) ComputeBarrierInForce(ctx context.Context) (ComputeBarrier, bool, error)

ComputeBarrierInForce reports the durable request, if there is one.

func (*Allocator) ComputeClear

func (a *Allocator) ComputeClear(ctx context.Context) (ComputeClearance, error)

ComputeClear reports what the fleet has proved about the compute it holds.

ON THE READ-ONLY POOL. A drain asks this on a cadence while the control plane is working, and a question must not reserve the single writer slot to answer itself.

func (*Allocator) DecideEnrollment

func (a *Allocator) DecideEnrollment(
	ctx context.Context, name, fingerprint, decision, certPEM string,
) error

DecideEnrollment approves or denies a pending request.

THE FINGERPRINT IS PART OF THE DECISION, not just a thing to look at. An operator approves the machine whose fingerprint they read off its console, and requiring it here is what makes that comparison load-bearing: approving by name alone would approve whatever is currently holding the name.

func (*Allocator) Decommission

func (a *Allocator) Decommission(ctx context.Context, req DecommissionRequest) (bool, error)

Decommission removes a host from the set a compute barrier expects to hear from.

MEMBERSHIP IS NEEDED BECAUSE "EVERY REGISTERED NODE" NEVER CONVERGES: a node row is durable and a control-plane start marks the fleet unreachable rather than removing anything, so a host retired a year ago would block every drain from now on.

IT MUST NOT LAUNDER UNCERTAINTY, which is the whole difficulty. If a silent host can simply be excluded, the next drain reports "nothing is running" while that host runs somebody's job. So an unproven exclusion is recorded AS unproven and stays that way, and every report that consumes it says so.

`drained` is what it writes, reconciling a column the schema has carried since migration 1 that no production code has ever written. Both placement queries and the floor arithmetic already read `live = 1 AND drained = 0`, so there is nothing new to teach them.

IT REPORTS WHETHER THE EXCLUSION WAS PROVED, and derives that ITSELF, inside this transaction. A caller cannot supply it: a proof is a statement about an incarnation, and a host can re-register between a caller reading its clearance and this write — which is exactly the change the epoch fence exists to catch. Passing a boolean across that gap would record a machine that had just come back, and may be running something, as proved idle.

func (*Allocator) DirectJobIdentity

func (a *Allocator) DirectJobIdentity(ctx context.Context, jobID string) (int64, bool, error)

DirectJobIdentity reads an existing direct-assignment identity without creating one.

func (*Allocator) DropComputeBarrier

func (a *Allocator) DropComputeBarrier(ctx context.Context, id string) error

DropComputeBarrier removes a request that can no longer mean anything, and its observations with it.

FENCED ON THE ID, so a loop dropping the barrier it was working on cannot drop one a waiter has just replaced it with.

func (*Allocator) EndedLeaseNode

func (a *Allocator) EndedLeaseNode(ctx context.Context, leaseID string) (string, error)

EndedLeaseNode reports the host a lease's job was attributed to, from the history row that outlives the lease.

WHAT AUTHORISES A REGISTRATION REMOVAL FOR A LEASE THAT IS OVER. The lease row's placement is gone once it terminalizes, and membership alone would let any registered node name another host's ended lease and withdraw its runner; the history row keeps the attribution. Empty when the job was never attributed to a host, which a caller must treat as no permission.

func (*Allocator) Enrollments

func (a *Allocator) Enrollments(ctx context.Context, want string) ([]Enrollment, error)

Enrollments lists what has asked to join.

func (*Allocator) Escrow

func (a *Allocator) Escrow(ctx context.Context, tier string, want int) ([]*Lease, error)

Escrow reserves up to want instances of a tier and returns the leases it actually took. len(result) is what a scale-set listener may advertise.

Reading headroom and then advertising it are two steps with a gap between them, and the gap is where two listeners promise the same slots. Escrow makes the promise and the reservation one act. Taking fewer than requested is ordinary.

func (*Allocator) ExpireForTest

func (a *Allocator) ExpireForTest(ctx context.Context, leaseID string) error

ExpireForTest ages a lease out, so a test can drive the real reaper.

A TEST THAT STAGES THE PHASE BY HAND PROVES NOTHING about the path it claims to protect: the reaper is what decides quarantine, and its rule about which phases keep their compute is exactly the thing worth testing. Moving the clock is the alternative, and it makes every helper take one.

func (*Allocator) ForceDestroyCandidates

func (a *Allocator) ForceDestroyCandidates(
	ctx context.Context, tier, node string,
) ([]ForceCandidate, error)

ForceDestroyCandidates lists the running compute an operator could destroy, oldest first.

ON THE READ-ONLY POOL. It is asked by a command with a person waiting, and again by that command to build the diagnostic; neither may reserve the single writer slot while the control plane is scheduling.

func (*Allocator) ForceRelease

func (a *Allocator) ForceRelease(ctx context.Context, leaseID string) (ForceReleaseResult, error)

ForceRelease records an operator's assertion that held compute is gone.

A quarantined lease has no live holder, so it is resolved here. Custody and teardown do have one: setting force_release makes its next heartbeat return ErrForceRelease, after which that node drops the local custody record and releases the lease. This ordering avoids changing the ledger underneath a process that still believes it owns the proof obligation.

func (*Allocator) ForceTargets

func (a *Allocator) ForceTargets(
	ctx context.Context, generation int64,
) ([]state.ForceTarget, error)

ForceTargets lists every lease one force-destroy covers.

func (*Allocator) ForceTerminate

func (a *Allocator) ForceTerminate(ctx context.Context, leaseID string) error

ForceTerminate archives a lease whose compute an operator destroyed.

THE ONE TERMINALISER FOR BOTH KINDS OF FORCED LEASE, and that is why it takes an id rather than a *Lease. A listener holds an object for the work it launched itself, and holds nothing at all for compute a restart re-adopted — but the durable force record names the lease either way, so a path keyed on the id reaches both and a path keyed on the in-memory object silently skips every job that outlived a control plane.

THE PHASE IS READ INSIDE THE TRANSACTION rather than taken from the destroy pass. Between asking a backend to stop a guest and returning its capacity, that lease can acquire a live holder — and a decision made from the caller's memory would free capacity the node had just taken responsibility for, seconds after the handoff.

func (*Allocator) ForgetEveryNode

func (a *Allocator) ForgetEveryNode(ctx context.Context) error

ForgetEveryNode marks the whole fleet unreachable, for a control plane that has just started.

LIVENESS IS THE PLANE'S JUDGEMENT, and a plane that has just started has not formed one. Every node re-registers within a poll, so the cost is a brief zero that is also the truth.

func (*Allocator) ForgetPoolRunner

func (a *Allocator) ForgetPoolRunner(ctx context.Context, leaseID string) error

ForgetPoolRunner removes settlement metadata after compute and capacity are gone.

func (*Allocator) Headroom

func (a *Allocator) Headroom(ctx context.Context, tier string) (int, error)

Headroom reports how many more instances of a tier would fit right now.

DIAGNOSTIC ONLY — never advertise this number to GitHub. It reserves nothing, so two listeners can each read four free slots and each advertise four, and Reserve cannot retract a promise GitHub has already received. Advertise what Escrow returns.

func (*Allocator) Heartbeat

func (a *Allocator) Heartbeat(ctx context.Context, leaseID string, epoch int64) error

Heartbeat extends a lease's expiry. A holder that stops calling this loses the lease to Reap.

func (*Allocator) Held

func (a *Allocator) Held(ctx context.Context) ([]HeldLease, error)

Held lists every operator-visible proof obligation, oldest first.

func (*Allocator) HistoryFailureReason

func (a *Allocator) HistoryFailureReason(ctx context.Context, leaseID string) (string, error)

HistoryFailureReason reports the durable explanation attached to a finished lease. An empty string means no external failure was recorded.

func (*Allocator) HistoryOutcome

func (a *Allocator) HistoryOutcome(ctx context.Context, leaseID string) (string, error)

HistoryOutcome reports how a finished lease was recorded.

The only DURABLE statement about what happened to a job, which is what makes it the right thing for a test to assert against. An in-memory field that feeds the archive is an input, not a record: a test reading it stays green even if the write hardcodes the wrong value.

func (*Allocator) HistoryOutcomesForRequest

func (a *Allocator) HistoryOutcomesForRequest(ctx context.Context, requestID int64) ([]string, error)

HistoryOutcomesForRequest reports how every archived lease for one job request was recorded, newest last.

A job can have more than one lease across a restart — GitHub redelivers an unacknowledged assignment, and the listener escrows a fresh lease for it — so "what happened to request N" is a list rather than a value. That plurality is the point: it is how a caller distinguishes a redelivery that was correctly refused from one that was silently dropped.

func (*Allocator) HistoryPlacement added in v0.8.0

func (a *Allocator) HistoryPlacement(ctx context.Context, leaseID string) (JobPlacement, error)

HistoryPlacement reads what a lease was charged for from its history row.

THE ONLY DURABLE STATEMENT ABOUT WHAT A JOB COST, which is what makes it the right thing for a test to assert against; the lease row it was copied from is reaped. ErrLeaseNotFound when the lease never had a history row.

func (*Allocator) IdentifyDirectJob

func (a *Allocator) IdentifyDirectJob(ctx context.Context, jobID string) (int64, error)

IdentifyDirectJob returns a durable negative scheduler id for one GitHub job id.

GitHub's direct JobAssigned path carries runnerRequestId 0. Zero cannot key concurrent work, while hashing jobId would make collisions a correctness property. Allocation under the database's immediate writer transaction gives every distinct job id one collision-free negative number and makes redelivery recover the same one after a restart.

func (*Allocator) IdentifyPoolSlot

func (a *Allocator) IdentifyPoolSlot(ctx context.Context, leaseID string) (int64, error)

IdentifyPoolSlot returns a durable negative scheduler id for one escrowed lease becoming a physical pool member. GitHub's desired-count signal names a quantity rather than a job, so the lease is the stable identity available on redelivery and after restart.

func (*Allocator) IdlePoolRunners

func (a *Allocator) IdlePoolRunners(ctx context.Context, tier string) ([]PoolRunner, error)

IdlePoolRunners reports pool members that can be considered for scale-down.

func (*Allocator) InvalidateBarrierRun

func (a *Allocator) InvalidateBarrierRun(ctx context.Context, node string) error

InvalidateBarrierRun discards a host's continuous-empty run.

CALLED WHEN A REGISTRATION BEGINS, not when it commits. The ledger's epoch — which is what fences a run — does not move until the registration's write lands, and `billet drain` reads this ledger from ANOTHER PROCESS where the plane's in-flight-registration state is invisible. So between a replacement arriving and its epoch committing, a completed run reads as current and the fleet can be reported clear about a host whose new incarnation may be holding compute the old one never saw.

UNCONDITIONAL, and cheap because it names one row. Discarding a run that did not need discarding costs one barrier round; keeping one that did costs a stopped service on a machine running somebody's job. IT READS BEFORE IT WRITES, and that is not a micro-optimisation. This now runs on EVERY registration, ahead of the revocation check — so a credential an operator has taken back can call it as fast as it can open connections, and an unconditional `db.Tx` would let it reserve SQLite's single writer slot over and over, starving every scheduling decision in the process. The overwhelmingly common case is a host with no run at all, and the read pool answers that.

The gap between the read and the skipped write is closed by the epoch: a run recorded in it belongs to an incarnation whose registration is about to move the epoch, which discards it. Where that registration is REFUSED and the epoch never moves, the run can only have come from another process answering under the same name — which is the two-hosts-one-identity residual this design documents rather than closes.

func (*Allocator) InvalidateEveryBarrierRun

func (a *Allocator) InvalidateEveryBarrierRun(ctx context.Context) error

InvalidateEveryBarrierRun discards what EVERY host had proved.

FOR THE ARRIVAL THAT CANNOT BE ATTRIBUTED. A loopback wire requires no certificate, so a registration whose body cannot be decoded — an unknown field from a node rolled ahead of the control plane, an oversized body — names no host at all, and those refusals are permanent ones a node does not retry. Something arrived, billet cannot tell what, and "I could not tell" must not read as "nothing changed".

OVER-INVALIDATION IS THE POINT, and it is cheap where it happens: a loopback deployment is one machine, so this is one host's barrier round. It is never reached on the real wire, where the certificate names the host.

func (*Allocator) JobForLease

func (a *Allocator) JobForLease(ctx context.Context, leaseID string) (LeaseJob, error)

JobForLease reads the job identity assigned to a lease, including a terminal one.

GitHub's completed-job message may omit runnerRequestId while still naming the ephemeral runner. The runner name carries the lease id, and this durable lookup recovers the request id without trusting an in-memory ownership map that a restart has erased. Terminal rows remain readable because an unacknowledged completion can be redelivered after teardown and release already settled.

func (*Allocator) JoinTokens

func (a *Allocator) JoinTokens(ctx context.Context) ([]JoinToken, error)

JoinTokens lists what is outstanding, without the secrets.

func (*Allocator) LatestForceDestroy

func (a *Allocator) LatestForceDestroy(ctx context.Context) (state.ForceDestroy, bool, error)

LatestForceDestroy reads the most recent force-destroy, for the report.

func (*Allocator) LaunchedLeaseIDs

func (a *Allocator) LaunchedLeaseIDs(ctx context.Context, node string) (map[string]bool, error)

LaunchedLeaseIDs reports the leases on a node that could legitimately have compute running for them.

Reconciliation's other half. A node can enumerate the compute it is running, but an instance alone does not say whether it is still WANTED — that is a fact about the lease, and it lives here. Anything running whose id is absent from this set is an orphan.

Scoped to one node deliberately. A node must never reason about instances it does not own, and a set containing every node's leases would let a bug on one host spare an orphan on another.

LAUNCHING, ONLINE, BUSY, CUSTODY and TEARDOWN — not merely "not terminal". A lease in the capacity or assigned phase has nothing running for it by construction, because the launch path commits Bind and Advance(launching) before it asks a provider to create anything. Including those phases would spare an instance that no phase authorises, which is precisely the orphan the caller is hunting.

I first wrote this as "not terminal" and justified the wider predicate with a race that does not exist: the caller lists instances BEFORE calling this, so anything it is judging was already created, and anything already created already has a lease at launching or beyond.

func (*Allocator) Lease

func (a *Allocator) Lease(ctx context.Context, leaseID string) (*Lease, error)

Lease reads one lease by id, whatever epoch it is at.

No epoch argument, deliberately, and it is the only reader shaped that way. Every other path holds a lease it was handed and passes the epoch back as a fence. This one exists for a caller that has just found ORPHANED compute and knows only the id encoded in its name — it has no epoch to present, because the process that held one is gone. Reading without a fence is safe here precisely because nothing is being mutated on the strength of it; the caller takes the epoch from the row and presents it to Release, which fences normally. A lease that moved in between fails there, which is correct.

Returns ErrLeaseNotFound for a lease that is absent OR already terminal, so a caller cleaning up cannot mistake "already finished" for "still holding capacity".

func (*Allocator) LeaseClosure

func (a *Allocator) LeaseClosure(ctx context.Context, leaseID string) (LeaseClosure, error)

LeaseClosure reports whether a lease is over and when the ledger closed it.

A READ ERROR IS RETURNED, NOT FOLDED INTO "UNKNOWN". An unknown lease is a fact the caller reports and keeps; a database that could not answer is evidence about nothing, and the caller stops rather than acting on any lease it has not asked about.

func (*Allocator) LeaseTTL

func (a *Allocator) LeaseTTL() time.Duration

LeaseTTL reports how long a lease survives without a heartbeat.

Exported because a holder has to renew FASTER than this: one deriving its cadence from DefaultLeaseTTL is correct only when the default is in use, and a shorter configured TTL then silently expires every lease it holds.

func (*Allocator) LiveCertsFor

func (a *Allocator) LiveCertsFor(ctx context.Context, node string) ([]IssuedCert, error)

LiveCertsFor lists the credentials a node holds that are neither expired nor already revoked.

func (*Allocator) LookupEnrollment

func (a *Allocator) LookupEnrollment(ctx context.Context, name string) (Enrollment, bool, error)

LookupEnrollment reads a request without creating one.

SEPARATE FROM RequestEnrollment, which INSERTS. Reusing that to ask "does this already exist" would record a row as a side effect of the question — and with no CSR on it, because a question does not carry one, leaving an enrollment that can never be approved.

func (*Allocator) MarkDeregistered

func (a *Allocator) MarkDeregistered(ctx context.Context, leaseID string) error

MarkDeregistered records that a lease's GitHub runner registration has been removed, which is what ActiveRunnerLeases keys on instead of phase. A teardown whose compute destroy is still retrying is deregistered, so it stops over-counting against the assignment deficit and no longer drops a freshly acquired job; a teardown or quarantine whose runner was never deregistered stays counted, so a replacement is not launched against a runner GitHub can still schedule.

It is NOT epoch-fenced, and deliberately so. Deregistration is a monotonic fact about GitHub, not about who holds the lease: once RemoveRunner has succeeded the runner is gone whatever the lease's epoch. A reap that quarantines the lease bumps the epoch, but a quarantined lease has only terminal successors and a reap never relaunches on the same row — new capacity is always a fresh lease id — so no live runner can ever occupy a row this flag has set. Fencing it here would let a reap between RemoveRunner and the mark strand a gone runner's lease as counted forever. Missing rows and terminal leases are harmless no-ops.

func (*Allocator) MarkFailure

func (a *Allocator) MarkFailure(ctx context.Context, leaseID string, epoch int64, reason string) error

MarkFailure records why a still-open lease is destined to fail.

Separate from Release because the fact often arrives before compute is gone, and capacity must remain charged throughout that interval.

func (*Allocator) NewJoinToken

func (a *Allocator) NewJoinToken(ctx context.Context, ttl time.Duration, uses int, note string) (string, error)

NewJoinToken mints one and returns the secret, which is shown exactly once.

BASE32 WITHOUT PADDING, because this is read off one terminal and typed into another: no case sensitivity to lose, no `+` or `/` to mangle in a shell, and no `=` for somebody to trim.

func (*Allocator) NodeFenceOf

func (a *Allocator) NodeFenceOf(ctx context.Context, node string) (NodeFence, bool, error)

NodeFenceOf reads the fence a barrier observation of this host must carry.

func (*Allocator) NodeGone

func (a *Allocator) NodeGone(ctx context.Context, name string, epoch int64) error

NodeGone records that the control plane has given up on a host.

FENCED ON THE EPOCH. Registration commits to the ledger BEFORE it takes the plane's mutex, and expiry holds that mutex while dropping the old entry — so a host that restarts quickly could commit its new registration and then be marked dead by the expiry of the incarnation it replaced. A no-op once the epoch has moved, which is the point.

func (*Allocator) NodeInventories

func (a *Allocator) NodeInventories(ctx context.Context) ([]NodeInventory, error)

NodeInventories reports what every known host last said it was running.

ON THE READ-ONLY POOL, because this answers a question an operator asks while the control plane is working, and a report must not reserve the writer slot.

func (*Allocator) NodeWireVersions

func (a *Allocator) NodeWireVersions(ctx context.Context) ([]NodeWire, error)

NodeWireVersions reports which wire version every known host is on.

ON THE READ-ONLY POOL. An operator asks this while the control plane is working, and a report must not reserve the single writer slot.

func (*Allocator) NodeWithdrawn

func (a *Allocator) NodeWithdrawn(
	ctx context.Context, name string, epoch int64, incarnation string,
) error

NodeWithdrawn records that a host said it is leaving, and takes it out of placement at once.

THE OPPOSITE OF NodeGone IN WHAT IT PROVES, and the same in what it writes. NodeGone is the control plane giving up on a host it can no longer hear — an observation about the jobs on it, which is why it marks them disrupted. This is the host itself saying, after it released its last lease, that it will not poll again. Nothing is being observed about anybody's job, so nothing is marked; and nothing is released, because a withdrawal only stops NEW work being aimed here — a lease escrowed against this host in the last instant is answered "nothing started" by the plane and handed back by the listener, exactly as it is after silence.

FENCED ON THE EPOCH AND THE INCARNATION, and the second is not redundant with the first: the epoch proves no registration landed since the plane read it, and the incarnation proves the process asking is the one that registration recorded. A superseded process still holds the certificate and the name, and its withdrawal must not take its replacement out of the fleet.

ONLY `live` MOVES. drained, the decommission columns, the inventory and the barrier run are all left alone: a withdrawal is not a decommission and not a proof, and the next registration clears what it needs to.

func (*Allocator) OpenForceDestroy

func (a *Allocator) OpenForceDestroy(ctx context.Context) (state.ForceDestroy, bool, error)

OpenForceDestroy reads the force-destroy request that has not finished, if any.

func (*Allocator) PendingForceTargets

func (a *Allocator) PendingForceTargets(
	ctx context.Context, generation int64, tier string,
) ([]state.ForceTarget, error)

PendingForceTargets lists what one tier still owes a destroy for.

func (*Allocator) PoolRunnerByLease

func (a *Allocator) PoolRunnerByLease(ctx context.Context, leaseID string) (PoolRunner, error)

PoolRunnerByLease resolves the compute authority when no message carries a runner name.

func (*Allocator) PoolRunnerByName

func (a *Allocator) PoolRunnerByName(ctx context.Context, name string) (PoolRunner, error)

PoolRunnerByName resolves GitHub's runner identity to Billet's compute lease.

func (*Allocator) PoolRunners

func (a *Allocator) PoolRunners(ctx context.Context, tier string) ([]PoolRunner, error)

PoolRunners reports every durable member of one tier's GitHub runner pool.

func (*Allocator) PreserveRecoveredBusyPoolRunner

func (a *Allocator) PreserveRecoveredBusyPoolRunner(ctx context.Context, runner PoolRunner) error

PreserveRecoveredBusyPoolRunner journals the exact identity of a legacy registration GitHub says is busy. Its empty actual-job fields are filled by a delayed JobStarted through StartPoolRunner.

func (*Allocator) Quarantined

func (a *Allocator) Quarantined(ctx context.Context) ([]QuarantinedLease, error)

Quarantined lists the leases holding capacity for compute nobody has accounted for, oldest first.

WHAT AN OPERATOR LOOKS AT WHEN CAPACITY IS MISSING. A quarantined lease is the one thing that shrinks a fleet without anything having failed, so it has to be visible or the number is inexplicable.

func (*Allocator) QuarantinedLeaseIDs

func (a *Allocator) QuarantinedLeaseIDs(ctx context.Context, node string) (map[string]bool, error)

QuarantinedLeaseIDs reports the quarantined leases attributed to one node.

SOMETHING IS STILL WAITING FOR THIS COMPUTE, which is the question the node is asking. LaunchedLeaseIDs answers it for leases a listener is managing, and deliberately does not include quarantine — the plane uses that set to decide ownership. But a quarantined lease is the case where the compute matters MOST: nobody is managing it, so a node that read only the launched set would see a running job as an orphan and destroy it.

func (*Allocator) Quiescence

func (a *Allocator) Quiescence(ctx context.Context) (Quiescence, error)

Quiescence reports what the deployment is still holding, and whether new work can still arrive.

ON THE READ-ONLY POOL, because a drain asks this on a cadence while the control plane is doing real work, and a question must not reserve the single writer slot to answer itself.

func (*Allocator) Reap

func (a *Allocator) Reap(ctx context.Context) (int, error)

Reap terminalizes leases whose holders stopped heartbeating, and returns how many it reclaimed.

The epoch is bumped as part of reclaiming, so a holder that comes back — a paused process, a healed partition — finds its writes refused rather than silently operating on a lease someone else now owns.

func (*Allocator) Reconcile

func (a *Allocator) Reconcile(ctx context.Context, node string, running []string) (int, error)

Reconcile frees capacity held for compute a host says it is not running.

THE IN-PROCESS SIDE OF THE NODE WIRE'S /reconcile, so a colocated node reaches the same code as a remote one. It reads the node's current epoch itself because there is no registration in flight to carry one — the caller IS the current incarnation by construction.

func (*Allocator) RecordBarrierObservation

func (a *Allocator) RecordBarrierObservation(ctx context.Context, obs BarrierObservation) error

RecordBarrierObservation stores one fenced observation, or ends the run.

THE WHOLE CONTENT OF THIS FUNCTION IS ITS REFUSALS. A launch dispatched after the barrier was issued has already advanced dispatch_generation, so this write matches nothing and the round is simply lost — which is the point. The alternative shape, where a launch INVALIDATES an acknowledgement, races the response it is invalidating: nonce N is queued, a later launch clears N, and the node then reports N and writes it back as valid while that launch is still waiting behind it.

A NON-EMPTY OR FAILED ANSWER DELETES THE ROW. What is stored is a CONTINUOUS RUN, not a snapshot, so an interruption ends it rather than ageing it.

func (*Allocator) RecordCacheObservation added in v0.8.0

func (a *Allocator) RecordCacheObservation(
	ctx context.Context, leaseID string, epoch int64, obs CacheObservation,
) error

RecordCacheObservation writes what a node saw the cache do for a lease's job.

FENCED ON THE EPOCH, because the observation arrives from the process holding the compute and a holder declared dead must not go on writing to a lease somebody else owns. Refuses a terminal lease: the history is closed then, and an archive already copied whatever the lease held.

THE FIRST OBSERVATION IS KEPT, and the statements decide it: each column is written only while it is empty, so a repeat from a node retrying a lost response changes nothing and a later, different observation cannot replace what the guest first saw. Both rows are written in one transaction, the history row NOW rather than at archive, for the reason a disruption is (see applyDisruptionTx). A lease that never reached Assign has no history row and that half updates nothing, which is correct: it ran no job.

func (*Allocator) RecordIssued

func (a *Allocator) RecordIssued(
	ctx context.Context, name, fingerprint, certPEM string,
) (string, error)

RecordIssued writes down a certificate handed out directly, so both ways into a deployment leave the same trail.

`billet ca issue` is the older path and the right one for a machine being provisioned anyway — cloud-init can drop a bundle on it, and no human is standing there to compare a fingerprint. It recorded NOTHING, so there was no single answer to "what has been admitted here, and when": a fleet built that way was invisible to the same list that shows what is waiting.

Marked as its own source, because the two are not the same fact. One was approved by somebody comparing a fingerprint; this one was issued. It REPORTS WHAT IT DISPLACED, because the wire refuses a second key under a name the first one claimed and this path does not. Overwriting is right here — an operator issuing a certificate is a deliberate act, and refusing would leave a name unusable after a machine was rebuilt — but it must not be silent: the fingerprint an operator compared yesterday stops describing anything, and nothing else would ever tell them.

func (*Allocator) RecordIssuedCert

func (a *Allocator) RecordIssuedCert(ctx context.Context, c IssuedCert) error

RecordIssuedCert writes down a credential at the moment it is handed out.

WITHOUT THIS, REVOCATION CANNOT REACH A RENEWAL. Revocation names one serial, which is the right granularity — a node name is legitimately re-issued to a replacement machine — but it only works on serials billet knows about. Renewal mints a fresh key and serial over the wire, so a node that has renewed once is presenting a credential that exists nowhere but on that node. An operator revoking the bundle they originally issued takes back a serial nobody holds, and the host carries on.

func (*Allocator) RecordJobResult

func (a *Allocator) RecordJobResult(
	ctx context.Context, leaseID, result string, runID int64,
) error

RecordJobResult stores GitHub's own conclusion for the job a lease ran.

SEPARATE FROM job_history.conclusion, which is the LEASE's terminal phase and answers a different question: whether billet's compute lifecycle finished tidily. A job GitHub reports as failed on a lease billet tore down perfectly is `done` there, and always was — so nothing in the ledger could tell an operator their build failed until this column existed.

UNFENCED, for the same reason MarkDeregistered is: GitHub's conclusion for a job is monotonic and says nothing about who holds the lease. A reap that quarantined the row in the meantime does not make the job unfinished.

A lease that never reached Assign has no history row and nothing to record — a promise GitHub cancelled before assigning it ran no job — so a write that matches nothing is success rather than an error.

STORED VERBATIM, and the trim is only ever a blankness TEST. Normalising the stored value would decide the report: `" succeeded "` trimmed to `"succeeded"` vanishes from it, and the one thing this column must not do is turn a value billet does not recognise into one it does. An unknown result fails OPEN into the report, quoted, where a person can see the padding.

FIRST OBSERVATION WINS, like MarkFailure and like a disruption. A lease runs exactly one job, so its result is immutable: a redelivery carries the same word, and re-writing would slide `result_at` forward and drag a days-old job back into every `--since` window while its teardown kept retrying. A CONTRADICTORY result is refused rather than allowed to replace the first, because one of the two is wrong and the earlier one is the one GitHub said first. THE WORKFLOW RUN IS FILLED IN HERE WHEN THE LEDGER HAS NONE, and only then. A pooled runner is launched before GitHub chooses its job, so assignPoolSlot records run 0 and the lease's own launch request id — and the run an operator needs is the one on the COMPLETION, which names the job that actually ran. Never an overwrite: a recorded run is the one this lease was assigned, and replacing it would let a swapped pool member rewrite another job's history.

func (*Allocator) RecordRenewedCert

func (a *Allocator) RecordRenewedCert(
	ctx context.Context, cert IssuedCert, parent string, parentIssuedAt time.Time,
) error

RecordRenewedCert records a renewal, refusing one whose parent was revoked.

THE RACE THIS CLOSES. Revocation checks the presented certificate at the start of a request, and a renewal signed a new serial some milliseconds later; a revocation committing in between took back a credential the machine had already stopped presenting, and reported success. Recording the child in the same transaction that asks about the parent makes the order decide: either the renewal lands first and RevokeNode sees its serial, or the revocation lands first and this refuses.

The wire refuses the renewal when this does, so the node keeps the certificate it has — which is the revoked one, and will be turned away on its next request. That is the intended outcome.

func (*Allocator) RecordedJobResult

func (a *Allocator) RecordedJobResult(ctx context.Context, leaseID string) (string, error)

RecordedJobResult reports what GitHub concluded about the job a lease ran, or an empty string when nothing has been recorded.

AN EMPTY ANSWER IS ONE OF THREE THINGS and the caller must not collapse them: the job has not finished, this lease never ran one, or it predates the column. Nothing here decides between them, which is why the report pairs the result with a disruption rather than reasoning from its absence.

func (*Allocator) RegisterNode

func (a *Allocator) RegisterNode(ctx context.Context, reg NodeRegistration) (int64, error)

RegisterNode records a host and what it runs, so leases can be placed on it.

A node exists in this table because it TOLD billet it exists, not because somebody wrote it in a config file. That is the whole reason placement compares a lease against the REGISTERED provider rather than a catalog entry: a host that says it runs Firecracker is the authority on that, and a catalog claiming otherwise is the thing that should lose.

Upsert, because a host re-registers every time it starts. The epoch is bumped on re-registration so a previous instance of the same host — a process that was killed and came back, or one that hung and returned — finds its writes refused rather than operating on leases the new instance now owns.

func (*Allocator) RegisterPoolRunner

func (a *Allocator) RegisterPoolRunner(ctx context.Context, runner PoolRunner) error

RegisterPoolRunner records the idle pool member created for a lease.

func (*Allocator) RegisteredNodes

func (a *Allocator) RegisteredNodes(ctx context.Context) ([]RegisteredNode, error)

RegisteredNodes lists every host the deployment has recorded, including an offline host whose placement identity is still part of the ledger.

func (*Allocator) Release

func (a *Allocator) Release(ctx context.Context, leaseID string, epoch int64, outcome Phase) error

Release terminalizes a lease and returns its capacity.

Idempotent: releasing an already-terminal lease succeeds, because a node retrying after a lost response must not be told its cleanup failed.

func (*Allocator) ReleaseFailed

func (a *Allocator) ReleaseFailed(ctx context.Context, leaseID string, epoch int64, reason string) error

ReleaseFailed terminalizes a lease as failed and records why, in one transaction.

THE LISTENER'S OWN FAILURES GO THROUGH HERE. A launch that failed conclusively never held compute and archives at once, so nothing outlives a process here — the reason exists for the report, where a failure nothing explains is a row an operator cannot act on. Written in the release's own transaction so the archive copies it, and idempotent exactly as Release is: a lease already failed is left alone whatever it recorded, and a lease that finished as done is refused rather than rewritten. A reason already on the row stands, because the earlier fact is the one that can still have been causal.

func (*Allocator) RemoteCostNodes

func (a *Allocator) RemoteCostNodes(ctx context.Context) ([]config.RemoteCostNode, error)

RemoteCostNodes returns the declarations behind every registered REMOTE node's compute-cost ceiling. Registration survives liveness loss because the cloud resources and their potential bill do too.

EVERY REMOTE BACKEND, NOT JUST EC2, and the first version was scoped to `provider = 'ec2'`. A codebuild node declares ordered shapes with a price per hour for exactly the same reason an ec2 node does — placement charges the first that fits — so a deployment whose only cloud capacity was codebuild printed no cost line at all, which reads as a fleet that costs nothing. The set comes from config.RemoteProviders, so a third remote backend is included by the same allowlist that already decides how it is charged.

func (*Allocator) RequestComputeBarrier

func (a *Allocator) RequestComputeBarrier(
	ctx context.Context, generation int64, actor string,
) (ComputeBarrier, error)

RequestComputeBarrier records that somebody wants the fleet proved clear, and returns the barrier now in force.

IDEMPOTENT WITHIN A GENERATION. A second waiter under the same admission generation joins the existing barrier rather than minting one, because a new id resets every host's continuous-empty run and two waiters would otherwise starve each other indefinitely.

func (*Allocator) RequestEnrollment

func (a *Allocator) RequestEnrollment(ctx context.Context, name, fingerprint, csrPEM string) (Enrollment, error)

RequestEnrollment records a node asking to join, or returns what it was already told.

IDEMPOTENT FOR THE SAME KEY, because the node polls this until it is approved. A second request from the same fingerprint is the same request; one from a different fingerprint is a different machine claiming a taken name.

func (*Allocator) RequestEnrollmentWithToken

func (a *Allocator) RequestEnrollmentWithToken(
	ctx context.Context, name, fingerprint, csrPEM, token string,
) (Enrollment, error)

RequestEnrollmentWithToken records a request and spends the credential that authorised it, in ONE transaction.

SEPARATELY THEY ARE A TRAP. The token is single-use and the decrement is atomic on its own, but committing it and then failing to insert the request — a crash, a busy ledger — burns the credential with nothing to show for it. The machine retries, is treated as new because no row exists, and finds its token spent: stranded until an operator mints another and notices why.

THE TOKEN IS SPENT ONLY FOR A REQUEST THAT IS NEW. A node polls this endpoint until a human decides, so charging every call would spend a single-use token on the second poll and strand the machine it was minted for.

func (*Allocator) RequestForceDestroy

func (a *Allocator) RequestForceDestroy(
	ctx context.Context, req state.ForceDestroyRequest,
) (state.ForceDestroy, error)

RequestForceDestroy records an operator's decision to destroy running compute.

func (*Allocator) Reserve

func (a *Allocator) Reserve(ctx context.Context, tier string) (*Lease, error)

Reserve escrows capacity for one instance of a tier.

Call this BEFORE advertising to GitHub. The returned lease holds the capacity until it is released or expires, so a second Reserve sees a smaller machine.

func (*Allocator) Resize

func (a *Allocator) Resize(
	ctx context.Context, leaseID string, epoch int64, instanceType string,
	vcpu int, memory config.ByteSize,
) error

Resize authorises one remote shape before the node asks its API to buy it.

The first fitting shape is charged at escrow. A later fallback is a new purchase decision, so its larger resource vector must fit atomically before the launch request is allowed onto the wire.

IT SERVES EVERY REMOTE BACKEND, and it used to demand `ec2` by name. A codebuild lease reaching a fallback compute type would have been refused here — so the launch would fail rather than resize, which loses the fallback the ordered list exists for. Keyed on RunsOnHost for the same reason the registration branch is: a host-backed lease has no shape to resize, because its capacity IS the machine.

func (*Allocator) ResolveQuarantine

func (a *Allocator) ResolveQuarantine(ctx context.Context, leaseID string, outcome Phase) error

ResolveQuarantine terminalizes a quarantined lease, returning its capacity.

PROOF, OR AN OPERATOR SAYING SO. The node calls this when it has destroyed the container, or when it re-registers reporting an inventory the lease is not in; both are evidence the compute is gone. `--force` exists for the case evidence can never arrive in — a machine that is not coming back — because otherwise its capacity would be missing from the deployment permanently, and the ceiling is deployment-wide. THE OUTCOME IS THE CALLER'S, because they are not all the same event. A listener resolving one after a completion knows the job finished; a node cleaning up compute it could not account for, and an operator forcing a machine that is never coming back, both know the opposite. Recording every one of them as `failed` puts a lie in the history of a job GitHub reported completed — the same objection the launch path makes in reverse.

func (*Allocator) ResolveQuarantineFailed

func (a *Allocator) ResolveQuarantineFailed(ctx context.Context, leaseID, reason string) error

ResolveQuarantineFailed is ResolveQuarantine for a failure the caller can explain, recording the reason in the same transaction unless one is there.

THE LISTENER'S PARKED LAUNCH FAILURE MEETS THE REAPER when it gets to the lease before the retry does — quarantined if it had reached `launching`, failed outright if it was escrow alone — and resolving it through ResolveQuarantine archived a failure with nothing to explain it. Both rows are explained here. Same rule as ReleaseFailed: an earlier reason stands.

func (*Allocator) ResolveQuarantineFor

func (a *Allocator) ResolveQuarantineFor(
	ctx context.Context, node string, running []string, epoch int64,
) (int, error)

func (*Allocator) RetirePoolRunner

func (a *Allocator) RetirePoolRunner(ctx context.Context, leaseID string) error

RetirePoolRunner claims one member for teardown.

func (*Allocator) RetireRecoveredPoolRunner

func (a *Allocator) RetireRecoveredPoolRunner(
	ctx context.Context, runner PoolRunner,
) (PoolRunner, error)

RetireRecoveredPoolRunner claims only an idle or placeholder-busy recovery row. An authoritative JobStarted binding wins the same transaction race and is returned unchanged so recovery preserves its compute.

func (*Allocator) RevokeCert

func (a *Allocator) RevokeCert(ctx context.Context, serial, node, reason string) error

RevokeCert withdraws one certificate.

KEYED ON SERIAL, not on node name. A name is legitimately re-issued to a replacement machine, and revoking the name would refuse the replacement too. The serial identifies the one credential being taken back.

Idempotent: revoking twice is not an error, because an operator who is not sure whether the first attempt landed must be able to just run it again.

func (*Allocator) RevokeNode

func (a *Allocator) RevokeNode(ctx context.Context, node, reason string) ([]IssuedCert, error)

RevokeNode withdraws every credential a node currently holds, and reports what it took back.

THE HANDLE AN OPERATOR ACTUALLY HAS. Responding to a compromised machine means taking back everything that machine can present, and after a renewal that is not the bundle in their hands — it is a serial they have never seen. Revoking by serial from a file silently leaves the live credential working.

A replacement machine under the same name is unaffected: this revokes the serials outstanding right now, and a certificate issued afterwards is not one of them.

THE CUTOFF COMPARES TWO CLOCKS, and that is a real if narrow residual. The timestamps come from the certificate's own issuer and from this process, so a CA whose clock runs ahead can mint a credential shortly before a revocation that dates itself after the cutoff and escapes it. It only reaches certificates whose serials were never recorded — everything issued since this release is revoked by serial, where no clock is involved — so it is bounded to the legacy set the cutoff exists for, and a deployment that cannot enumerate its old certificates and does not trust its clocks should rotate the authority instead.

func (*Allocator) RevokedCerts

func (a *Allocator) RevokedCerts(ctx context.Context) ([]RevokedCert, error)

RevokedCerts lists what has been withdrawn, newest first.

func (*Allocator) RunningWithReplacedHolder

func (a *Allocator) RunningWithReplacedHolder(ctx context.Context) ([]ReplacedHolderLease, error)

RunningWithReplacedHolder lists every running-phase lease whose holding process is not the one its host registered with, oldest renewal first.

ON THE READ-ONLY POOL, because it answers a question an operator asks while the control plane is working, and a report must not reserve the writer slot.

func (*Allocator) ServiceableRunnerLeaseIDs

func (a *Allocator) ServiceableRunnerLeaseIDs(ctx context.Context, tier string) ([]string, error)

ServiceableRunnerLeaseIDs reports restart-surviving runner capacity that may still serve the scale set. Teardown and quarantine remain charged for safety but are cleanup obligations, not capacity GitHub may schedule against.

func (*Allocator) SettleCompletionOnTerminalLease

func (a *Allocator) SettleCompletionOnTerminalLease(
	ctx context.Context, leaseID string, leaseEpoch int64, outcome Phase,
) (bool, error)

SettleCompletionOnTerminalLease records GitHub's outcome against a lease that has ALREADY been settled by something else, and reports whether it was.

THE ONLY COMPLETION PATH THAT DOES NOT REACH THE HOLDER, and the narrowness is the safety argument. An earlier path let a completion terminalize an open quarantine from the plane's cached inventory snapshot, and that cache has no ordering relationship to the quarantine: a snapshot taken before a build became visible, never refreshed because every later listing failed, would settle the lease under a running build. So a completion whose holder is gone — replaced, or never replaced at all — settles NOTHING itself. It waits for the host's ordinary inventory reconciliation — a fresh observation, taken after the grace — or an operator's forced release to settle the lease, and then corrects a provisional verdict to the outcome GitHub reported. An open lease answers false, however old it is.

func (*Allocator) SettleForceTarget

func (a *Allocator) SettleForceTarget(
	ctx context.Context, generation int64, leaseID, disposition, detail string,
) error

SettleForceTarget records what became of one forced lease.

func (*Allocator) SettlePoolRunner

func (a *Allocator) SettlePoolRunner(ctx context.Context, tier string, requestID int64) error

SettlePoolRunner preserves the physical identity until GitHub acknowledges the completion that used it. A redelivery must resolve to the same compute even after teardown and capacity release have both completed.

func (*Allocator) SpendJoinToken

func (a *Allocator) SpendJoinToken(ctx context.Context, token string) error

SpendJoinToken checks a token and consumes one use.

CHECK AND DECREMENT IN ONE STATEMENT, so two machines racing on a single-use token cannot both be admitted: the UPDATE matches only while a use remains, and whichever commits second changes no rows.

func (*Allocator) StartPoolRunner

func (a *Allocator) StartPoolRunner(ctx context.Context, leaseID, tier string, runnerID int64,
	runnerName string, requestID, runID int64, jobID string,
) (PoolRunner, error)

StartPoolRunner durably binds a pool member to the job GitHub actually gave it.

func (*Allocator) Stranded

func (a *Allocator) Stranded(ctx context.Context, ids []string) ([]string, error)

Stranded reports which of these leases their target machine can no longer honour — because it is gone, or because it is no longer big enough.

FOR CAPACITY THAT HAS BEEN ADVERTISED BUT NOT USED. A listener holds escrow and tells GitHub about it; if the host those reservations name cannot keep them, the number is a promise nothing will honour, and the listener only ever ADDS to it. These are the ones it can safely take back.

TWO WAYS TO BE STRANDED, and only the first was handled. A host that DISAPPEARS is the obvious one. A host that SHRINKS is the same failure with a quieter cause: capacity is deliberately overwritten on re-registration, so an operator who halves node.max_vcpu and restarts leaves the ledger recording a machine smaller than the escrow already aimed at it. It stays perfectly live, so a liveness question returns nothing, and billet goes on advertising slots that will fail to launch on arrival.

ONLY THE EXCESS. Shedding every lease on an overcommitted host would give back capacity it can still honour, and the listener would immediately re-escrow it — advertisement flapping once per poll for as long as the host stayed small.

A lease with no target is NOT stranded. Every reservation names a machine now, so an empty target is a row from before that was true — and guessing that such a lease is worthless is exactly the kind of cleanup that deletes something real. It fails closed by being left alone.

func (*Allocator) Usage

func (a *Allocator) Usage(ctx context.Context) (Usage, error)

Usage reports what is currently held.

type AttributedFailure

type AttributedFailure struct {
	LeaseID string
	Tier    string
	Node    string
	RunID   int64
	// Result is GitHub's own word, stored verbatim. It reaches a report an
	// operator reads as billet's own output, so a renderer quotes it.
	Result string
	// Detail is the free-form failure reason recorded beside a reclaim, which is
	// text a NODE supplied. Quoted for the same reason.
	Detail      string
	Disruption  Disruption
	DisruptedAt string
	ResultAt    string
}

AttributedFailure is one job GitHub did not report as succeeded, on a lease billet's own infrastructure had disrupted.

TWO FACTS, NOT A VERDICT. Nothing here says the disruption caused the failure; billet cannot tell a broken host from a broken build, and the report that renders this has to say so. NO REQUEST ID. A lease's request id is billet's SCHEDULER identity, and for a pooled runner it is a negative synthetic one issued before GitHub chose the job — so it names a different thing from the run beside it and no report should pair the two. The lease is billet's handle; the run is GitHub's.

type BarrierObservation

type BarrierObservation struct {
	Node      string
	BarrierID string
	// Fence is what the caller captured BEFORE it asked. Both halves are compared
	// against the ledger inside the recording transaction.
	Fence NodeFence
	// Empty says the host read its provider and found no billet compute. A host
	// that could not read its provider, or that reported instances, is not empty
	// and its run is discarded.
	Empty bool
}

BarrierObservation is one host's fenced answer to "what are you running".

type CacheObservation added in v0.8.0

type CacheObservation struct {
	ImageCache      ImageCache   `json:"image_cache,omitempty"`
	CacheGeneration string       `json:"cache_generation,omitempty"`
	ActionsCache    ActionsCache `json:"actions_cache,omitempty"`
}

CacheObservation is what a node saw the cache do for one job. Either half may be empty, meaning that half has not been observed yet; a generation travels only with a warm image store.

func (CacheObservation) Validate added in v0.8.0

func (o CacheObservation) Validate() error

Validate refuses an observation billet must not write: an unknown token, a generation with no warm store to attribute it to, or nothing at all.

type ClearanceState

type ClearanceState int

ClearanceState is what billet can say about ONE host's compute.

THE ZERO VALUE IS NOT "PROVED", and that is the whole reason this is an enum rather than a bool beside a count. An earlier inventory shape paired a `Current bool` with a `Running int`, and the natural thing to write against it is `Current && Running == 0` — which is exactly the clearance nothing here may be turned into by accident.

const (
	// ClearanceUnknown is the fail-closed zero value.
	ClearanceUnknown ClearanceState = iota
	// ClearanceProved is a fenced, continuously empty run past the grace.
	ClearanceProved
	// ClearanceRunning is the host saying it IS running billet compute. The one
	// answer here worth acting on.
	ClearanceRunning
	// ClearanceSettling is an empty run that has not yet lasted long enough.
	ClearanceSettling
	// ClearanceWaiting is a host that has not given a fenced answer under this
	// barrier — it has not been asked yet, or its answer did not arrive.
	ClearanceWaiting
	// ClearanceUnreachable is a host this deployment cannot reach, so it cannot
	// be asked. It is NOT excluded: its compute may be running.
	ClearanceUnreachable
	// ClearanceBelowProtocol is a host whose registration negotiated a wire with
	// no inventory command. It can never answer, and must never be assumed.
	ClearanceBelowProtocol
)

func (ClearanceState) String

func (s ClearanceState) String() string

type ComputeBarrier

type ComputeBarrier struct {
	ID string
	// Generation is the admission generation this barrier was requested under.
	Generation  int64
	RequestedAt string
	RequestedBy string
}

ComputeBarrier is one durable request to prove the fleet is running nothing.

A SINGLETON, AND SCOPED TO AN ADMISSION GENERATION. `billet drain` is a separate process with no handle to the running plane, so the request has to be durable and observed rather than called. Concurrent waiters join one barrier id — superseding would reset the continuous runs the earlier waiter is already most of the way through — and a resume moves the generation, after which the request can no longer mean anything and the plane drops it.

type ComputeClearance

type ComputeClearance struct {
	// Requested says a durable barrier is in force. Without one, nothing here is
	// evidence of anything: no host has been asked.
	Requested  bool
	BarrierID  string
	Generation int64
	// AdmissionGeneration and AdmissionSealed are the ledger's admission read in
	// the SAME SNAPSHOT as everything else here.
	//
	// WITHOUT THEM A PROOF OUTLIVES THE SEAL IT WAS TAKEN UNDER. The plane drops
	// a barrier whose generation has moved, but that is asynchronous cleanup and
	// not a fence: between somebody resuming, taking work, and resealing, and the
	// plane's next pass, every host's run is still stored, still fenced by an
	// epoch and a dispatch generation nothing has moved, and would read as clear.
	// A drain would exit 0 against a deployment that was open in between.
	AdmissionGeneration int64
	AdmissionSealed     bool
	// Nodes is every EXPECTED host, ordered by name.
	Nodes []NodeClearance
	// Excluded is every host a person removed from that set.
	Excluded []Exclusion
}

ComputeClearance is the fleet's answer to "is anything still running".

SEPARATE FROM Quiescence, DELIBERATELY. That type means exactly "sealed, and no non-terminal ledger lease", and its comments already disclaim machine proof. Folding this into Quiet() would silently change what every existing caller of it is told.

func (ComputeClearance) Blocking

func (c ComputeClearance) Blocking() []NodeClearance

Blocking lists the expected hosts that are not proved clear, in the order a report should name them: what is running first.

func (ComputeClearance) Clear

func (c ComputeClearance) Clear() bool

Clear reports whether every expected host has been proved to be running nothing.

IT SAYS NOTHING ABOUT EXCLUSIONS, on purpose. An unproven exclusion cannot make this false without making a forced decommission useless, and it must not make it quietly true either — so it changes the SENTENCE a caller prints, through Unproven, rather than the boolean.

func (ComputeClearance) Stale

func (c ComputeClearance) Stale() bool

Stale reports that the barrier belongs to an admission generation the ledger has moved past, so nothing under it can mean anything any more.

func (ComputeClearance) Unproven

func (c ComputeClearance) Unproven() []string

Unproven names the hosts excluded from the expected set without proof.

type DecommissionRequest

type DecommissionRequest struct {
	Node  string
	Actor string
	// Force skips the checks a person is allowed to override — a host the
	// deployment can still reach, and the absence of proof. It never skips the
	// outstanding-lease check, which is about capacity rather than judgement.
	Force bool
}

DecommissionRequest is one decision to stop expecting a host to answer.

type Disruption

type Disruption string

Disruption names something billet's OWN infrastructure did to a lease while the job on it may still have been running.

A CLOSED VOCABULARY, and only billet's control plane ever writes one. It is an OBSERVATION rather than a verdict: nothing here says a job failed because of it, and nothing derives a conclusion from it on its own. What makes a disruption interesting is reading it beside GitHub's own result for the same job — see AttributedFailures — which is why the two are recorded separately and neither is stored as an answer.

const (
	// DisruptionNodeForgotten means this control plane stopped hearing from the
	// host the lease was running on and gave up on it.
	//
	// THE WEAKEST OF THE THREE, and it is here because nothing else covers the
	// case that motivated any of this: a host that vanishes mid-job never lets
	// its lease expire — the listener goes on renewing it — so it is never
	// quarantined and no inventory ever reports it absent. The bar is not a
	// blip: nodeplane forgets a host only after four consecutive poll windows of
	// silence, and never while it has a command in flight.
	DisruptionNodeForgotten Disruption = "node-forgotten"
	// DisruptionGuestAbsent means the host's own inventory, taken under the
	// registration this deployment is talking to, did not contain the lease's
	// guest after the quarantine grace. The compute is gone and billet did not
	// remove it.
	DisruptionGuestAbsent Disruption = "guest-absent"
	// DisruptionReclaimed means an external party told billet the machine was
	// being taken — today an EC2 Spot interruption warning. The strongest of the
	// three: billet was informed, about this exact fenced lease, before it began
	// tearing the guest down.
	DisruptionReclaimed Disruption = "reclaimed"
	// DisruptionHeldPastLimit means billet itself destroyed the job, because an
	// operator bounded how long compute may be held (node.WithMaxCustody) and
	// this job outlived the bound. The one disruption billet chooses rather
	// than observes, and it is recorded for the same reason the others are: the
	// build went red, and only billet knows why.
	DisruptionHeldPastLimit Disruption = "held-past-limit"
)

func (Disruption) Valid

func (d Disruption) Valid() bool

Valid reports whether this is a token billet may write.

EVERY NEW OBSERVATION GOES THROUGH the helpers below, which check this, so the closed set is enforced in one place rather than at each call site. The database carries no CHECK for it — see migration 35 — so this is the only thing standing between a typo and a token no report knows how to render.

AN ARCHIVE CARRY IS NOT A NEW OBSERVATION and is deliberately not checked: alloc.archive copies whatever the lease row already holds, which may be a token a NEWER binary wrote. Refusing it there would drop an observation on the floor to protect a vocabulary that is already on disk, so the reader is total instead.

type Enrollment

type Enrollment struct {
	Name        string
	Fingerprint string
	CSRPEM      string
	CertPEM     string
	State       string
	// Source is how this machine got in: `enrolled` (it asked and an operator
	// approved a fingerprint) or `issued` (an operator handed it a bundle).
	Source      string
	RequestedAt string
	DecidedAt   string
}

Enrollment is a machine asking to join, and what was decided.

type Exclusion

type Exclusion struct {
	Node string
	// Proven says whether the removal was authorised by a current clearance. An
	// UNPROVEN exclusion is billet admitting it does not know what is on that
	// machine, and a report that treats the two the same is what this exists to
	// prevent.
	Proven bool
	Actor  string
	At     string
}

Exclusion is a host a person removed from the expected set.

type ForceCandidate

type ForceCandidate struct {
	ID    string
	Tier  string
	Node  string
	Phase Phase
	// RunID is GitHub's workflow run, where the lease carries one. It is what
	// makes the diagnostic recognisable to the person whose build is about to be
	// failed — a lease id tells them nothing.
	RunID string
	// SchedulerRequest is billet's numeric scheduler identity, which is how a
	// listener finds this lease in its own escrow. It can be negative on the
	// direct-assignment path, so zero is the only value that means "none".
	SchedulerRequest int64
	Since            string
}

ForceCandidate is one lease a force-destroy could target.

type ForceReleaseResult

type ForceReleaseResult struct {
	Node    string
	Pending bool
}

ForceReleaseResult says whether capacity was returned immediately or the request was handed to a live custody holder.

type HeldLease

type HeldLease struct {
	ID             string
	Tier           string
	Node           string
	State          Phase
	VCPU           int
	Memory         config.ByteSize
	Since          string
	ForceRequested bool
	// Holder is the node process that took the obligation, beside what the
	// deployment knows about that host now.
	Holder Holder
}

HeldLease is capacity retained while compute has not been confirmed gone. State distinguishes a live node tending it from a lease whose holder vanished.

type Holder

type Holder struct {
	// Incarnation is the process that took the work, or empty when no process
	// recorded one.
	Incarnation string
	// NodeIncarnation is the process the host registered with most recently,
	// empty for a host that presented none, and NodeKnown says the ledger has a
	// row for the host at all.
	NodeIncarnation string
	NodeKnown       bool
	// NodeLive is whether this deployment can reach the host right now.
	NodeLive bool
	// NodeSeenAt is when the host's current registration was recorded — for a
	// replaced holder, when its replacement arrived.
	NodeSeenAt string
}

Holder names the node process a lease was given to, and whether it is still the process the deployment talks to.

A REPORT, NOT A VERDICT. A different incarnation says the process that took the work is not the one this host's commands reach — dead, or superseded and still draining what it holds. Which of those it is shows in whether the lease keeps being renewed, and that is the reaper's to decide: a lease nobody renews is quarantined within a TTL, and quarantine is what an operator can release.

INCARNATIONS, NOT EPOCHS. A node process mints one incarnation for its life; the registration epoch moves on every registration, and the same process registers again whenever a control plane restarts or forgets it. A report built on the epoch would call every surviving lease's holder replaced after an ordinary restart, which is exactly the accusation that gets a report ignored.

func (Holder) Replaced

func (h Holder) Replaced() bool

Replaced reports whether a different process has registered under the host's name since the holder took the work. False when either side is unknown, because "cannot tell" must not read as "replaced".

type ImageCache added in v0.8.0

type ImageCache string

ImageCache is what the guest's Docker image-store clone did, as the node saw it.

A CLOSED VOCABULARY AND AN OBSERVATION, like Disruption: it says what the cache did for one job and decides nothing. Recorded from what the node saw at the moment the guest asked, never from what the tier intended, because a field that says "warm" without saying who observed it is the could-not-tell collapse this repository keeps removing. The empty string means nothing was observed.

const (
	// ImageCacheWarm means the guest's image store was cloned from a published
	// generation, which CacheObservation.CacheGeneration names.
	ImageCacheWarm ImageCache = "warm"
	// ImageCacheCold means no generation existed for the store and a fresh volume
	// was created for the guest.
	ImageCacheCold ImageCache = "cold"
	// ImageCacheUnavailable means the site store failed and the job continued
	// with no image store at all.
	ImageCacheUnavailable ImageCache = "unavailable"
	// ImageCacheUnused means the cache session closed without the guest ever
	// asking for an image store.
	ImageCacheUnused ImageCache = "unused"
)

func (ImageCache) Valid added in v0.8.0

func (c ImageCache) Valid() bool

Valid reports whether this is a token billet may write.

type InventoryReport

type InventoryReport struct {
	// ReportedRunning is how many billet instances that snapshot contained.
	ReportedRunning int
	// ReceivedAt is when the CONTROL PLANE got the report, never when the host
	// took it.
	ReceivedAt string
}

InventoryReport is one host's own account of what it was running.

EVERY FIELD IS ABOUT A MOMENT THAT HAS PASSED. The node lists its provider and THEN posts, so ReceivedAt is when this control plane learned of a snapshot taken some time before — and a launch can be handed to that host immediately afterwards, which is why this cannot be turned into proof.

type IssuedCert

type IssuedCert struct {
	Serial   string
	Node     string
	Source   string
	NotAfter string
	IssuedAt string
}

IssuedCert is a credential this deployment handed out.

type JobPlacement added in v0.8.0

type JobPlacement struct {
	// Provider is the backend the lease ran on, empty for one that never bound.
	Provider config.ProviderKind
	// InstanceType is the shape placement bought, empty for a host-backed lease.
	InstanceType string
	// VCPU and Memory are what the lease was CHARGED: the shape for a remote
	// lease, the tier request for a host-backed one.
	VCPU   int
	Memory config.ByteSize
	// Site is the placed host's registered site at escrow.
	Site string
	// PriceUSDPerHour is the shape's price when it was charged. ZERO IS NOT A
	// PRICE: it is a host-backed lease that bought nothing, or a remote row
	// written before the price was recorded, and InstanceType tells the two
	// apart. A reader renders the second as unknown, never as $0.
	PriceUSDPerHour config.USDPerHour
	// ImageCache, CacheGeneration and ActionsCache are what the node observed.
	// Empty means nothing was observed; a token this binary does not recognise
	// is a newer binary's observation and is carried verbatim.
	ImageCache      ImageCache
	CacheGeneration string
	ActionsCache    ActionsCache
}

JobPlacement is what one lease was charged for and what the cache did, from the history row that outlives the lease.

type JoinToken

type JoinToken struct {
	Note      string
	Uses      int
	CreatedAt string
	ExpiresAt string
}

JoinToken is a short-lived credential that lets a machine ASK to enroll.

It admits nothing on its own: a request still waits for an operator to compare fingerprints. What it buys is that a stranger who can reach the port cannot fill the pending list, or take a name before the machine that should have it.

type Lease

type Lease struct {
	ID   string
	Tier string
	// Node is the node that actually bound this lease; empty until Bind.
	Node string
	// TargetNode is the node the lease is CONSTRAINED to by its tier's config.
	// Recorded at reserve time so placement survives a catalog change.
	TargetNode string
	// MacOSSlot records whether this lease consumes one of its host's macOS
	// guest licences. Stored rather than re-derived for the same reason.
	MacOSSlot bool
	// GuestOS is what this lease boots, recorded at reserve time so a tier
	// redefined underneath an in-flight lease cannot reclassify it. Bind checks
	// it against the target host's allowlist.
	GuestOS config.GuestOS
	// Provider is the backend the lease is ACTUALLY on, empty until it is bound.
	//
	// Chosen at Bind, from Providers. What a lease MAY run on is decided when it
	// is reserved; what it IS running on is only knowable once a host has taken
	// it.
	Provider config.ProviderKind

	// Providers is what the lease MAY run on, most preferred first, copied from the
	// tier when the lease was reserved.
	//
	// Copied rather than looked up: a tier's configuration can change while a lease is
	// open, and a placement decision has to be answerable from the lease itself.
	Providers []config.ProviderKind
	Phase     Phase
	// VCPU and Memory are what the lease is CHARGED. For an EC2 lease this is
	// the selected purchasable shape, which may be larger than the tier asked for.
	VCPU   int
	Memory config.ByteSize
	// RequestedVCPU and RequestedMemory are the tier's requirement. They stay
	// fixed while EC2 fallback may resize the charged shape around them.
	RequestedVCPU   int
	RequestedMemory config.ByteSize
	// InstanceType is the EC2 shape currently authorised for purchase. Empty for
	// backends whose charged resources are the requested resources.
	InstanceType string
	// Site is the placed host's registered site at escrow, recorded on the row
	// so the history a terminalization copies names where the job ran.
	Site string
	// PriceUSDPerHour is the charged shape's price at the moment it was
	// charged, written at escrow and again by a fallback resize. Zero for a
	// host-backed lease, which buys nothing. Never re-read from the node's
	// catalogue: a node may re-register with new prices while this lease is
	// open, and the history has to say what was bought.
	PriceUSDPerHour config.USDPerHour
	// ImageCache, CacheGeneration and ActionsCache are what the node observed
	// the cache do for this job, first observation kept. Empty means nothing
	// was observed; see CacheObservation.
	ImageCache      ImageCache
	CacheGeneration string
	ActionsCache    ActionsCache
	// PreferenceRank is the chosen target provider's position in the tier's
	// preference list. It orders unbound listener escrow so a shrink releases
	// fallback capacity before preferred capacity. Unbound capacity is not adopted
	// across a listener restart, so this runtime ordering fact is not persisted.
	PreferenceRank int
	// HeldSince is set when the lease enters custody or an unconfirmed teardown.
	HeldSince string
	// HolderIncarnation is the incarnation of the node process that last took
	// responsibility for the compute: the one that bound the lease, or the one
	// that moved it into custody or teardown. Empty means no process recorded
	// one. Compared with the node's current incarnation by reports, and by
	// nothing that decides capacity — see migration 45.
	HolderIncarnation string
	// ForceRelease asks the node holding custody to relinquish it. It is carried
	// by Heartbeat as ErrForceRelease rather than acted on behind the node's back.
	ForceRelease bool
	// FailureReason is an external fact that decided a running job cannot finish,
	// such as an EC2 Spot interruption warning. It is written before teardown so
	// recovery preserves why the lease will fail.
	FailureReason string
	// Disruption is what billet's OWN infrastructure did to this lease while its
	// job may still have been running, and DisruptedAt is when billet observed
	// it. Empty means nothing did.
	//
	// SEPARATE FROM FailureReason, and not interchangeable with it: a lease with
	// a failure reason is adopted as outcome=failed, discard=true — which
	// destroys a guest — while a disruption decides nothing at all and is only
	// ever read beside GitHub's own result for the job.
	Disruption  Disruption
	DisruptedAt string
	Epoch       int64
	RunID       int64
	RequestID   int64
}

Lease is a capacity reservation. The Epoch is the fencing token: every write must present it, and a reclaim bumps it so the previous holder's writes stop matching.

type LeaseClosure

type LeaseClosure struct {
	Known    bool
	Terminal bool
	// FinishedAt is when the ledger closed the lease, or zero when the history
	// row predates the column. A zero time is never old enough.
	FinishedAt time.Time
}

LeaseClosure is what the ledger knows about whether one lease is over.

THREE ANSWERS, NOT TWO. Known=false is a lease the ledger has never heard of; Terminal=false is one still open; Terminal=true is one that released its capacity, closed at FinishedAt. The caller that asks is the control plane's sweep of staged CodeBuild registrations, and only the third answer, aged past the service's own build ceilings, may authorise deleting one. Collapsing the first into the third would delete a registration for a lease this ledger cannot see — which is what a ledger restored from an older backup looks like.

type LeaseJob

type LeaseJob struct {
	Tier      string
	RunID     int64
	RequestID int64
}

LeaseJob is the GitHub identity assigned to one lease.

type Limits

type Limits struct {
	MaxVCPU   int
	MaxMemory config.ByteSize

	// Nodes is per-host policy keyed by node name. Build it with
	// config.Config.NodePolicies so the runtime checks and the load-time guard read
	// the same rules.
	//
	// A node absent from the map is unconstrained in guest OS and falls back to
	// config.DefaultMacOSVMLimit — the licence rather than "unlimited", so a mistyped
	// node name costs a scheduling constraint rather than a licence violation.
	Nodes map[string]config.NodePolicy
}

Limits is the global ceiling the allocator escrows against.

type NodeClearance

type NodeClearance struct {
	Node  string
	State ClearanceState
	// EmptySince is when the current continuous empty run began, or empty.
	EmptySince string
	// ClearAt is when that run crosses the grace, or empty.
	ClearAt string
	// WireVersion is what registration settled on, for the diagnostic a
	// ClearanceBelowProtocol host needs.
	WireVersion int
}

NodeClearance is what one host contributes to the fleet's answer.

type NodeFence

type NodeFence struct {
	// Epoch is the registration in force. A reconnect bumps it, which is what
	// makes a proof about a previous incarnation stop counting.
	Epoch int64
	// Dispatch is the launch-dispatch generation. A launch handed to this host
	// after the barrier was issued has already moved it.
	Dispatch int64
	// WireVersion is the protocol registration settled on, which decides whether
	// this host can be ASKED at all.
	WireVersion int
	// Live is whether the deployment could reach it when it last looked. It is
	// NOT part of the fence — see clearanceOf — and travels here only so one read
	// answers the whole question.
	Live bool
}

NodeFence is the pair a barrier observation has to be taken against.

type NodeInventory

type NodeInventory struct {
	Node string
	// Live is what the deployment believes about the host right now, which is a
	// different fact from anything in the report.
	Live bool
	// Report is what this host said under the registration the deployment is
	// talking to NOW, or nil if it has said nothing under it.
	//
	// A POINTER SO THE ABSENT CASE CANNOT BE READ AS A COUNT. An earlier shape
	// paired a Current bool with a Running int, and the natural thing to write
	// against that is `Current && Running == 0` — which is precisely the
	// clearance this must never be. There is no zero to reach for here without
	// first admitting the host said something.
	Report *InventoryReport
}

NodeInventory is one host's last word about what it was running.

IT IS TELEMETRY, NOT A VERDICT, and every field is shaped to keep it that way. The node lists its provider and THEN posts, so ReceivedAt is when the report arrived and never when the snapshot was taken, and a launch can be dispatched to that host immediately afterwards. A zero here is one host's opinion, already stale, about a question the ledger cannot answer.

type NodeRegistration

type NodeRegistration struct {
	// Name is what tiers pin to and what certificates authorise.
	Name string
	// Provider is the compute backend this host runs. A host is the authority on
	// this, which is why it is reported rather than read from a catalogue.
	Provider config.ProviderKind
	// Site is where this machine is, or empty for a deployment that has not
	// needed the distinction.
	Site string
	// VCPU and Memory are what this host CONTRIBUTES, which is not necessarily
	// what it has — see config.NodeConfig.Contribution.
	VCPU   int
	Memory config.ByteSize
	// EC2Shapes are the ordered shapes this node may buy, whatever its remote
	// backend calls them. Empty for a backend that runs work on its own host.
	//
	// The name is the wire's and the ledger column's; see nodeapi.RegisterRequest.
	EC2Shapes []config.RemoteShape
	// Incarnation is the value this node PROCESS minted for its whole life and
	// presents on every request, or empty for a host that presented none.
	//
	// RECORDED SO A LEASE CAN NAME ITS HOLDER. The registration epoch names a
	// registration, and the same process registers again after every
	// control-plane restart; this names the process. A lease copies it at Bind
	// and on entry to custody or teardown, and `billet leases` compares the two
	// to say whether the process holding a lease is the one the host runs now.
	// Nothing authorises anything from it.
	Incarnation string
	// CodeBuildFleet is the reserved-capacity fleet this node's builds run on, or
	// empty for on-demand compute.
	//
	// RECORDED AND ENFORCED, unlike Release and Digest beside it. A reserved fleet
	// is one shared pool, so two live nodes naming it each advertise all of it —
	// which is escrow promising GitHub twice what AWS will run, from two config
	// files neither of which is wrong alone. This is the only place both are
	// visible, so a duplicate is refused here.
	CodeBuildFleet string
	// CodeBuildJITPath and CodeBuildRegion are where this node stages each
	// build's single-use runner registration, and the region it does it in.
	//
	// RECORDED SO THE CONTROL PLANE CAN SWEEP THE PATH. A node that dies between
	// staging a registration and reaching any of the three places that remove one
	// leaks exactly one parameter, and from the provider alone "no build for this
	// lease" and "the build has not appeared yet" are the same observation. What
	// authorises the delete is the LEDGER (the lease terminal, and closed longer
	// ago than any build could still run), which only the control plane holds —
	// and it holds no node.codebuild block, so the path has to arrive here. Both
	// or neither: a path without a region cannot be reached and a region without
	// a path names nothing. Empty on a host that registered before it could say,
	// which `billet status` names rather than reads as swept.
	CodeBuildJITPath string
	CodeBuildRegion  string
	// Release is the node binary, and WireMin/WireMax the wire versions it said
	// it speaks. WireVersion is the one registration settled on.
	//
	// RECORDED, NOT ENFORCED. Nothing in placement or capacity reads these — they
	// exist so an operator can see which hosts still hold an old protocol open,
	// and so a later release knows when it may stop supporting one. Negotiation
	// has exactly ONE authority and it is the wire; a second opinion here would be
	// a second place for the fleet's version to be decided. Zero and empty mean
	// "not recorded" and are reported as unknown, which is what a host registered
	// before this existed leaves behind.
	Release string
	// Digest is the sha256 of the signed release manifest that produced this
	// host's binary, or empty when nothing on that machine can say.
	//
	// OVERWRITTEN ON EVERY REGISTRATION, like Release and for the same reason: the
	// answer to "what is this machine running" is whatever it just said, and
	// keeping an older value would leave a converged host reported against bytes
	// it has replaced.
	//
	// A CLAIM, LIKE EVERY OTHER FIELD HERE, and one that authorises nothing. What
	// it does is let a rollout tell a host that installed the manifest it decided
	// on from one that installed something else — where before there was only a
	// version string the two would have shared.
	Digest      string
	WireMin     int
	WireMax     int
	WireVersion int
}

NodeRegistration is what a host tells the ledger about itself.

A STRUCT RATHER THAN FIVE ARGUMENTS: two are strings meaning entirely different things and two are numbers that are not interchangeable, so positionally, transposing any pair compiles and produces a fleet that is wrong in a way that surfaces as bad placement rather than as an error.

type NodeWire

type NodeWire struct {
	Name string
	// Live is whether the deployment can reach this host. A host it cannot reach
	// still BLOCKS retirement of the protocol it last spoke: its compute may be
	// running, and it will come back speaking whatever it spoke before.
	Live bool
	// Release is the node binary, or empty for a host that registered before a
	// registration named one.
	Release string
	// Min and Max are the range the node said it speaks, and Negotiated is the
	// version registration chose. Zero means the row predates this being
	// recorded — never that the host speaks version zero.
	Min        int
	Max        int
	Negotiated int
	// Digest is the signed release manifest that produced this host's binary, or
	// empty when nothing on that machine could say.
	//
	// THREE STATES READ OFF TWO FIELDS. Empty with a wire below
	// nodeapi.VersionNodeDigest is a build that has no way to name one; empty at or
	// above it is a host billet did not install, or one whose record no longer
	// describes its binary. Neither is a disagreement, and `billet status` says
	// which is which rather than calling both unverified.
	Digest string
	// Epoch is the fencing token this host's CURRENT registration holds.
	//
	// IT IS THE ONLY CAUSAL EVIDENCE A ROLLOUT HAS about a host coming back.
	// Release and Live are both true of a node that never left and of one that
	// went away and returned on the same binary — so a rollout watching for a
	// rollback cannot tell "still draining" from "restored and running" without
	// something that provably postdates the instruction. A registration bumps
	// this; nothing else does.
	Epoch int64
	// HighestRelease is the newest release tag this host has ever registered
	// with, or empty for a host that has only ever named something that is not
	// one.
	//
	// A REPORT, NOT A RULE. A host whose Release is provably older than this
	// is running something older than it once did, which `billet status` says so
	// a person can decide whether that was a rollout's rollback or somebody's
	// hand. Refusing the registration would break the rollback the coordinator
	// infers from exactly that re-registration.
	HighestRelease string
}

NodeWire is what a host's registration said about its build, and the wire version this control plane settled on with it.

A VERDICT, WHICH IS WHY IT IS NOT PART OF NodeInventory. That type is one host's own account of what it was running — telemetry about a moment that has passed. This is a decision this control plane made at registration, and putting the two in one struct invites reading either as the other.

type Option

type Option func(*Allocator)

Option configures an Allocator.

func WithClock

func WithClock(now func() time.Time) Option

WithClock replaces the clock. Test-only in practice.

func WithLeaseTTL

func WithLeaseTTL(d time.Duration) Option

WithLeaseTTL sets how long a lease survives without a heartbeat.

func WithPlacement

func WithPlacement(p config.PlacementPolicy) Option

WithPlacement chooses how a reservation picks among equally preferred hosts.

Empty means pack, which is the safer failure: spreading strands capacity in fragments too small for a large tier, and a job that cannot be placed is worse than one that shares a disk.

type Outstanding

type Outstanding struct {
	ID    string
	Tier  string
	Node  string
	Phase Phase
	// RunID is GitHub's workflow run, where the lease carries one. It is what
	// makes a report about work recognisable to the person whose work it is.
	RunID string
	Since string
	// Deregistered says whether GitHub's runner registration has been removed.
	// A lease that still carries one is work GitHub can route to; one without is
	// compute billet is still destroying.
	Deregistered bool
}

Outstanding is one lease standing between a deployment and quiescence.

type Phase

type Phase string

Phase is a lease's position in its lifecycle. The values are constrained by a CHECK in the schema, so a typo cannot sit in the open-lease index forever.

const (
	// PhaseCapacity means capacity is escrowed and advertised, but GitHub has not
	// yet handed us a job.
	PhaseCapacity Phase = "capacity"
	// PhaseAssigned means GitHub assigned a job to this lease.
	PhaseAssigned Phase = "assigned"
	// PhaseLaunching means a node is bringing the instance up.
	PhaseLaunching Phase = "launching"
	// PhaseOnline means the runner registered with GitHub.
	PhaseOnline Phase = "online"
	// PhaseBusy means the runner is executing the job.
	PhaseBusy Phase = "busy"
	// PhaseCustody means the node is preserving compute it inherited or can no
	// longer manage as an ordinary running command. The capacity stays charged.
	PhaseCustody Phase = "custody"
	// PhaseTeardown means the node asked its backend to remove compute but has not
	// confirmed it stopped. It is the operator-visible proof obligation.
	PhaseTeardown Phase = "teardown"
	// PhaseQuarantine means a lease that had compute behind it stopped being
	// heartbeated, and the compute has not been confirmed gone.
	//
	// STILL CHARGED TO ITS HOST, which is the whole point. Terminalizing an
	// expired running lease frees the capacity at once while the container keeps
	// running until the node next sweeps, so another tier can escrow that slot in
	// between and two jobs land on a machine sized for one. Capacity reclaimed
	// late is recoverable; capacity handed out twice is not.
	//
	// It leaves only on PROOF: the node destroys the container and says so, or it
	// re-registers reporting an inventory this lease is not in. An operator can
	// force it for a machine that is never coming back, which is the one case
	// proof can never arrive for.
	PhaseQuarantine Phase = "quarantine"
	// PhaseDone and PhaseFailed are terminal and release capacity.
	PhaseDone   Phase = "done"
	PhaseFailed Phase = "failed"
)

func (Phase) Terminal

func (p Phase) Terminal() bool

Terminal reports whether a phase releases capacity.

type PoolRunner

type PoolRunner struct {
	LeaseID            string
	Tier               string
	LaunchRequestID    int64
	RunnerID           int64
	RunnerName         string
	Status             string
	ActualRequestID    int64
	RunID              int64
	JobID              string
	SourceAcknowledged bool
}

PoolRunner is one GitHub registration backed by one compute lease.

type QuarantinedLease

type QuarantinedLease struct {
	ID     string
	Tier   string
	Node   string
	VCPU   int
	Memory config.ByteSize
	Since  string
}

QuarantinedLease is capacity held because compute could not be confirmed gone.

type Quiescence

type Quiescence struct {
	// Sealed says whether the deployment is refusing new work. A deployment that
	// is quiet but open is not quiesced: the next poll may fill it.
	Sealed bool
	// Generation is the admission generation this snapshot saw.
	//
	// A WAITER NEEDS IT, and Sealed alone is not enough: between two samples
	// somebody can resume and seal again, and a waiter watching only the boolean
	// sees "sealed" both times and never learns that admission was open in
	// between — during which the deployment could have taken work. Comparing the
	// generation against the one the drain established turns that into something
	// observable.
	Generation int64
	// Outstanding is every lease short of terminal, oldest first.
	Outstanding []Outstanding
}

Quiescence is what a deployment is still holding.

WHAT IT COUNTS. A lease implies compute, or a registration GitHub can route to, or capacity a listener can still turn into either — and it implies none of those once it reaches a terminal phase. Everything short of terminal counts.

ESCROWED CAPACITY COUNTS, and an earlier version of this did not. The reasoning for excluding it was that such a lease holds no compute and carries no runner, which is true and is not the question: while the listener is alive it still ADVERTISES that lease, so GitHub can assign against it and the lease becomes running work with nothing having changed on the host and admission never having reopened. A barrier that samples before that transition reports quiet about a deployment that is about to start a job. Counting it is conservative in the only direction that is safe — a drain that waits too long costs patience, one that stops too early costs somebody's build.

It is REPORTED separately, because the two are different waits. Running work ends by finishing. Escrow ends when the listener releases it, which is what a sealed listener must do — until it does, a drain on a busy deployment waits on something no amount of patience resolves, and that is a gap in the listener rather than in this query.

WHAT IT CANNOT SEE, stated rather than claimed away: compute whose lease has already gone. A listener that loses a running lease keeps an in-memory obligation to destroy what it launched, and a launch whose lease was reclaimed can create compute it then fails to destroy. Neither is in the ledger, and neither survives a restart of the process holding it. The ordinary cases are covered — restart-adopted compute keeps its launching/online/busy/custody lease, and an out-of-contact holder becomes quarantine, which is counted — but a barrier built on the ledger cannot answer for compute the ledger never hears about again.

WHAT ANSWERS IT IS ComputeClearance, AND THIS TYPE IS DELIBERATELY UNCHANGED. That is a SECOND barrier — it asks each host what its provider is actually running and records the answer against a fence taken before the question — and folding it in here would silently change what every existing caller of Quiet() is told. The two are also ORDERED rather than independent: the compute barrier is meaningful only once this one holds nothing, because while a lease is open a launch may legitimately be dispatched and would discard whatever a host had proved.

func (Quiescence) Escrowed

func (q Quiescence) Escrowed() int

Escrowed counts outstanding leases that hold no compute yet — capacity a listener is advertising, or has promised to GitHub and cannot withdraw.

func (Quiescence) Quiet

func (q Quiescence) Quiet() bool

Quiet reports whether a drain may stop waiting.

func (Quiescence) RegistrationUnconfirmed

func (q Quiescence) RegistrationUnconfirmed() int

RegistrationUnconfirmed counts outstanding leases whose GitHub registration has not been confirmed removed.

NAMED FOR WHAT THE FLAG PROVES, which is less than "GitHub can route here": `deregistered` records that a RemoveRunner call succeeded, so an unset flag covers a lease that never registered at all — an assigned lease, an early launch, an ambiguous pre-registration custody. Calling that "routable" would tell an operator something stronger than billet knows.

type RegisteredNode

type RegisteredNode struct {
	Name     string
	Provider config.ProviderKind
	Site     string
	Live     bool
	// Decommissioned is when a person stopped expecting this host to answer, or
	// empty. DecommissionProven says whether anything proved it was running no
	// compute at the time — an unproven exclusion is billet admitting it does not
	// know what is on that machine, and a report that renders the two the same is
	// what the whole membership rule exists to prevent.
	Decommissioned     string
	DecommissionProven bool
	DecommissionedBy   string
}

RegisteredNode is the durable placement identity of one compute host.

type RegistrationPath

type RegistrationPath struct {
	Node   string
	Region string
	// Path is empty for a host that registered before it could name one, which
	// the caller reports as unswept rather than treating as clean.
	Path string
	// Decommissioned says an operator has taken the host out of the fleet. Its
	// path is still swept: the registrations a dead node left behind are exactly
	// the ones nobody is left to remove.
	Decommissioned bool
}

RegistrationPath is one codebuild host and the Parameter Store path it stages runner registrations under.

type ReplacedHolderLease

type ReplacedHolderLease struct {
	ID          string
	Tier        string
	Node        string
	State       Phase
	VCPU        int
	Memory      config.ByteSize
	LastRenewed string
	Holder      Holder
}

ReplacedHolderLease is a lease in a running phase whose host has registered again since the process holding it was given the work.

THE SHAPE AN OPERATOR ONCE HAD NOTHING TO READ ABOUT. Such a lease is charged and is listed as held by nobody: its process is dead or superseded, and until it stops being renewed the reaper cannot quarantine it. It is reported so an operator can see WHY a slot is taken, and so that "stops being renewed" can be watched for rather than inferred.

type RevokedCert

type RevokedCert struct {
	Serial    string
	Node      string
	Reason    string
	RevokedAt string
}

RevokedCert is a credential that has been withdrawn.

type Usage

type Usage struct {
	VCPU   int
	Memory config.ByteSize
	Leases int
}

Usage is the vector of what is currently held.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL