Compare commits

...
19 changed files with 85 additions and 10 deletions
@@ -47,6 +47,9 @@ func (m *Module) askSteps(steps []StepTool) buildstep.AskSteps {
Has: m.Has, Has: m.Has,
Release: func(ws string) error { return m.spaces().Release(ws) }, Release: func(ws string) error { return m.spaces().Release(ws) },
Logf: m.Say, Logf: m.Say,
// A failed test's whole output is said on the module's own log stream (buildstep.LogTool reads it back).
Narrate: m.Emit,
Module: "mesh-build-go",
} }
} }
@@ -3,6 +3,7 @@ package main
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"os" "os"
"path/filepath" "path/filepath"
"slices" "slices"
@@ -47,9 +48,14 @@ func TestTheManifestDeclaresTheToolchainsStream(t *testing.T) {
Streams []struct { Streams []struct {
Name string `json:"name"` Name string `json:"name"`
Events []string `json:"events"` Events []string `json:"events"`
Age int `json:"max-age-days"`
MiB int `json:"max-mib"`
} `json:"streams"` } `json:"streams"`
} }
if err := json.Unmarshal(raw, &m); err != nil || len(m.Streams) != 1 || m.Streams[0].Name != "toolchains-go" || !slices.Equal(m.Streams[0].Events, []string{"toolchain.**"}) { // And its log stream: a failed test's whole output, kept 14 days and at most 2 GiB, dropping its oldest (the operator,
// 2026-10-30).
if err := json.Unmarshal(raw, &m); err != nil || len(m.Streams) != 2 || m.Streams[0].Name != "toolchains-go" || !slices.Equal(m.Streams[0].Events, []string{"toolchain.**"}) ||
m.Streams[1].Name != buildstep.LogStreamOf("go") || !slices.Equal(m.Streams[1].Events, []string{"log.**"}) || m.Streams[1].Age != 14 || m.Streams[1].MiB != 2048 {
t.Errorf("streams = %+v (%v)", m.Streams, err) t.Errorf("streams = %+v (%v)", m.Streams, err)
} }
} }
@@ -14,6 +14,7 @@ import (
"time" "time"
stdio "git.novox.be/novox/mesh-sdk/go" stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/delivery"
) )
@@ -41,6 +42,7 @@ func main() {
Emit: func(t string, b any) error { return stdio.Emit(t, b) }, Emit: func(t string, b any) error { return stdio.Emit(t, b) },
Steps: stdio.State(delivery.StepsState).Put, Steps: stdio.State(delivery.StepsState).Put,
ReadSteps: readOf(stdio.State(delivery.StepsState)), ReadSteps: readOf(stdio.State(delivery.StepsState)),
ReadLog: stdio.Stream(buildstep.LogStreamOf("go")).Read,
Pauses: stdio.State(delivery.PausesState).Put, Pauses: stdio.State(delivery.PausesState).Put,
ReadPauses: readOf(stdio.State(delivery.PausesState)), ReadPauses: readOf(stdio.State(delivery.PausesState)),
ReadToolchainsState: readOf(stdio.State(delivery.ToolchainsState)), ReadToolchainsState: readOf(stdio.State(delivery.ToolchainsState)),
@@ -31,6 +31,9 @@ type Module struct {
// Held is the puller whose running asks a step-end tool will not end (issue 1890); nil in a test. // Held is the puller whose running asks a step-end tool will not end (issue 1890); nil in a test.
Held *buildstep.Puller Held *buildstep.Puller
ReadSteps, ReadToolchainsState StateRead ReadSteps, ReadToolchainsState StateRead
// ReadLog reads the module's own log stream (stdio.Stream(buildstep.LogStreamOf(language)).Read), where each step
// says a failed test's whole output (Emit says it); nil in a test.
ReadLog buildstep.StreamRead
// Pauses is the Put of the pauses state, which keeps the node's pause key without an age; ReadPauses reads it back. // Pauses is the Put of the pauses state, which keeps the node's pause key without an age; ReadPauses reads it back.
Pauses buildstep.Put Pauses buildstep.Put
ReadPauses StateRead ReadPauses StateRead
@@ -115,7 +115,7 @@ func TestAGoThatCannotBeRunRefusesEveryStepAndHealthIsUnhealthy(t *testing.T) {
{Name: "short_probe", Run: run}, {Name: "short_probe", Run: run},
}, m.StepTools()...) }, m.StepTools()...)
for _, tool := range m.Tools(steps) { for _, tool := range m.Tools(steps) {
if tool.Name == StatusTool || tool.Name == HealthTool || tool.Name == StepReadTool || tool.Name == StepsReadTool || tool.Name == ToolchainsReadTool || tool.Name == ReleaseTool || tool.Name == StepEndTool { if tool.Name == StatusTool || tool.Name == HealthTool || tool.Name == StepReadTool || tool.Name == StepsReadTool || tool.Name == LogReadTool || tool.Name == ToolchainsReadTool || tool.Name == ReleaseTool || tool.Name == StepEndTool {
continue continue
} }
var reason string var reason string
@@ -15,13 +15,16 @@ import (
"time" "time"
stdio "git.novox.be/novox/mesh-sdk/go" stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/delivery"
) )
// The read tools, named as the module is: build_go_ and the verb. // The read tools, named as the module is: build_go_ and the verb.
const ( const (
StepReadTool = "build_go_step" StepReadTool = "build_go_step"
StepsReadTool = "build_go_steps" StepsReadTool = "build_go_steps"
// LogReadTool reads one step's log, a failed test's whole output, from the module's own log stream.
LogReadTool = "build_go_log"
ToolchainsReadTool = "build_go_toolchains" ToolchainsReadTool = "build_go_toolchains"
) )
@@ -225,7 +228,14 @@ func (m *Module) ReadToolchains() (map[string]delivery.Toolchain, error) {
// ReadTools are the module's read tools. All are read-only. // ReadTools are the module's read tools. All are read-only.
func (m *Module) ReadTools() []stdio.Tool { func (m *Module) ReadTools() []stdio.Tool {
readLog := m.ReadLog
if readLog == nil {
readLog = func(string, uint64, int) (*stdio.StreamPage, error) {
return nil, fmt.Errorf("this process reads no log stream: it was not launched by the runtime")
}
}
return []stdio.Tool{ return []stdio.Tool{
buildstep.LogTool(LogReadTool, readLog),
{Name: StepReadTool, {Name: StepReadTool,
Description: "What one step of this machine ended with, as stored in the module's steps state: its tool, state " + Description: "What one step of this machine ended with, as stored in the module's steps state: its tool, state " +
"(running, passed, failed, refused), when it started and ended, why it failed or was refused, and its result " + "(running, passed, failed, refused), when it started and ended, why it failed or was refused, and its result " +
+1 -1
View File
@@ -3,7 +3,7 @@ module meshbuildgo
go 1.26.0 go 1.26.0
require ( require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029233535-78c9ec881771 git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030100935-c2ec8b6b2fde
github.com/distribution/distribution/v3 v3.1.2 github.com/distribution/distribution/v3 v3.1.2
github.com/nats-io/nats-server/v2 v2.11.17 github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.54.0 github.com/nats-io/nats.go v1.54.0
+6
View File
@@ -1,5 +1,11 @@
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029233535-78c9ec881771 h1:Tt16HJk8JZRce1i3JzzDSNdCWOrv7dw8FQ/bckNQ5Ig= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029233535-78c9ec881771 h1:Tt16HJk8JZRce1i3JzzDSNdCWOrv7dw8FQ/bckNQ5Ig=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029233535-78c9ec881771/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029233535-78c9ec881771/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030095131-16bc0dcf3e9d h1:jFOz6wUfZvIayd4DctwlaFKKZHQNME6NLs2OS1rNv30=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030095131-16bc0dcf3e9d/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030095816-530d8d3007dc h1:Wdjl2gomooHswJ5qpkwZPq/ureZgXVw6FMCsgzPJhPo=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030095816-530d8d3007dc/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030100935-c2ec8b6b2fde h1:eKXSllHCS31GgMazfvZ7BeiLoXIUibnUmzxWVkj+Vcw=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030100935-c2ec8b6b2fde/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI= github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI=
github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
+7
View File
@@ -51,6 +51,7 @@
"build_go_release", "build_go_release",
"build_go_step", "build_go_step",
"build_go_steps", "build_go_steps",
"build_go_log",
"build_go_step_end", "build_go_step_end",
"build_go_toolchains", "build_go_toolchains",
"build_go_status", "build_go_status",
@@ -60,6 +61,12 @@
{ {
"name": "toolchains-go", "name": "toolchains-go",
"events": ["toolchain.**"] "events": ["toolchain.**"]
},
{
"name": "go-build-logs",
"events": ["log.**"],
"max-age-days": 14,
"max-mib": 2048
} }
], ],
"requires": [ "requires": [
+1
View File
@@ -0,0 +1 @@
/mesh-build-node
@@ -37,6 +37,9 @@ func (m *Module) askSteps(steps []StepTool) buildstep.AskSteps {
}, },
Release: func(ws string) error { return m.spaces().Release(ws) }, Release: func(ws string) error { return m.spaces().Release(ws) },
Logf: m.Say, Logf: m.Say,
// A failed test's whole output is said on the module's own log stream (buildstep.LogTool reads it back).
Narrate: m.Emit,
Module: "mesh-build-node",
} }
} }
@@ -3,6 +3,7 @@ package main
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"os" "os"
"path/filepath" "path/filepath"
"slices" "slices"
@@ -47,9 +48,14 @@ func TestTheManifestDeclaresTheToolchainsStream(t *testing.T) {
Streams []struct { Streams []struct {
Name string `json:"name"` Name string `json:"name"`
Events []string `json:"events"` Events []string `json:"events"`
Age int `json:"max-age-days"`
MiB int `json:"max-mib"`
} `json:"streams"` } `json:"streams"`
} }
if err := json.Unmarshal(raw, &m); err != nil || len(m.Streams) != 1 || m.Streams[0].Name != "toolchains-node" || !slices.Equal(m.Streams[0].Events, []string{"toolchain.**"}) { // And its log stream: a failed test's whole output, kept 14 days and at most 2 GiB, dropping its oldest (the operator,
// 2026-10-30).
if err := json.Unmarshal(raw, &m); err != nil || len(m.Streams) != 2 || m.Streams[0].Name != "toolchains-node" || !slices.Equal(m.Streams[0].Events, []string{"toolchain.**"}) ||
m.Streams[1].Name != buildstep.LogStreamOf("node") || !slices.Equal(m.Streams[1].Events, []string{"log.**"}) || m.Streams[1].Age != 14 || m.Streams[1].MiB != 2048 {
t.Errorf("streams = %+v (%v)", m.Streams, err) t.Errorf("streams = %+v (%v)", m.Streams, err)
} }
} }
@@ -16,6 +16,7 @@ import (
"time" "time"
stdio "git.novox.be/novox/mesh-sdk/go" stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/forgekey" "git.novox.be/novox/mesh-sdk/go/forgekey"
) )
@@ -47,6 +48,7 @@ func main() {
Emit: func(t string, b any) error { return stdio.Emit(t, b) }, Emit: func(t string, b any) error { return stdio.Emit(t, b) },
Steps: stdio.State(delivery.StepsState).Put, Steps: stdio.State(delivery.StepsState).Put,
ReadSteps: readOf(stdio.State(delivery.StepsState)), ReadSteps: readOf(stdio.State(delivery.StepsState)),
ReadLog: stdio.Stream(buildstep.LogStreamOf("node")).Read,
Pauses: stdio.State(delivery.PausesState).Put, Pauses: stdio.State(delivery.PausesState).Put,
ReadPauses: readOf(stdio.State(delivery.PausesState)), ReadPauses: readOf(stdio.State(delivery.PausesState)),
ReadToolchainsState: readOf(stdio.State(delivery.ToolchainsState)), ReadToolchainsState: readOf(stdio.State(delivery.ToolchainsState)),
@@ -45,6 +45,9 @@ type Module struct {
// Held is the puller whose running asks a step-end tool will not end (issue 1890); nil in a test. // Held is the puller whose running asks a step-end tool will not end (issue 1890); nil in a test.
Held *buildstep.Puller Held *buildstep.Puller
ReadSteps, ReadToolchainsState StateRead ReadSteps, ReadToolchainsState StateRead
// ReadLog reads the module's own log stream (stdio.Stream(buildstep.LogStreamOf(language)).Read), where each step
// says a failed test's whole output (Emit says it); nil in a test.
ReadLog buildstep.StreamRead
// Pauses is the Put of the pauses state, which keeps the node's pause key without an age; ReadPauses reads it back. // Pauses is the Put of the pauses state, which keeps the node's pause key without an age; ReadPauses reads it back.
Pauses buildstep.Put Pauses buildstep.Put
ReadPauses StateRead ReadPauses StateRead
@@ -117,7 +117,7 @@ func TestANodeThatCannotBeRunRefusesEveryStepAndHealthIsUnhealthy(t *testing.T)
{Name: "short_probe", Run: run}, {Name: "short_probe", Run: run},
}, (&Module{}).StepTools()...) }, (&Module{}).StepTools()...)
for _, tool := range m.Tools(steps) { for _, tool := range m.Tools(steps) {
if tool.Name == StatusTool || tool.Name == HealthTool || tool.Name == StepReadTool || tool.Name == StepsReadTool || tool.Name == ToolchainsReadTool || tool.Name == ReleaseTool || tool.Name == StepEndTool { if tool.Name == StatusTool || tool.Name == HealthTool || tool.Name == StepReadTool || tool.Name == StepsReadTool || tool.Name == LogReadTool || tool.Name == ToolchainsReadTool || tool.Name == ReleaseTool || tool.Name == StepEndTool {
continue continue
} }
var reason string var reason string
@@ -15,13 +15,16 @@ import (
"time" "time"
stdio "git.novox.be/novox/mesh-sdk/go" stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/delivery"
) )
// The read tools, named as the module is: build_node_ and the verb. // The read tools, named as the module is: build_node_ and the verb.
const ( const (
StepReadTool = "build_node_step" StepReadTool = "build_node_step"
StepsReadTool = "build_node_steps" StepsReadTool = "build_node_steps"
// LogReadTool reads one step's log, a failed test's whole output, from the module's own log stream.
LogReadTool = "build_node_log"
ToolchainsReadTool = "build_node_toolchains" ToolchainsReadTool = "build_node_toolchains"
) )
@@ -225,7 +228,14 @@ func (m *Module) ReadToolchains() (map[string]delivery.Toolchain, error) {
// ReadTools are the module's read tools. All are read-only. // ReadTools are the module's read tools. All are read-only.
func (m *Module) ReadTools() []stdio.Tool { func (m *Module) ReadTools() []stdio.Tool {
readLog := m.ReadLog
if readLog == nil {
readLog = func(string, uint64, int) (*stdio.StreamPage, error) {
return nil, fmt.Errorf("this process reads no log stream: it was not launched by the runtime")
}
}
return []stdio.Tool{ return []stdio.Tool{
buildstep.LogTool(LogReadTool, readLog),
{Name: StepReadTool, {Name: StepReadTool,
Description: "What one step of this machine ended with, as stored in the module's steps state: its tool, state " + Description: "What one step of this machine ended with, as stored in the module's steps state: its tool, state " +
"(running, passed, failed, refused), when it started and ended, why it failed or was refused, and its result " + "(running, passed, failed, refused), when it started and ended, why it failed or was refused, and its result " +
+1 -1
View File
@@ -3,7 +3,7 @@ module meshbuildnode
go 1.26.0 go 1.26.0
require ( require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029233535-78c9ec881771 git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030100935-c2ec8b6b2fde
github.com/distribution/distribution/v3 v3.1.2 github.com/distribution/distribution/v3 v3.1.2
github.com/nats-io/nats.go v1.54.0 github.com/nats-io/nats.go v1.54.0
) )
+6
View File
@@ -1,5 +1,11 @@
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029233535-78c9ec881771 h1:Tt16HJk8JZRce1i3JzzDSNdCWOrv7dw8FQ/bckNQ5Ig= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029233535-78c9ec881771 h1:Tt16HJk8JZRce1i3JzzDSNdCWOrv7dw8FQ/bckNQ5Ig=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029233535-78c9ec881771/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029233535-78c9ec881771/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030095131-16bc0dcf3e9d h1:jFOz6wUfZvIayd4DctwlaFKKZHQNME6NLs2OS1rNv30=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030095131-16bc0dcf3e9d/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030095816-530d8d3007dc h1:Wdjl2gomooHswJ5qpkwZPq/ureZgXVw6FMCsgzPJhPo=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030095816-530d8d3007dc/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030100935-c2ec8b6b2fde h1:eKXSllHCS31GgMazfvZ7BeiLoXIUibnUmzxWVkj+Vcw=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030100935-c2ec8b6b2fde/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI= github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI=
github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
+7
View File
@@ -46,6 +46,7 @@
"build_node_release", "build_node_release",
"build_node_step", "build_node_step",
"build_node_steps", "build_node_steps",
"build_node_log",
"build_node_step_end", "build_node_step_end",
"build_node_toolchains", "build_node_toolchains",
"build_node_status", "build_node_status",
@@ -57,6 +58,12 @@
"events": [ "events": [
"toolchain.**" "toolchain.**"
] ]
},
{
"name": "node-build-logs",
"events": ["log.**"],
"max-age-days": 14,
"max-mib": 2048
} }
], ],
"requires": [ "requires": [