package resolution import ( "fmt" "strings" "testing" mcat "git.novox.be/novox/mesh-sdk/go/catalogue" ) func TestASeatPlaceholderAnswersWhereThisMachinePutTheHolder(t *testing.T) { control := map[string]any{ "type": "container", "id": "server", "name": "mesh-controller", "env": map[string]any{ "MESH_STORE_INVENTORY_PORT": "${seat:mesh-store:5432}", "MESH_BROKER_ADDRESS_PORT": "${seat:mesh-broker:5671}", "MESH_STORE_INVENTORY_FILE": "/run/secrets/inventory", }, } with := mcat.Rendering{Seats: map[string]map[int]int{ "mesh-store": {5432: 6852}, "mesh-broker": {5672: 5679, 5671: 5671}, }} if err := seatInto(control, "mesh-controller", with); err != nil { t.Fatal(err) } env := control["env"].(map[string]any) for key, want := range map[string]string{ "MESH_STORE_INVENTORY_PORT": "6852", "MESH_BROKER_ADDRESS_PORT": "5671", "MESH_STORE_INVENTORY_FILE": "/run/secrets/inventory", } { if env[key] != want { t.Errorf("%s = %v, want %q", key, env[key], want) } } } // A seat nothing on this machine holds — or one whose holder the mesh has given no port — answers // with nothing, so the port genesis wrote into the connection string stands. Not the software's // own port: on a node given a port at genesis before the store's module exists, that would // override the right number with the catalogue's. func TestASeatTheMeshCannotPlaceAnswersWithNothing(t *testing.T) { control := map[string]any{ "type": "container", "id": "server", "name": "mesh-controller", "env": map[string]any{"MESH_STORE_INVENTORY_PORT": "${seat:mesh-store:5432}"}, } if err := seatInto(control, "mesh-controller", mcat.Rendering{}); err != nil { t.Fatal(err) } if got := control["env"].(map[string]any)["MESH_STORE_INVENTORY_PORT"]; got != "" { t.Fatalf("with nothing known, the seat answered %q", got) } file := map[string]any{"type": "file", "content": "port=${seat:mesh-store:5432}\n"} if err := seatInto(file, "x", mcat.Rendering{Seats: map[string]map[int]int{"mesh-store": {5433: 1}}}); err != nil { t.Fatal(err) } if got := file["content"]; got != "port=\n" { t.Fatalf("a port the holder does not publish answered %q", got) } } func TestASeatPlaceholderNamingNoPortIsRefused(t *testing.T) { file := map[string]any{"type": "file", "content": "${seat:mesh-store:99999}"} if err := seatInto(file, "x", mcat.Rendering{}); err == nil { t.Fatal("99999 was accepted as a port") } } func TestFillingASeatLeavesTheManifestAlone(t *testing.T) { env := map[string]any{"MESH_STORE_INVENTORY_PORT": "${seat:mesh-store:5432}"} manifest := map[string]any{"type": "container", "id": "server", "env": env} for _, at := range []int{6852, 5432} { copied := map[string]any{} for k, v := range manifest { copied[k] = v } with := mcat.Rendering{Seats: map[string]map[int]int{"mesh-store": {5432: at}}} if err := seatInto(copied, "mesh-controller", with); err != nil { t.Fatal(err) } } if env["MESH_STORE_INVENTORY_PORT"] != "${seat:mesh-store:5432}" { t.Fatalf("the module's own manifest was edited: %v", env) } } func runtimeTrust() map[string]any { return map[string]any{ "type": "file", "id": "daemon", "path": "/etc/docker/daemon.json", "into": "json", "content": `{"live-restore": true, "insecure-registries": ["${seat:mesh-artifact-store:reach}"]}` + "\n", } } func TestASeatsReachIsWhereThisMachineReachesItsHolder(t *testing.T) { file := runtimeTrust() with := mcat.Rendering{SeatReach: map[string]string{"mesh-artifact-store": "anchor.internal:5100"}} if err := seatInto(file, "docker", with); err != nil { t.Fatal(err) } want := `{"live-restore": true, "insecure-registries": ["anchor.internal:5100"]}` + "\n" if file["content"] != want { t.Fatalf("content = %q, want %q", file["content"], want) } process := map[string]any{"type": "process", "name": "p", "env": map[string]any{"REGISTRY": "${seat:mesh-artifact-store:reach}"}} if err := seatInto(process, "x", with); err != nil { t.Fatal(err) } if got := process["env"].(map[string]any)["REGISTRY"]; got != "anchor.internal:5100" { t.Fatalf("an environment value was filled with %q", got) } } // With no holder reachable, the runtime is not told to trust "": the member is dropped, and the // list with it when nothing else is in it. func TestAnUnansweredReachAddsNothingToAList(t *testing.T) { file := runtimeTrust() if err := seatInto(file, "docker", mcat.Rendering{}); err != nil { t.Fatal(err) } if got := file["content"]; got != `{"live-restore":true}`+"\n" { t.Fatalf("with no store reachable, the runtime's keys are %q", got) } kept := map[string]any{"type": "file", "into": "json", "content": `{"insecure-registries": ["${seat:mesh-artifact-store:reach}", "192.0.2.7:5000"]}`} if err := seatInto(kept, "docker", mcat.Rendering{}); err != nil { t.Fatal(err) } if got := kept["content"]; got != `{"insecure-registries":["192.0.2.7:5000"]}`+"\n" { t.Fatalf("a list's other members were not kept: %q", got) } } func TestAReachTheMeshDoesNotAnswerIsRefused(t *testing.T) { file := map[string]any{"type": "file", "content": "${seat:mesh-store:reach}"} err := seatInto(file, "x", mcat.Rendering{SeatReach: map[string]string{"mesh-store": "anchor.internal:5432"}}) if err == nil || !strings.Contains(err.Error(), "mesh-artifact-store") { t.Fatalf("a reach the mesh does not answer was not refused by name: %v", err) } } // Through the whole composition, as the container runtime's module declares it. func TestTheRuntimesTrustIsComposedFromTheSeatsReach(t *testing.T) { r := mcat.Resolution{Node: "anchor", Modules: []mcat.Manifest{{ Module: "docker", Resources: []map[string]any{runtimeTrust()}, }}} out, err := Declaration(r, mcat.Rendering{ SeatReach: map[string]string{"mesh-artifact-store": "anchor.internal:5100"}, }) if err != nil { t.Fatal(err) } file := fileNamed(out, "docker.daemon") if file == nil { t.Fatalf("no file in %v", out) } if got := file["content"]; !strings.Contains(fmt.Sprint(got), `["anchor.internal:5100"]`) { t.Fatalf("the runtime's file says %q", got) } }