154 lines
8.5 KiB
Go
154 lines
8.5 KiB
Go
// Command mesh-delivery-view-tools serves the read tools of the indexer's modules (novox/hq issue 1562): the runtime launches it for a
|
|
// call, it reads the indexer's modules bucket through the view's reads (mesh-delivery-indexer.modules) and writes nothing.
|
|
// The view is the other program: the indexer serves no tool (ADR 0437 §4).
|
|
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
stdio "git.novox.be/novox/mesh-sdk/go"
|
|
"mesh-delivery-view/internal/view"
|
|
)
|
|
|
|
// Tools are the read tools over a modules state.
|
|
func Tools(r view.Reader) []stdio.Tool {
|
|
return []stdio.Tool{
|
|
{Name: view.ModuleReadTool,
|
|
Description: "What the indexer stored for one module under modules.<module>, as stored: its fingerprint (fp, none), the " +
|
|
"new-form fingerprint (fp2) or why it has none (none2), the inputs it was computed from (inputs2), the module's " +
|
|
"directory (path) and the toolchains it was computed with. Read-only.",
|
|
Input: map[string]any{"type": "object", "required": []string{"module"}, "properties": map[string]any{
|
|
"module": map[string]any{"type": "string", "description": "the module's name"}}},
|
|
Run: func(args map[string]any) (any, error) {
|
|
name, _ := args["module"].(string)
|
|
return r.Module(name)
|
|
}},
|
|
{Name: view.ModulesReadTool,
|
|
Description: "Every module the indexer holds, each as stored under modules.<module>. With none2 true, only the modules " +
|
|
"that have no new-form fingerprint, each with the reason (none2). Read-only.",
|
|
Input: map[string]any{"type": "object", "properties": map[string]any{
|
|
"none2": map[string]any{"type": "boolean", "description": "only the modules without a new-form fingerprint"}}},
|
|
Run: func(args map[string]any) (any, error) {
|
|
only, _ := args["none2"].(bool)
|
|
mods, err := r.Modules(only)
|
|
return map[string]any{"modules": mods}, err
|
|
}},
|
|
{Name: view.CandidateReadTool,
|
|
Description: "What the indexer stored for one candidate (the open pull requests of a branch) under candidates.<group>, as stored: " +
|
|
"the pull requests and heads, the base, and per pull request the touched modules with their new-form fingerprint (fp2) or why " +
|
|
"they have none (none2). Read-only.",
|
|
Input: map[string]any{"type": "object", "required": []string{"group"}, "properties": map[string]any{
|
|
"group": map[string]any{"type": "string", "description": "the candidate's group, the branch name its pull requests share"}}},
|
|
Run: func(args map[string]any) (any, error) {
|
|
group, _ := args["group"].(string)
|
|
return r.Candidate(group)
|
|
}},
|
|
{Name: view.CandidatesReadTool,
|
|
Description: "Every candidate the indexer holds, by group, each as stored under candidates.<group>; with module, only those with a " +
|
|
"pull request touching that module. Keys that cannot be read are listed as unreadable. Read-only.",
|
|
Input: map[string]any{"type": "object", "properties": map[string]any{
|
|
"module": map[string]any{"type": "string", "description": "only candidates touching this module"}}},
|
|
Run: func(args map[string]any) (any, error) {
|
|
module, _ := args["module"].(string)
|
|
c, bad, err := r.Candidates(module)
|
|
return map[string]any{"candidates": c, "unreadable": bad}, err
|
|
}},
|
|
{Name: view.BuilderBuildsReadTool,
|
|
Description: "The builder's build keys, each as stored in mesh-delivery-builder_builds: key, module, fingerprint (src2) and build " +
|
|
"(state, by, step with the nodes it was built on, manifest, artifacts with their digests, toolchains, error). Narrow by module " +
|
|
"or state (queued, building, done, failed); at most limit builds (default 50), newest revision first for a module, and the answer says when it was cut and lists keys that are no build key (unreadable). Without a module, give one to get its newest. Read-only.",
|
|
Input: map[string]any{"type": "object", "properties": map[string]any{
|
|
"module": map[string]any{"type": "string", "description": "only this module's builds"},
|
|
"state": map[string]any{"type": "string", "description": "only builds in this state"},
|
|
"limit": map[string]any{"type": "integer", "description": "at most this many builds (default 50), newest revision first"}}},
|
|
Run: func(args map[string]any) (any, error) {
|
|
module, _ := args["module"].(string)
|
|
state, _ := args["state"].(string)
|
|
limit, _ := args["limit"].(float64)
|
|
return r.BuilderBuilds(module, state, int(limit))
|
|
}},
|
|
{Name: view.BuilderBuildReadTool,
|
|
Description: "One build of the builder as stored. Give the module and its fingerprint (fp2, src2:...), or the module alone for the build " +
|
|
"at the fingerprint the indexer holds for it now, joined through modules.<module>; with commit, only if the indexer holds the module at that commit. Read-only.",
|
|
Input: map[string]any{"type": "object", "required": []string{"module"}, "properties": map[string]any{
|
|
"module": map[string]any{"type": "string", "description": "the module's name"},
|
|
"fp2": map[string]any{"type": "string", "description": "its new-form fingerprint; empty means the indexer's current one"},
|
|
"commit": map[string]any{"type": "string", "description": "the commit the indexer must hold the module at"}}},
|
|
Run: func(args map[string]any) (any, error) {
|
|
module, _ := args["module"].(string)
|
|
fp2, _ := args["fp2"].(string)
|
|
commit, _ := args["commit"].(string)
|
|
return r.BuilderBuild(module, fp2, commit)
|
|
}},
|
|
{Name: view.WantsReadTool,
|
|
Description: "The assigner's wants and holds as stored in mesh-delivery-assigner_wants: wants by key (want.<node>.<module>) and " +
|
|
"held fingerprints by key (held.<module>.<hex>). Narrow by node and module (a hold has no node and is shown when no node is given). Read-only.",
|
|
Input: map[string]any{"type": "object", "properties": nodeModule},
|
|
Run: func(args map[string]any) (any, error) {
|
|
node, module := nodeModuleOf(args)
|
|
return r.Wants(node, module)
|
|
}},
|
|
{Name: view.WantReadTool,
|
|
Description: "One want of the assigner as stored: what the node is to run of the module (fingerprint, the newest it is held back from and the rule, removed, words). Read-only.",
|
|
Input: map[string]any{"type": "object", "required": []string{"node", "module"}, "properties": nodeModule},
|
|
Run: func(args map[string]any) (any, error) {
|
|
node, module := nodeModuleOf(args)
|
|
return r.Want(node, module)
|
|
}},
|
|
{Name: view.DifferencesReadTool,
|
|
Description: "The assigner's differences between a want and what the controller sends, as stored in mesh-delivery-assigner_differences, " +
|
|
"by key (<node>.<module>), with the rule that explains each or unexplained. Narrow by node and module. Read-only.",
|
|
Input: map[string]any{"type": "object", "properties": nodeModule},
|
|
Run: func(args map[string]any) (any, error) {
|
|
node, module := nodeModuleOf(args)
|
|
return r.Differences(node, module)
|
|
}},
|
|
{Name: view.HavesReadTool,
|
|
Description: "What each node has, as the node-engine stored it in node-engine_have: by key <node>.<module> (the fingerprint it runs, its phase and health), " +
|
|
"and <node>.node (the node's own facts). Narrow by node and module. Read-only.",
|
|
Input: map[string]any{"type": "object", "properties": nodeModule},
|
|
Run: func(args map[string]any) (any, error) {
|
|
node, module := nodeModuleOf(args)
|
|
return r.Haves(node, module)
|
|
}},
|
|
}
|
|
}
|
|
|
|
var nodeModule = map[string]any{
|
|
"node": map[string]any{"type": "string", "description": "only this node's keys"},
|
|
"module": map[string]any{"type": "string", "description": "only this module's keys"}}
|
|
|
|
func nodeModuleOf(args map[string]any) (string, string) {
|
|
node, _ := args["node"].(string)
|
|
module, _ := args["module"].(string)
|
|
return strings.TrimSpace(node), strings.TrimSpace(module)
|
|
}
|
|
|
|
func read(state stdio.KeptState) view.StateRead {
|
|
return view.StateRead{Keys: state.Keys, GetEntry: func(key string) (json.RawMessage, uint64, error) {
|
|
e, err := state.Get(key)
|
|
if err != nil || e == nil {
|
|
return nil, 0, err
|
|
}
|
|
return e.Value, e.Revision, nil
|
|
}, Get: func(key string) (json.RawMessage, error) {
|
|
e, err := state.Get(key)
|
|
if err != nil || e == nil {
|
|
return nil, err
|
|
}
|
|
return e.Value, nil
|
|
}}
|
|
}
|
|
|
|
func main() {
|
|
r := view.Reader{State: read(stdio.State("mesh-delivery-indexer.modules")), Builds: read(stdio.State("mesh-delivery-builder.builds")), CandidatesState: read(stdio.State("mesh-delivery-indexer.candidates")),
|
|
WantsState: read(stdio.State("mesh-delivery-assigner.wants")), DifferencesState: read(stdio.State("mesh-delivery-assigner.differences")), HavesState: read(stdio.State("node-engine.have"))}
|
|
if err := stdio.Serve("", Tools(r)); err != nil {
|
|
fmt.Fprintf(os.Stderr, "[mesh-delivery-view-tools] %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|