mesh/merge-gate head c79591531575 merged into trunk aa02e7bf4e78 — pass: builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step; every …
mesh/repo-check head c79591531575 merged into trunk aa02e7bf4e78 — pass: its merge-check.sh passed
mesh/delivery delivered
Milestone 5 moved 8,599 build records onto the bus under bare build ids, each carrying its module's whole manifest. Every build lookup then read the whole bucket, and a delivery plan's send did that per module per machine while it held the plans and the machine's declaration: the send of build-agent never finished, and every other act and the status waited behind it. Builds now live under <module>.build.<id> (requests under req.<id>, id.<id> names a build's module), with pointer keys newest, worked, held, commit.<sha> and source.<reuse key> that move only to a newer build and are read as hints, repaired when wrong. Manifests are kept once in the same bucket under manifest.sha256-<hex>, so no grant the running bus lacks is needed. The old keys are laid out once at start, idempotently, and left unread. The calls a plan look makes on the silent clocks while it holds the plans are bounded, since the vendored kv.Keys ignores its context.
204 lines
9.3 KiB
Go
204 lines
9.3 KiB
Go
// Package chain keeps the controller's chain on the bus alone (novox/hq ADR 0408, design 47): module, commit, build,
|
|
// published artifact or package, rollout and assignment are one chain, a bucket each of the bus's key-value store,
|
|
// each the only source of its kind, written by the controller that holds the lease by compare-and-set.
|
|
//
|
|
// **No key is removed.** A Backend has no delete and no purge (ADR 0408 §4): an assignment of a module taken off its
|
|
// node is kept, saying so. **A value is never cut** (§6): one over the largest the bus holds is refused, and the key
|
|
// stays as it was. **Each key keeps its earlier values** (§5), read back with History.
|
|
package chain
|
|
|
|
import (
|
|
"encoding/json"
|
|
"time"
|
|
)
|
|
|
|
// Ref names a build and the commit it was made from: one end of a change.
|
|
type Ref struct {
|
|
Build string `json:"build,omitempty"`
|
|
Commit string `json:"commit,omitempty"`
|
|
}
|
|
|
|
// Package is a release a build published to the package registry.
|
|
type Package struct {
|
|
Name string `json:"name"`
|
|
Version string `json:"version"`
|
|
}
|
|
|
|
// Published is what a build published: an artifact by its digest, or a package release by name and version.
|
|
type Published struct {
|
|
Artifact string `json:"artifact,omitempty"`
|
|
Package *Package `json:"package,omitempty"`
|
|
}
|
|
|
|
// Artifact is one thing a build made.
|
|
type Artifact struct {
|
|
Name string `json:"name"`
|
|
Kind string `json:"kind"`
|
|
Reference string `json:"reference"`
|
|
}
|
|
|
|
// ReadRepository is a repository a build read source from besides the module's own.
|
|
type ReadRepository struct {
|
|
Repository string `json:"repository"`
|
|
Ref string `json:"ref,omitempty"`
|
|
Paths []string `json:"paths,omitempty"`
|
|
Own bool `json:"own,omitempty"`
|
|
}
|
|
|
|
// Source is the build source a build read in one repository.
|
|
type Source struct {
|
|
Repository string `json:"repository,omitempty"`
|
|
Ref string `json:"ref,omitempty"`
|
|
Paths []string `json:"paths"`
|
|
}
|
|
|
|
// The states of a build record. A record in state asked is a request that no outcome has answered (issue 1091); one
|
|
// without a state is an outcome, and keeps the Request it was asked with.
|
|
const BuildAsked = "asked"
|
|
|
|
// The states of a request's Reask.
|
|
const (
|
|
ReaskPending = "pending"
|
|
ReaskClaimed = "claimed"
|
|
)
|
|
|
|
// Request is a build as it was asked for (novox/hq issue 325, ADR 0408 §1): kept in the build's own record under its id,
|
|
// first alone as state asked and then beside the outcome that answered it.
|
|
type Request struct {
|
|
// Repository and Seat are the source as the mesh spells it; Path is the module's directory in it, Ref the branch or
|
|
// commit asked, and Commit the commit that made the ask, where one did.
|
|
Repository string `json:"repository,omitempty"`
|
|
Seat string `json:"seat,omitempty"`
|
|
Path string `json:"path,omitempty"`
|
|
Ref string `json:"ref,omitempty"`
|
|
Commit string `json:"commit,omitempty"`
|
|
// For says who asked: merge, plan, build (a person), assign.
|
|
For string `json:"for,omitempty"`
|
|
// NotAsked is why the ask could not be handed over; OutcomeUnknown why an asker that handed it over stopped waiting.
|
|
NotAsked string `json:"not-asked,omitempty"`
|
|
OutcomeUnknown string `json:"outcome-unknown,omitempty"`
|
|
At time.Time `json:"at,omitzero"`
|
|
AtTerminal bool `json:"at-terminal,omitempty"`
|
|
// Reask is, on a request the move found never handed over, "pending" until the controller asks it again, "claimed"
|
|
// while it does, and the build id it was asked as once it has: published once, never twice (issue 981 note 7 Q5).
|
|
Reask string `json:"reask,omitempty"`
|
|
}
|
|
|
|
// Build is one attempt, whichever way it went, kept under its id. It names its module, its repository and commit, its
|
|
// reuse key (novox/hq ADR 0350) and what it published (ADR 0408 §1).
|
|
type Build struct {
|
|
ID string `json:"id"`
|
|
State string `json:"state,omitempty"`
|
|
Repository string `json:"repository"`
|
|
Ref string `json:"ref,omitempty"`
|
|
Module string `json:"module,omitempty"`
|
|
Commit string `json:"commit,omitempty"`
|
|
On string `json:"on,omitempty"`
|
|
Path string `json:"path,omitempty"`
|
|
Manifest json.RawMessage `json:"manifest,omitempty"`
|
|
// ManifestDigest names the manifest in the manifests bucket (ManifestKey); a record that has it keeps no Manifest.
|
|
ManifestDigest string `json:"manifest-digest,omitempty"`
|
|
Against []string `json:"against,omitempty"`
|
|
Mirrored []string `json:"mirrored,omitempty"`
|
|
Read []ReadRepository `json:"read,omitempty"`
|
|
Sources []Source `json:"sources,omitempty"`
|
|
SourceFingerprint string `json:"source-fingerprint,omitempty"`
|
|
Failed string `json:"failed,omitempty"`
|
|
Made []Artifact `json:"made,omitempty"`
|
|
Asked time.Time `json:"asked,omitzero"`
|
|
At time.Time `json:"at,omitzero"`
|
|
ReuseKey string `json:"reuse-key,omitempty"`
|
|
Published *Published `json:"published,omitempty"`
|
|
Request *Request `json:"request,omitempty"`
|
|
}
|
|
|
|
// Commit is one repository's commit a rollout carries.
|
|
type Commit struct {
|
|
Repository string `json:"repository"`
|
|
Branch string `json:"branch,omitempty"`
|
|
Commit string `json:"commit"`
|
|
Merged time.Time `json:"merged,omitzero"`
|
|
}
|
|
|
|
// Change is one assignment a rollout changed: the build and commit it ran before and the ones it runs after.
|
|
type Change struct {
|
|
Node string `json:"node"`
|
|
Module string `json:"module"`
|
|
Before Ref `json:"before"`
|
|
After Ref `json:"after"`
|
|
}
|
|
|
|
// Step is one tier sent to one machine.
|
|
type Step struct {
|
|
Tier int `json:"tier"`
|
|
Node string `json:"node"`
|
|
Sent *time.Time `json:"sent,omitempty"`
|
|
Reported *time.Time `json:"reported,omitempty"`
|
|
}
|
|
|
|
// Links are the fields a rollout gains on the chain: the builds it carried, the machine steps it has taken and the
|
|
// assignments it changed, each with the build before and after. The controller's plan embeds them, so the plan's own
|
|
// fields and these are one value (ADR 0408 §1).
|
|
type Links struct {
|
|
Builds []string `json:"builds,omitempty"`
|
|
Steps []Step `json:"steps,omitempty"`
|
|
Changed []Change `json:"changed,omitempty"`
|
|
}
|
|
|
|
// HeldMerge is a merge a rollout holds: the columns the controller's table of batched merges had, kept in the record of the
|
|
// batch or walk that answers it (novox/hq ADR 0276, issue 1092). A merge no plan answers (Waiting) stays in the record
|
|
// that held it last. Placed is when it entered this record, so one found in two records after a crash between the two
|
|
// writes is read from the one it entered last.
|
|
type HeldMerge struct {
|
|
Repository string `json:"repository"`
|
|
Branch string `json:"branch,omitempty"`
|
|
Commit string `json:"commit"`
|
|
Merged time.Time `json:"merged,omitzero"`
|
|
Heard time.Time `json:"heard,omitzero"`
|
|
Event json.RawMessage `json:"event,omitempty"`
|
|
Alone bool `json:"alone,omitempty"`
|
|
Waiting bool `json:"waiting,omitempty"`
|
|
Placed time.Time `json:"placed,omitzero"`
|
|
}
|
|
|
|
// Rollout is the controller's record of one batch's delivery, kept under the batch's id: the commit it fixed per
|
|
// repository, its tiers, the builds it carried and the assignments it changed (ADR 0408 §1). The controller's plan
|
|
// carries more (its modules, its times, its backups) beside these, under the same key.
|
|
type Rollout struct {
|
|
ID string `json:"id"`
|
|
State string `json:"state,omitempty"`
|
|
Commits []Commit `json:"commits,omitempty"`
|
|
Tiers [][]string `json:"tiers,omitempty"`
|
|
Links
|
|
}
|
|
|
|
// Assignment is one module on one node, kept under `<node>.<module>`. The first five fields are the ones its readers
|
|
// have always read, with the names they have always had (novox/hq ADR 0408 §3); the rest name the chain: the build, the
|
|
// artifact (by digest) or the package it runs, its commit, the rollout that put it there and since when.
|
|
type Assignment struct {
|
|
Node string `json:"node"`
|
|
Module string `json:"module"`
|
|
Assigned time.Time `json:"assigned,omitzero"`
|
|
RequiredBy string `json:"required-by,omitempty"`
|
|
Provisioning json.RawMessage `json:"provisioning,omitempty"`
|
|
|
|
Build string `json:"build,omitempty"`
|
|
Artifact string `json:"artifact,omitempty"`
|
|
Package *Package `json:"package,omitempty"`
|
|
Commit string `json:"commit,omitempty"`
|
|
Rollout string `json:"rollout,omitempty"`
|
|
Since time.Time `json:"since,omitzero"`
|
|
|
|
// Ended is when the assignment ended (an unassignment): absent while it stands. **No key of the chain is removed**
|
|
// (ADR 0408 §4), so an unassigned module keeps its key, saying so; every reader treats a value with Ended, or with a
|
|
// State, as no assignment. State is, in a later delivery, the pending assignment waiting for its build (issue 1094).
|
|
Ended time.Time `json:"ended,omitzero"`
|
|
State string `json:"state,omitempty"`
|
|
}
|
|
|
|
// Stands says the value is an assignment that holds: it has not ended and is not waiting in a state of its own.
|
|
func (a Assignment) Stands() bool { return a.Ended.IsZero() && a.State == "" }
|
|
|
|
// Key is an assignment's key.
|
|
func (a Assignment) Key() string { return a.Node + "." + a.Module }
|