Files
mesh-sdk/go/catalogue/two_consumers_test.go
T

144 lines
5.3 KiB
Go

package catalogue
import (
"strings"
"testing"
)
// A node runs several modules that all want one database (novox/hq 04-ISSUES/022).
//
// **The ordinary arrangement, and it could not be planned at all.** The walk that resolves a node
// is a work-list over names, so a requirement three modules shared was visited once and produced
// one need — carrying whichever module mentioned it first. Everything downstream inherited that:
// one credential, keyed by machine, named after a machine by the provisioner.
//
// The symptom had two halves and only one was loud. The provider refused, naming the modules and
// saying they would share one credential, which reads as a decision. The consumer did not: it
// resolved cleanly, wrote one module's credential file, and left the other two absent — a service
// that starts and cannot authenticate, with nothing anywhere saying why. That is the shape of 021
// again, on a different axis.
func threeConsumers() map[string]Manifest {
return shelf(
Manifest{Module: "postgres", Version: "1", Provides: FromAnywhere("postgres-database")},
Manifest{Module: "gitea", Version: "1", Requires: []string{"postgres-database"},
Contributes: map[string]map[string]any{"postgres-database": {"name": "gitea"}},
Secrets: map[string]string{"postgres-database": "/var/lib/gitea/db.secret"}},
Manifest{Module: "keycloak", Version: "1", Requires: []string{"postgres-database"},
Contributes: map[string]map[string]any{"postgres-database": {"name": "keycloak"}},
Secrets: map[string]string{"postgres-database": "/var/lib/keycloak/db.secret"}},
Manifest{Module: "umami", Version: "1", Requires: []string{"postgres-database"},
Contributes: map[string]map[string]any{"postgres-database": {"name": "umami"}},
Secrets: map[string]string{"postgres-database": "/var/lib/umami/db.secret"}},
)
}
func TestEveryConsumerOnANodeGetsItsOwnCredential(t *testing.T) {
got, err := Resolve(threeConsumers(), []string{"gitea", "keycloak", "umami"},
reachable(), World{Offered: onNetwork("anchor")})
if err != nil {
t.Fatal(err)
}
if len(got.Needs) != 3 {
t.Fatalf("three modules want a database and the node has %d need(s): %v",
len(got.Needs), got.Needs)
}
for _, want := range []string{"gitea", "keycloak", "umami"} {
var found bool
for _, n := range got.Needs {
if n.For == want {
found = true
}
}
if !found {
t.Errorf("%s wants a database and no credential is made for it", want)
}
}
}
// Each consumer's own credential reaches its own file. Matching on the provision alone, every
// consumer took whichever need was last — a module handed somebody else's password, which is a
// valid credential and therefore fails in a way that looks like a configuration error.
func TestEachConsumerGetsItsOwnCredentialAndNotAnothersFile(t *testing.T) {
got, err := Resolve(threeConsumers(), []string{"gitea", "keycloak", "umami"},
reachable(), World{Offered: onNetwork("anchor")})
if err != nil {
t.Fatal(err)
}
for i := range got.Needs {
got.Needs[i].Sealed = "sealed-for-" + got.Needs[i].For
}
out, err := got.Declaration(Rendering{})
if err != nil {
t.Fatal(err)
}
for _, want := range []string{"gitea", "keycloak", "umami"} {
var seen bool
for _, r := range out {
if r["path"] != "/var/lib/"+want+"/db.secret" {
continue
}
seen = true
if r["sealed"] != "sealed-for-"+want {
t.Errorf("%s was given %v, which belongs to something else", want, r["sealed"])
}
}
if !seen {
t.Errorf("%s resolved and its credential file was never written", want)
}
}
}
// The provider is told about all three, separately, and names each grant after the module.
func TestAProviderIsToldAboutEveryConsumerOnOneMachine(t *testing.T) {
provider, err := Resolve(shelf(Manifest{
Module: "postgres", Version: "1", Provides: FromAnywhere("postgres-database"),
Grants: map[string]string{"postgres-database": "/var/lib/postgres/grants"},
Receives: map[string]string{"postgres-database": "/var/lib/postgres/grants/mesh.json"},
}), []string{"postgres"}, reachable(), World{})
if err != nil {
t.Fatal(err)
}
var grants []Grant
for _, who := range []string{"gitea", "keycloak", "umami"} {
grants = append(grants, Grant{
Provision: "postgres-database", Consumer: "anchor", From: who,
Values: map[string]any{"name": who}, Sealed: "sealed-for-" + who})
}
out, err := provider.Declaration(Rendering{Grants: grants})
if err != nil {
t.Fatal(err)
}
for _, who := range []string{"gitea", "keycloak", "umami"} {
path := "/var/lib/postgres/grants/anchor." + who + ".secret"
var found bool
for _, r := range out {
if r["path"] == path {
found = true
if r["sealed"] != "sealed-for-"+who {
t.Errorf("%s's grant holds %v", who, r["sealed"])
}
}
}
if !found {
t.Errorf("the provider was never told to create a login for %s", who)
}
}
// And all three appear in the readable manifest, so the provisioner sees three consumers
// where there are three. Named after one machine, they were one path and the last won.
for _, r := range out {
if r["path"] != "/var/lib/postgres/grants/mesh.json" {
continue
}
body := r["content"].(string)
for _, who := range []string{"gitea", "keycloak", "umami"} {
if !strings.Contains(body, `"`+who+`"`) {
t.Errorf("the provider's manifest never mentions %s: %s", who, body)
}
}
}
}