package delivery import ( "encoding/json" "fmt" "strings" "time" ) // **The control records' layouts, out of the controller** (novox/hq ADR 0565 clauses 2, 3 and 6; issue 1953 L5-S2): what // the indexer keeps of the catalogue's predefined list and of each open pull request's config declarations, which // mesh-config reads in place of the controller's mirrors and `pull-declares`; and each node's declared packages, which // its engine writes in place of the controller's mirror. // The indexer's two states (clause 2). const ( // IndexerPredefinedState holds one key, PredefinedListKey: the catalogue's predefined.json at the newest merge taken. IndexerPredefinedState = "predefined" PredefinedListKey = "list" // IndexerConfigCandidatesState holds one key per open pull request (ConfigCandidateKey). IndexerConfigCandidatesState = "config-candidates" ) // PredefinedKept is the indexer's key `predefined.list`: the list whole, as predefined.json holds it, with the merge it // was read at. A merge older than the one the key names never replaces it (ADR 0348 §7). type PredefinedKept struct { V int `json:"v"` Commit string `json:"commit"` At time.Time `json:"at"` List json.RawMessage `json:"list"` } // ConfigDeclaration is one config key a module's manifest declares, in the layout of the controller's declared-config // mirror (mesh-controller internal/inventory DeclaredMirrored) unchanged, so mesh-config reads the indexer's as it read // the mirror's. type ConfigDeclaration struct { Kind string `json:"kind"` Default json.RawMessage `json:"default"` Why string `json:"why"` Type string `json:"type,omitempty"` Description string `json:"description,omitempty"` Enum json.RawMessage `json:"enum,omitempty"` Minimum *float64 `json:"minimum,omitempty"` Maximum *float64 `json:"maximum,omitempty"` Pattern string `json:"pattern,omitempty"` Trusted bool `json:"trusted,omitempty"` Predefined string `json:"predefined,omitempty"` Required bool `json:"required,omitempty"` Runtime bool `json:"runtime,omitempty"` } // ConfigCandidate is one open pull request's key of `config-candidates`: its head, and per module the config // declarations the head's manifests add or change against the trunk's, an empty set when none. Written at each new // head and each trunk merge that changes a module it names; deleted when the pull request merges or closes. type ConfigCandidate struct { V int `json:"v"` Pull string `json:"pull"` Head string `json:"head"` Declares map[string]map[string]ConfigDeclaration `json:"declares"` At time.Time `json:"at"` } // ConfigCandidateKey is a pull request's key, `owner/repository#number` with `/` and `#` as dots, the form mesh-config // keeps a pull request's values under. func ConfigCandidateKey(pull string) (string, error) { owner, rest, ok := strings.Cut(strings.TrimSpace(pull), "/") repo, number, ok2 := strings.Cut(rest, "#") if !ok || !ok2 || owner == "" || repo == "" || number == "" || strings.ContainsAny(owner+repo+number, ".*> ") { return "", fmt.Errorf("delivery: %q is not a pull request, owner/repository#number", pull) } return owner + "." + repo + "." + number, nil } // The node-engine's packages (clause 6): its state `packages`, one key, the node's name, written by that node's engine // alone. const EnginePackagesState = "packages" // PackageDeclared is one package a node's modules declare, the controller's declared-packages mirror's entry unchanged // (mesh-controller internal/inventory PackageDeclared): its name, the modules that declare it that way, sorted, and // whether they declare it absent. type PackageDeclared struct { Package string `json:"package"` Modules []string `json:"modules"` Absent bool `json:"absent"` } // DeclaredPackages is one node's key of `packages`, the mirror's value unchanged: its packages sorted by name, absent // after present. Fixed fields and no time, so the same declaration is the same bytes (ADR 0289 §1). type DeclaredPackages struct { Node string `json:"node"` Packages []PackageDeclared `json:"packages"` } // mesh-config's state of the approved values held for a pull request (novox/hq ADR 0565 clause 5): read by the checker // and the assigner's composition check, which lay a pull request's own held values over its modules' values. const ( MeshConfigKeptState = "kept" MeshConfigKeptRead = "mesh-config." + MeshConfigKeptState ) // KeptValue is one approved held value, mesh-config's layout unchanged (modules/mesh-config pulls.go): kept apart from // the values mesh-config resolves, laid only over the composition of its own pull request at its head. type KeptValue struct { Pull string `json:"pull"` Head string `json:"head"` Digest string `json:"declaration"` Node string `json:"node"` Module string `json:"module"` Key string `json:"key"` // Value is the value held, as the operator approved it. Value json.RawMessage `json:"value"` By string `json:"by"` Via string `json:"via"` Why string `json:"why"` // Approved is who approved it, as the proposal kept it. Approved string `json:"approved"` Proposal string `json:"proposal"` At time.Time `json:"at"` } // HeldValueKey is a held value's key in `kept`: the pull request's key (ConfigCandidateKey's form), the node, the module and // the config key, joined by dots, as mesh-config writes it. func HeldValueKey(pull, node, module, key string) (string, error) { p, err := ConfigCandidateKey(pull) if err != nil { return "", err } return p + "." + node + "." + module + "." + key, nil } // The assigner's state of a person's upgrade policy, one key per module (clause 7; catalogue.PersonPolicy). const AssignerPoliciesState = "policies"