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"` } // 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 `.`. func (i *Inventory) AssignmentsMirror(ctx context.Context) (map[string][]byte, 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() out := map[string][]byte{} 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() value, err := json.Marshal(a) if err != nil { return nil, err } out[a.Node+"."+a.Module] = value } 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) }