130 lines
5.2 KiB
Go
130 lines
5.2 KiB
Go
package apply
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/declaration"
|
|
"github.com/novox/mesh-host/internal/store"
|
|
)
|
|
|
|
// novox/hq issue 190, ADR 0222: the private network stops writing the mesh's registry into the
|
|
// container runtime's file, and the runtime's own module writes the same member. Both are moved in
|
|
// one apply, and the machine never loses the member: the network's record goes first (its member
|
|
// leaves the list), the runtime's module is applied after (the member is added back, now recorded
|
|
// as the runtime's), and the daemon is reloaded once, never stopped, disabled or restarted — even
|
|
// though the record going says the unit was found stopped and disabled.
|
|
|
|
const theRegistry = "anchor.internal:5100"
|
|
|
|
func runtimeDecl(t *testing.T, path string, network bool) *declaration.Declaration {
|
|
t.Helper()
|
|
var resources []string
|
|
if network {
|
|
resources = append(resources,
|
|
fmt.Sprintf(`{"id":"networking.registry-trust","type":"file","path":%q,"into":"json","content":%q}`,
|
|
path, `{"insecure-registries":["`+theRegistry+`"]}`),
|
|
`{"id":"networking.registry-trust-reload","type":"service","unit":"docker.service","state":"running",
|
|
"reload-on":["networking.registry-trust"]}`)
|
|
}
|
|
resources = append(resources,
|
|
fmt.Sprintf(`{"id":"docker.daemon","type":"file","path":%q,"into":"json","content":%q}`,
|
|
path, `{"live-restore":true,"insecure-registries":["`+theRegistry+`"]}`),
|
|
`{"id":"docker.runtime","type":"service","unit":"docker.service","state":"running","boot":"enabled",
|
|
"reload-on":["docker.daemon"]}`)
|
|
return parse(t, `{"declaration":1,"resources":[`+strings.Join(resources, ",")+`]}`)
|
|
}
|
|
|
|
func TestTheRegistryMovesToTheRuntimesModuleWithoutLeavingTheList(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "daemon.json")
|
|
if err := os.WriteFile(path, []byte(`{"insecure-registries":["192.0.2.7:5000"]}`), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var commands []string
|
|
run := recordingServices(&commands)
|
|
|
|
// Both declare it: the network's record added the member, so the runtime's finds it there.
|
|
_, state, err := Apply(context.Background(), archHost(t), runtimeDecl(t, path, true), store.State{},
|
|
store.OriginDeclared, run, nil, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Say the network's record found the runtime stopped and disabled: giving that back would stop
|
|
// every container on the machine.
|
|
for i := range state.Resources {
|
|
if state.Resources[i].ID == "networking.registry-trust-reload" {
|
|
state.Resources[i].Found = &store.FoundUnit{Unit: "docker.service", State: "stopped", Boot: "disabled"}
|
|
}
|
|
}
|
|
|
|
commands = nil
|
|
report, state, err := Apply(context.Background(), archHost(t), runtimeDecl(t, path, false), state,
|
|
store.OriginDeclared, run, nil, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := fmt.Sprint(readObject(t, path)["insecure-registries"]); got != "[192.0.2.7:5000 "+theRegistry+"]" {
|
|
t.Fatalf("the list after the move: %s", got)
|
|
}
|
|
rec, _ := state.Find("docker.daemon")
|
|
if added := rec.Into.Added["insecure-registries"]; len(added) != 1 || canonical(added[0]) != `"`+theRegistry+`"` {
|
|
t.Errorf("the member is not recorded as the runtime's module's: %s", added)
|
|
}
|
|
reloads := 0
|
|
for _, c := range commands {
|
|
if strings.Contains(c, "docker.service") && (strings.Contains(c, " stop ") || strings.Contains(c, " restart ") ||
|
|
strings.Contains(c, " disable ")) {
|
|
t.Errorf("the runtime was given back as the network's record found it: %q", c)
|
|
}
|
|
if strings.Contains(c, "reload docker.service") {
|
|
reloads++
|
|
}
|
|
}
|
|
if reloads != 1 {
|
|
t.Errorf("the runtime was reloaded %d times; commands were %v", reloads, commands)
|
|
}
|
|
for _, o := range report.Outcomes {
|
|
if o.ID == "networking.registry-trust-reload" && o.Action != "forgotten" {
|
|
t.Errorf("the network's record of the unit was %q: %s", o.Action, o.Detail)
|
|
}
|
|
}
|
|
|
|
// Steady from here on, and undeclaring the runtime's module takes only what it added.
|
|
report, state, err = Apply(context.Background(), archHost(t), runtimeDecl(t, path, false), state,
|
|
store.OriginDeclared, run, nil, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, o := range report.Outcomes {
|
|
if o.ID == "docker.daemon" && o.Action != "unchanged" {
|
|
t.Errorf("a second apply was %q", o.Action)
|
|
}
|
|
}
|
|
if _, _, err := Apply(context.Background(), archHost(t), somethingElse(t), state, store.OriginDeclared, run, nil, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := fmt.Sprint(readObject(t, path)["insecure-registries"]); got != "[192.0.2.7:5000]" {
|
|
t.Errorf("undeclaring the runtime's module left %s", got)
|
|
}
|
|
}
|
|
|
|
// And the preview says the same before it happens.
|
|
func TestThePlanForgetsARecordOfAUnitStillHeld(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "daemon.json")
|
|
var commands []string
|
|
_, state, err := Apply(context.Background(), archHost(t), runtimeDecl(t, path, true), store.State{},
|
|
store.OriginDeclared, recordingServices(&commands), nil, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, step := range Plan(runtimeDecl(t, path, false), state, store.OriginDeclared) {
|
|
if step.ID == "networking.registry-trust-reload" && step.Verb != "forget" {
|
|
t.Errorf("the plan would %s the network's record of a unit docker.runtime holds: %s", step.Verb, step.Why)
|
|
}
|
|
}
|
|
}
|