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) } } } }