100 lines
4.3 KiB
Go
100 lines
4.3 KiB
Go
package bootstrap
|
|
|
|
import (
|
|
"context"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-host/internal/store"
|
|
)
|
|
|
|
// Defends novox/hq ADR 0100: a converged genesis refuses a machine in use, naming every container
|
|
// and listener it counted.
|
|
|
|
// Lines as `ss -Hltunp` prints them. The ssh, samba, loopback and proxy lines are captured from a
|
|
// real machine; the resolver, DHCP and time lines are written in the same shape for the processes a
|
|
// fresh machine runs, and still need measuring against one.
|
|
const inUseSockets = `tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1188536,fd=6))
|
|
tcp LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=1188536,fd=7))
|
|
tcp LISTEN 0 32 127.0.0.1:53 0.0.0.0:* users:(("dnsmasq",pid=1189392,fd=7))
|
|
tcp LISTEN 0 4096 127.0.0.1:5432 0.0.0.0:* users:(("docker-proxy",pid=1854543,fd=7))
|
|
udp UNCONN 0 0 0.0.0.0:5355 0.0.0.0:* users:(("systemd-resolve",pid=301,fd=11))
|
|
udp UNCONN 0 0 192.0.2.10%eth0:68 0.0.0.0:* users:(("systemd-network",pid=280,fd=19))
|
|
udp UNCONN 0 0 0.0.0.0:68 0.0.0.0:* users:(("dhcpcd",pid=270,fd=9))
|
|
udp UNCONN 0 0 0.0.0.0:123 0.0.0.0:* users:(("systemd-timesyn",pid=260,fd=9))
|
|
`
|
|
|
|
const servingSockets = `tcp LISTEN 0 50 0.0.0.0:445 0.0.0.0:* users:(("smbd",pid=1248,fd=29))
|
|
tcp LISTEN 0 4096 0.0.0.0:8080 0.0.0.0:* users:(("docker-proxy",pid=1920035,fd=7))
|
|
udp UNCONN 0 0 0.0.0.0:123 0.0.0.0:* users:(("ntpd",pid=1070791,fd=17))
|
|
`
|
|
|
|
type inUseRunner struct{ ps, ss string }
|
|
|
|
func (m inUseRunner) run(_ context.Context, name string, args ...string) (string, error) {
|
|
if name == "docker" {
|
|
return m.ps, nil
|
|
}
|
|
return m.ss, nil
|
|
}
|
|
|
|
func TestAFreshMachineIsNotInUse(t *testing.T) {
|
|
containers, listeners, err := InUse(context.Background(), inUseRunner{ss: inUseSockets}.run,
|
|
func(string) bool { return false })
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(containers) != 0 || len(listeners) != 0 {
|
|
t.Errorf("ssh, loopback, name resolution, DHCP and time were counted: %v %v", containers, listeners)
|
|
}
|
|
}
|
|
|
|
func TestAMachineServingIsInUse(t *testing.T) {
|
|
m := inUseRunner{ps: "hello-web\t\nmesh-store\tabc123\n", ss: inUseSockets + servingSockets}
|
|
containers, listeners, err := InUse(context.Background(), m.run, func(string) bool { return false })
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(containers) != 1 || containers[0] != "hello-web" {
|
|
t.Errorf("containers counted: %v (one a host made is not a predecessor's)", containers)
|
|
}
|
|
var by []string
|
|
for _, l := range listeners {
|
|
by = append(by, l.By)
|
|
}
|
|
if strings.Join(by, " ") != "smbd docker-proxy ntpd" {
|
|
t.Errorf("listeners counted: %v", listeners)
|
|
}
|
|
}
|
|
|
|
func TestAConvergedGenesisRefusesAMachineInUseNamingEverything(t *testing.T) {
|
|
o := Options{State: filepath.Join(t.TempDir(), "state.json")}
|
|
m := inUseRunner{ps: "hello-web\t\n", ss: inUseSockets + servingSockets}
|
|
err := RefuseAMachineInUse(context.Background(), o, m.run, quietly)
|
|
if err == nil {
|
|
t.Fatal("a machine in use was not refused")
|
|
}
|
|
for _, want := range []string{"container hello-web", "tcp 0.0.0.0:445 by smbd", "tcp 0.0.0.0:8080 by docker-proxy",
|
|
"udp 0.0.0.0:123 by ntpd", "--adopted"} {
|
|
if !strings.Contains(err.Error(), want) {
|
|
t.Errorf("the refusal does not name %q: %v", want, err)
|
|
}
|
|
}
|
|
o.Adopted = true
|
|
if err := RefuseAMachineInUse(context.Background(), o, m.run, quietly); err != nil {
|
|
t.Errorf("an adopted genesis was refused a machine in use: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestARerunOfGenesisIsNotAMachineInUse(t *testing.T) {
|
|
o := Options{State: filepath.Join(t.TempDir(), "state.json")}
|
|
if err := store.Save(o.State, store.State{Resources: []store.Applied{{ID: "store", Type: "container", Target: "mesh-store"}}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
m := inUseRunner{ps: "mesh-gitea-server\t\n", ss: servingSockets}
|
|
if err := RefuseAMachineInUse(context.Background(), o, m.run, quietly); err != nil {
|
|
t.Errorf("what an earlier genesis raised was counted as a machine in use: %v", err)
|
|
}
|
|
}
|