Files
mesh-controller/internal/inventory/mirrors.go
T
mesh-tools 97a2d841c7 Land feature 57's controller work on its release branch
The controller plans config, templates and moved providers' provisions,
hands bus accounts to the vault and judges the new manifest words, on the
feature's SDK and node-engine validator (feature 57, config and provisioning).
2026-10-15 21:27:33 +00:00

205 lines
8.4 KiB
Go

package inventory
import (
"bytes"
"context"
"encoding/json"
"fmt"
"time"
)
// The values of the controller's record mirrors, built from the store (novox/hq ADR 0289, design 54 §1,
// design 57 package F3).
//
// **Each value is built from a named list of fields, and nothing else** (design 54 §1): no epoch, no time
// of writing and no time of the last look, so any lease holder builds the same bytes from the same record
// and a pass over unchanged records writes nothing (ADR 0289 §1, §4). The encoding is fixed: the fields in
// their struct's order, a declaration's maps sorted.
// AssignmentMirrored is one assignment as the assignments mirror holds it: the module, the node, and since
// when it is assigned there. Design 54 §1 also lists whether it is pending, the builds sent and running and
// the seats and provisions it holds there; those join with issue 419, which builds the rest of design 54.
type AssignmentMirrored struct {
Node string `json:"node"`
Module string `json:"module"`
Assigned time.Time `json:"assigned,omitzero"`
// RequiredBy is, for a module only pulled in by another and handed to the provisioner on this node (issue 765),
// the module that requires it there; such a value has no time assigned. Absent for an assignment.
RequiredBy string `json:"required-by,omitempty"`
// Provisioning is the plan of a module handed to the provisioner on this node (novox/hq ADR 0349 clause 4,
// design 57 P5): absent for every other, so their values are the bytes they were.
Provisioning *Provisioning `json:"provisioning,omitempty"`
}
// DeclaredConfigMirrored is one registered module's config declarations as the declared-config mirror holds
// them: the module, and each key its manifest declares — under `config`, or under its old name `settings` for a
// module not yet moved (ADR 0348 §1) — with that declaration's listed fields. An empty object when the module
// declares none: registered, declaring nothing.
type DeclaredConfigMirrored struct {
Module string `json:"module"`
Settings map[string]DeclaredMirrored `json:"settings"`
}
// DeclaredMirrored is one key's declaration as the mirror holds it: **its listed fields and no other**
// (ADR 0289 §12), and every field a declaration has (catalogue.SettingDeclaration), under the same names. The
// mirror holds what the module's manifest declares about its config values, and mesh-config validates and
// resolves from it (ADR 0356 §4, ADR 0348 §4, §9), so it carries the whole declaration: kind, default and why
// of the settings form, and type, description, validation, trusted, predefined, required and runtime of the
// config form. None is a secret: a secret lives in the vault, never in config, and the catalogue refuses a
// default for a key whose name says secret. A field the manifest gains reaches the bus only once it is added
// here, deliberately: a test fails until it is listed. The config form's fields are left out when unset, so a
// module not yet moved is mirrored as it was before they were carried.
type DeclaredMirrored 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"`
}
// DeclaredMirroredFields are the fields of a declaration the mirror carries, by their manifest names.
var DeclaredMirroredFields = []string{"kind", "default", "why", "type", "description", "enum", "minimum", "maximum",
"pattern", "trusted", "predefined", "required", "runtime"}
// AssignmentsMirror is every assignment's mirrored value, keyed `<node>.<module>`, with the provisioner's plan of
// each assignment of a module handed to it, and a value of its own for each module handed to it on a node that
// nothing assigned there, only pulled in by another (issue 765).
func (i *Inventory) AssignmentsMirror(ctx context.Context) (map[string][]byte, error) {
var plans map[string]Provisioning
if i.provisioningPlans != nil {
var err error
if plans, err = i.provisioningPlans(ctx); err != nil {
return nil, fmt.Errorf("composing the provisioner's plans: %w", err)
}
}
assignments, err := i.assignmentsMirrored(ctx)
if err != nil {
return nil, err
}
return AssignmentValues(assignments, plans)
}
func (i *Inventory) assignmentsMirrored(ctx context.Context) ([]AssignmentMirrored, error) {
rows, err := i.store.Pool().Query(ctx,
`select n.name, a.module, a.assigned from assignment a join node n on n.id = a.node`)
if err != nil {
return nil, err
}
defer rows.Close()
var out []AssignmentMirrored
for rows.Next() {
var a AssignmentMirrored
if err := rows.Scan(&a.Node, &a.Module, &a.Assigned); err != nil {
return nil, err
}
a.Assigned = a.Assigned.UTC()
out = append(out, a)
}
return out, rows.Err()
}
// DeclaredConfigMirror is every registered module's mirrored config declarations, keyed by the module.
func (i *Inventory) DeclaredConfigMirror(ctx context.Context) (map[string][]byte, error) {
rows, err := i.store.Pool().Query(ctx,
`select name, coalesce(manifest->'config', manifest->'settings', '{}'::jsonb) from module`)
if err != nil {
return nil, err
}
defer rows.Close()
out := map[string][]byte{}
for rows.Next() {
var (
d DeclaredConfigMirrored
raw []byte
)
if err := rows.Scan(&d.Module, &raw); err != nil {
return nil, err
}
if d.Settings, err = declaredMirrored(raw); err != nil {
return nil, fmt.Errorf("the declarations of %s cannot be read: %w", d.Module, err)
}
value, err := json.Marshal(d)
if err != nil {
return nil, err
}
out[d.Module] = value
}
return out, rows.Err()
}
// declaredMirrored is a manifest's config declarations, keyed by the value, as the mirror holds them: each
// with its listed fields, a default and an enum encoded the one way.
func declaredMirrored(raw []byte) (map[string]DeclaredMirrored, error) {
var declared map[string]DeclaredMirrored
if err := json.Unmarshal(raw, &declared); err != nil {
return nil, err
}
out := map[string]DeclaredMirrored{}
for key, decl := range declared {
var err error
if len(decl.Default) > 0 {
if decl.Default, err = canonical(decl.Default); err != nil {
return nil, err
}
}
if len(decl.Enum) > 0 {
if decl.Enum, err = canonical(decl.Enum); err != nil {
return nil, err
}
}
out[key] = decl
}
return out, nil
}
// canonical is a JSON document encoded the one way: objects' keys sorted, numbers as written.
func canonical(raw []byte) ([]byte, error) {
dec := json.NewDecoder(bytes.NewReader(raw))
dec.UseNumber()
var v any
if err := dec.Decode(&v); err != nil {
return nil, err
}
return json.Marshal(v)
}
// PredefinedMirrorKey is the predefined-keys mirror's one key: the list kept is one record.
const PredefinedMirrorKey = "list"
// PredefinedMirrored is the list of predefined keys kept as its mirror holds it (design 57 K3, issue 662): the
// keys, canonical, and the trunk build of the catalogue they came from, by its commit and generation, so a reader
// says which list it holds. Not when it was kept: any lease holder builds the same bytes from the same record.
type PredefinedMirrored struct {
Keys json.RawMessage `json:"keys"`
Repository string `json:"repository"`
Commit string `json:"commit"`
Generation int `json:"generation"`
Build string `json:"build"`
}
// PredefinedMirror is the list of predefined keys kept, under PredefinedMirrorKey; no key while none is kept.
func (i *Inventory) PredefinedMirror(ctx context.Context) (map[string][]byte, error) {
kept, has, err := i.PredefinedKept(ctx)
if err != nil || !has {
return map[string][]byte{}, err
}
keys, err := kept.Keys.Canonical()
if err != nil {
return nil, err
}
value, err := json.Marshal(PredefinedMirrored{Keys: keys, Repository: kept.Repository, Commit: kept.Commit,
Generation: kept.Generation, Build: kept.Build})
if err != nil {
return nil, err
}
return map[string][]byte{PredefinedMirrorKey: value}, nil
}