A folded module owns its manifest's paths, as the controller tells node-files them, not every path it runs at (issue 1126, seed-8: f1-circuits, snake and txt-game shifted node-tools' owned paths on ace)
This commit is contained in:
+16
-13
@@ -263,6 +263,10 @@ func NamesBuild(m catalogue.Manifest) bool {
|
||||
// and nothing else of its own is composed (issue 1126: nats's ${dir:mesh-state} on novox). A module refused in a
|
||||
// node's answer is composed so; a folded one the node runs is Carried.
|
||||
func Stub(m catalogue.Manifest) catalogue.Manifest {
|
||||
// The paths it owns stay its manifest's, as the controller tells the holder of node-files them (issue 1126, seed-8).
|
||||
if m.OwnsPaths == nil {
|
||||
m.OwnsPaths = catalogue.DeclaredPaths(m)
|
||||
}
|
||||
m.Build = nil
|
||||
var dirs []map[string]any
|
||||
for _, r := range m.Resources {
|
||||
@@ -276,19 +280,21 @@ func Stub(m catalogue.Manifest) catalogue.Manifest {
|
||||
|
||||
// Carried is m, folded into its node's own composition at a build of the old form, as the node runs it (issue 1126,
|
||||
// C5): nothing to build; its containers and directories those the node's own composition (runs) carries of it, their
|
||||
// module's word taken off their ids, with the manifest's directories it does not run; and the path of every resource it
|
||||
// runs (catalogue.Manifest.RunsAt). So what other modules read of it is what runs: the machine ports its containers
|
||||
// publish (the filter's rules, the routes reaching it: MachineSide) and the paths it owns (the holder of node-files is
|
||||
// told them). Its other resources are not taken, since the composition makes some of them again from its manifest (its
|
||||
// secrets' files) and one id twice is refused; none of them is composed into what is applied either way (compositions
|
||||
// leaves a carried module's out, and carries the ones that run). What it provides, requires, listens on and grants is
|
||||
// its manifest's. A module whose resources runs holds none of is its Stub, as before.
|
||||
// module's word taken off their ids, with the manifest's directories it does not run. So what other modules read of it
|
||||
// is what runs: the machine ports its containers publish (the filter's rules, the routes reaching it: MachineSide). The
|
||||
// paths it owns, which the holder of node-files is told, are its manifest's, as for its Stub: the controller composes
|
||||
// them from the manifest, not from every path a resource of it runs at (issue 1126, seed-8: f1-circuits, snake and
|
||||
// txt-game on ace, whose manifests leave their directories to the mesh). Its other resources are not taken, since the
|
||||
// composition makes some of them again from its manifest (its secrets' files) and one id twice is refused; none of them
|
||||
// is composed into what is applied either way (compositions leaves a carried module's out, and carries the ones that
|
||||
// run). What it provides, requires, listens on and grants is its manifest's. A module whose resources runs holds none
|
||||
// of is its Stub, as before.
|
||||
func Carried(m catalogue.Manifest, module string, runs *delivery.Composed) catalogue.Manifest {
|
||||
if runs == nil {
|
||||
return Stub(m)
|
||||
}
|
||||
var taken []map[string]any
|
||||
var at []string
|
||||
runsAny := false
|
||||
ids := map[string]bool{}
|
||||
for _, raw := range runs.Resources {
|
||||
var r map[string]any
|
||||
@@ -303,9 +309,7 @@ func Carried(m catalogue.Manifest, module string, runs *delivery.Composed) catal
|
||||
if owner != module {
|
||||
continue
|
||||
}
|
||||
if p, ok := r["path"].(string); ok && p != "" {
|
||||
at = append(at, p)
|
||||
}
|
||||
runsAny = true
|
||||
if typ := r["type"]; typ != "container" && typ != "directory" {
|
||||
continue
|
||||
}
|
||||
@@ -314,7 +318,7 @@ func Carried(m catalogue.Manifest, module string, runs *delivery.Composed) catal
|
||||
ids[r["id"].(string)] = true
|
||||
taken = append(taken, r)
|
||||
}
|
||||
if len(at) == 0 && len(taken) == 0 {
|
||||
if !runsAny {
|
||||
return Stub(m)
|
||||
}
|
||||
stub := Stub(m)
|
||||
@@ -324,7 +328,6 @@ func Carried(m catalogue.Manifest, module string, runs *delivery.Composed) catal
|
||||
}
|
||||
}
|
||||
stub.Resources = taken
|
||||
stub.RunsAt = at
|
||||
return stub
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
@@ -240,17 +241,39 @@ func answerNamesEveryRefusalAndLeavesAnOldBuildToTheNode(t *testing.T) {
|
||||
if !strings.Contains(rules, "# spiegel — the site") || !strings.Contains(rules, "dport 20005 accept") || strings.Contains(rules, "dport 8080") {
|
||||
t.Errorf("the filter does not open the machine port spiegel runs at:\n%s", rules)
|
||||
}
|
||||
// The paths a carried module owns are its manifest's, as the controller composes them, never what runs of it (issue
|
||||
// 1126, seed-8 #542: on ace, the folded f1-circuits, snake and txt-game, whose manifests leave their directories and
|
||||
// files to ${dir:…}, owned their /var/lib paths on the node and none on the controller, shifting node-tools'
|
||||
// MESH_OWNED_PATHS). f1-circuits' manifest at the indexer's commit (c0ea2c94) is captured; what runs of it is
|
||||
// composed from that manifest by the controller's rule (the directory at /var/lib/f1-circuits, its file, its container).
|
||||
for _, c := range running {
|
||||
if c.Module == "" && !slices.Contains(compose.Carried(in.Catalogue["spiegel"], "spiegel", &c).RunsAt, "/var/lib/spiegel/server.env") {
|
||||
t.Errorf("spiegel carried does not own the path its running file is at")
|
||||
if c.Module == "" && !reflect.DeepEqual(compose.Carried(in.Catalogue["spiegel"], "spiegel", &c).OwnsPaths, []string{"/var/lib/spiegel"}) {
|
||||
t.Errorf("spiegel carried owns %v, want its manifest's /var/lib/spiegel alone", compose.Carried(in.Catalogue["spiegel"], "spiegel", &c).OwnsPaths)
|
||||
}
|
||||
}
|
||||
f1raw, err := os.ReadFile("testdata/f1-circuits-c0ea2c94.module.json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f1, err := catalogue.ParseManifest(f1raw)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f1runs := delivery.Composed{Node: "ace", Resources: []json.RawMessage{
|
||||
json.RawMessage(`{"id":"f1-circuits.state","module":"f1-circuits","type":"directory","path":"/var/lib/f1-circuits","mode":"0700"}`),
|
||||
json.RawMessage(`{"id":"f1-circuits.cache","module":"f1-circuits","type":"directory","path":"/var/lib/f1-circuits/cache","mode":"0700"}`),
|
||||
json.RawMessage(`{"id":"f1-circuits.site-env","module":"f1-circuits","type":"file","path":"/var/lib/f1-circuits/site.env","mode":"0644","content":"F1_CIRCUITS_BASE_URL=https://f1.example\n"}`),
|
||||
json.RawMessage(`{"id":"f1-circuits.server","module":"f1-circuits","type":"container","name":"f1-circuits","image":"registry.example/f1@sha256:` + strings.Repeat("c", 64) + `"}`)}}
|
||||
if got, want := catalogue.DeclaredPaths(compose.Carried(f1, "f1-circuits", &f1runs)), catalogue.DeclaredPaths(f1); !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("f1-circuits carried owns %v, want what the controller composes from its manifest, %v", got, want)
|
||||
}
|
||||
var k1, k2 any
|
||||
_ = json.Unmarshal(keptComposed, &k1)
|
||||
_ = json.Unmarshal(keptFile, &k2)
|
||||
if !reflect.DeepEqual(k1, k2) {
|
||||
t.Errorf("the operator export is composed as %s, want the file that runs %s", keptComposed, keptFile)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// A module another node cannot run in this composition offers nothing in it: the refusal names it and why
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"module": "f1-circuits",
|
||||
"slug": "f1",
|
||||
"version": "1",
|
||||
"capabilities": [
|
||||
"container-runtime"
|
||||
],
|
||||
"requires": [
|
||||
"route"
|
||||
],
|
||||
"contributes": {
|
||||
"route": {
|
||||
"label": "f1-circuits",
|
||||
"endpoint": "web"
|
||||
}
|
||||
},
|
||||
"binds": {
|
||||
"route": "${dir:state}/route.json"
|
||||
},
|
||||
"listens": [
|
||||
{
|
||||
"name": "web",
|
||||
"port": 8000,
|
||||
"protocol": "tcp",
|
||||
"from": "mesh",
|
||||
"why": "the track-layout CDN, the race posters and the Kometa metadata over http; its public name is a route grant and the proxy reaches it here. Kometa fetches the metadata and every poster by that public name"
|
||||
}
|
||||
],
|
||||
"resources": [
|
||||
{
|
||||
"id": "state",
|
||||
"type": "directory",
|
||||
"mode": "0700",
|
||||
"place": "."
|
||||
},
|
||||
{
|
||||
"id": "cache",
|
||||
"type": "directory",
|
||||
"mode": "0700"
|
||||
},
|
||||
{
|
||||
"id": "site-env",
|
||||
"type": "file",
|
||||
"path": "${dir:state}/site.env",
|
||||
"mode": "0644",
|
||||
"content": "F1_CIRCUITS_BASE_URL=https://${bound:route:name}\n"
|
||||
},
|
||||
{
|
||||
"id": "server",
|
||||
"type": "container",
|
||||
"name": "f1-circuits",
|
||||
"artifact": "cdn",
|
||||
"ports": [
|
||||
"8000"
|
||||
],
|
||||
"env-file": [
|
||||
"${dir:state}/site.env"
|
||||
],
|
||||
"volumes": [
|
||||
"${dir:cache}:/app/cache"
|
||||
],
|
||||
"restart-on": [
|
||||
"site-env"
|
||||
]
|
||||
}
|
||||
],
|
||||
"build": {
|
||||
"on": [
|
||||
{
|
||||
"arg": "PYTHON_BASE",
|
||||
"image": "python@sha256:6d43704baacd1bfbe7c295d7f13079d5d8104ed33568873133f8fc69980419df"
|
||||
}
|
||||
],
|
||||
"artifacts": [
|
||||
{
|
||||
"name": "cdn",
|
||||
"kind": "image",
|
||||
"from": "service/Dockerfile"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user