`status` says which machines are not doing what they were told, and nothing acted on it: a machine that refused or failed stayed wrong until somebody ran push again naming it. `push --behind` sends only to machines whose last report was not a clean apply. A command rather than a timer, deliberately: a scheduler is then a scheduler over this, where building the scheduler first would have meant two paths to one act with nothing to compare them against. Naming a machine and asking which machines need one are different requests, so `push <node> --behind` is refused rather than guessed. With nothing behind it says so, because "nothing needed one" and "this did not run" must never look the same. A machine failing the same way for six hours is pushed to anyway and said about — refusing would leave no way to retry after fixing the cause, and this is a command somebody ran. Proven in the lab: a machine is broken with a package that does not exist, `push --behind` names it and not the machine that is fine, the module is corrected, and the machine recovers without anybody naming it. And the builder can be told where to publish rather than configured. A builder that is a module requires an artifact store, and the mesh writes it the same binding any consumer of any provision gets. A binding with no address is refused rather than falling back to anything — that would publish to a store on the wrong machine and be found out much later. The variable remains for a builder run by a person, which is how it is still run while being developed.
77 lines
2.3 KiB
Go
77 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// Where a builder publishes.
|
|
//
|
|
// Preferably from the mesh: a builder that is a module requires an artifact store, and the mesh
|
|
// writes it a binding saying which machine answers and on what port. Reading it means the address
|
|
// is not a setting somebody keeps in step by hand.
|
|
|
|
func binding(t *testing.T, body string) string {
|
|
t.Helper()
|
|
path := filepath.Join(t.TempDir(), "artifact-store.json")
|
|
if err := os.WriteFile(path, []byte(body), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return path
|
|
}
|
|
|
|
func TestTheMeshSaysWhereToPublish(t *testing.T) {
|
|
t.Setenv("MESH_BINDING", binding(t, `{"binding":1,"provision":"artifact-store",
|
|
"from":"anchor","at":"anchor.internal","serves":{"port":5000,"scheme":"http"}}`))
|
|
where, err := whereToPublish()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if where != "anchor.internal:5000" {
|
|
t.Fatalf("got %q", where)
|
|
}
|
|
}
|
|
|
|
func TestABindingWithNoAddressIsRefused(t *testing.T) {
|
|
// The provider is not on the private network, so there is no name to reach it by. Falling
|
|
// back to anything would publish to a store on the wrong machine and be found out much later.
|
|
t.Setenv("MESH_BINDING", binding(t, `{"binding":1,"from":"anchor","serves":{"port":5000}}`))
|
|
_, err := whereToPublish()
|
|
if err == nil {
|
|
t.Fatal("a binding with nowhere to reach was accepted")
|
|
}
|
|
if !strings.Contains(err.Error(), "anchor") {
|
|
t.Fatalf("the failure does not name the machine: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestABindingWithNoPortIsRefused(t *testing.T) {
|
|
t.Setenv("MESH_BINDING", binding(t, `{"binding":1,"from":"a","at":"a.internal","serves":{}}`))
|
|
if _, err := whereToPublish(); err == nil {
|
|
t.Fatal("a binding saying nothing about a port was accepted")
|
|
}
|
|
}
|
|
|
|
func TestTheVariableStillWorksForABuilderRunByAPerson(t *testing.T) {
|
|
// Which is how this started and how it is still run while being developed.
|
|
t.Setenv("MESH_BINDING", "")
|
|
t.Setenv("MESH_REGISTRY", "127.0.0.1:5000")
|
|
where, err := whereToPublish()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if where != "127.0.0.1:5000" {
|
|
t.Fatalf("got %q", where)
|
|
}
|
|
}
|
|
|
|
func TestNeitherIsRefusedRatherThanGuessed(t *testing.T) {
|
|
t.Setenv("MESH_BINDING", "")
|
|
t.Setenv("MESH_REGISTRY", "")
|
|
if _, err := whereToPublish(); err == nil {
|
|
t.Fatal("a builder with nowhere to publish reported somewhere")
|
|
}
|
|
}
|