View: build_usage answers how the build nodes are used in one call; the checker's tries name their asks
The operator's question (how much are the build nodes used, is ace eligible) took six calls over four tools. build_usage reads it from the bus's states: seats held (have), capacity (mesh-config resolved), pauses, the build modules' steps by kind with left-running keys, the last hour and day with total and median time and time at capacity, the running tries, and the backlog the view program reads from the seats' streams. A try now names the asks it put, and the checker announces its tries readable, so the view tells a try's asks from a check's.
This commit is contained in:
@@ -11,12 +11,24 @@ import (
|
||||
|
||||
"mesh-delivery-view/internal/view"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
)
|
||||
|
||||
// Tools are the read tools over a modules state.
|
||||
func Tools(r view.Reader) []stdio.Tool {
|
||||
// Tools are the read tools over a modules state, and build_usage over the build modules' states.
|
||||
func Tools(r view.Reader, u view.UsageReader) []stdio.Tool {
|
||||
return []stdio.Tool{
|
||||
{Name: view.BuildUsageTool,
|
||||
Description: "How the build nodes are used, per node: each build seat it holds (node-build-go, -node, -image) with its capacity " +
|
||||
"(mesh-config's resolved value, or the modules' default) and pause, and whether it is eligible to build and why not; the asks " +
|
||||
"running now by kind (delivery, check, recheck, try) and the keys left running (past the step bound, or their module not running); " +
|
||||
"the steps started and finished in the last hour and the last day, failed ones, total and median time, by kind, and how long and " +
|
||||
"what share of the window the node ran its capacity of asks. Mesh-wide: the backlog of asks waiting and held on each build seat's " +
|
||||
"stream, and the tries running. Read from the bus's states (have, mesh-config, the build modules' steps and pauses, the checker's tries); " +
|
||||
"the backlog from the view program's reading of the streams; CPU is not on the bus and the answer names the per-node tool. Read-only.",
|
||||
Input: map[string]any{"type": "object", "properties": map[string]any{}},
|
||||
Run: func(map[string]any) (any, error) { return u.Usage(), nil }},
|
||||
{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 " +
|
||||
@@ -131,6 +143,24 @@ func nodeModuleOf(args map[string]any) (string, string) {
|
||||
return strings.TrimSpace(node), strings.TrimSpace(module)
|
||||
}
|
||||
|
||||
// socket is the view program's socket, as the program reads it (MESH_DELIVERY_SOCKET, else its default).
|
||||
func socket() string {
|
||||
if s := strings.TrimSpace(os.Getenv("MESH_DELIVERY_SOCKET")); s != "" {
|
||||
return s
|
||||
}
|
||||
return "/var/lib/mesh-delivery-view-cli/cli.sock"
|
||||
}
|
||||
|
||||
// backlogOf asks the view program on its socket for the backlog it reads from the seats' streams' workers: the tool
|
||||
// runtime grants a bundle states, and the stream and worker information is granted to the view program's own account
|
||||
// (mesh-sdk buscompose.BuildBacklogReads).
|
||||
func backlogOf(path string) func() ([]view.BacklogRow, error) {
|
||||
return func() ([]view.BacklogRow, error) {
|
||||
s, err := view.Ask(path)
|
||||
return s.Backlog, err
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -150,7 +180,14 @@ func read(state stdio.KeptState) view.StateRead {
|
||||
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 {
|
||||
u := view.UsageReader{Haves: r.HavesState, Resolved: read(stdio.State("mesh-config.resolved")), Tries: read(stdio.State("mesh-delivery-checker.tries")),
|
||||
Steps: map[string]view.StateRead{}, Pauses: map[string]view.StateRead{}, Backlog: backlogOf(socket())}
|
||||
for _, lang := range delivery.AskLanguages {
|
||||
module, _ := delivery.BuildModuleOf(lang)
|
||||
u.Steps[lang] = read(stdio.State(module + "." + delivery.StepsState))
|
||||
u.Pauses[lang] = read(stdio.State(module + "." + delivery.PausesState))
|
||||
}
|
||||
if err := stdio.Serve("", Tools(r, u)); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "[mesh-delivery-view-tools] %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func (f fake) reader() view.Reader {
|
||||
|
||||
func run(t *testing.T, r view.Reader, name string, args map[string]any) (any, error) {
|
||||
t.Helper()
|
||||
for _, tl := range Tools(r) {
|
||||
for _, tl := range Tools(r, view.UsageReader{}) {
|
||||
if tl.Name == name {
|
||||
return tl.Run(args)
|
||||
}
|
||||
@@ -64,11 +64,7 @@ func TestModuleToolAnswersTheStoredValue(t *testing.T) {
|
||||
if err := json.Unmarshal(out.(json.RawMessage), &m); err != nil || m["fp"] != "a1" || m["fp2"] != "b2" || m["path"] != "." || m["inputs2"] == nil || m["toolchains"] == nil {
|
||||
t.Errorf("stored fields are not all there: %v %v", m, err)
|
||||
}
|
||||
}
|
||||
|
||||
// A module with no key, and a name that is no key, are said so.
|
||||
func TestModuleToolRefusesWhatIsNotThere(t *testing.T) {
|
||||
r := fake{"a": withFP2}.reader()
|
||||
// A module with no key, and a name that is no key, are said so.
|
||||
if _, err := run(t, r, view.ModuleReadTool, map[string]any{"module": "gone"}); err == nil || !strings.Contains(err.Error(), "no module gone") {
|
||||
t.Errorf("a missing module: %v", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user