H-20: a tools bundle's words hold its module's want fingerprint
Builds: design 47 G §519, §618
This commit is contained in:
@@ -388,8 +388,8 @@ func ToolsRunning(running []engcomp.Composed) map[string][]catalogue.Bundle {
|
||||
}
|
||||
var own map[string]string
|
||||
for w, v := range words[module] {
|
||||
if w == catalogue.FilesOwnedPaths || w == catalogue.ReadsSecretPlaces {
|
||||
continue // the mesh's to say, composed again
|
||||
if w == catalogue.FilesOwnedPaths || w == catalogue.ReadsSecretPlaces || w == engcomp.FingerprintVar {
|
||||
continue // the mesh's to say, composed again (the fingerprint is the want's, §519)
|
||||
}
|
||||
if own == nil {
|
||||
own = map[string]string{}
|
||||
|
||||
@@ -180,7 +180,12 @@ func TestCompositionsAreTheDeclarationSplitByModule(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if env[catalogue.RuntimeToolModules] != served || env[catalogue.RuntimeToolEnv] != `{"lamp":{"LAMP_CONF":"/var/lib/lamp/conf"}}` {
|
||||
// §519: the words each bundle's module is given hold the fingerprint of the want it applies, where there is one.
|
||||
words := `{"lamp":{"LAMP_CONF":"/var/lib/lamp/conf"}}`
|
||||
if fp := row.fps["lamp"]; fp != "" {
|
||||
words = `{"lamp":{"LAMP_CONF":"/var/lib/lamp/conf","MESH_FINGERPRINT":"` + fp + `"}}`
|
||||
}
|
||||
if env[catalogue.RuntimeToolModules] != served || env[catalogue.RuntimeToolEnv] != words {
|
||||
t.Errorf("%s: the runtime serves %v with %v, want what runs of lamp, %s", row.name,
|
||||
env[catalogue.RuntimeToolModules], env[catalogue.RuntimeToolEnv], served)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
seat "git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -203,6 +204,26 @@ func TestComparingCompositions(t *testing.T) {
|
||||
t.Errorf("the node's own carries %s: %s", FingerprintVar, raw)
|
||||
}
|
||||
}
|
||||
|
||||
// §519, §618: the tool runner's process hands each bundle's module its own want's fingerprint in the words of its
|
||||
// bundles, a module with bundles and no words included, and the runner's own fingerprint reaches no other module's.
|
||||
fpLamp, fpBare := "src2:"+strings.Repeat("1", 64), "src2:"+strings.Repeat("2", 64)
|
||||
runner, err := Split("novox", []json.RawMessage{json.RawMessage(`{"id":"r","type":"process","module":"nats","run":["x"],"env":{` +
|
||||
`"` + catalogue.RuntimeToolModules + `":"bare=/b/x,lamp=/l/y","` + catalogue.RuntimeToolEnv + `":"{\"lamp\":{\"LAMP_CONF\":\"/c\"}}"}}`)},
|
||||
map[string]string{"nats": fp, "lamp": fpLamp, "bare": fpBare}, nil, NodeOwn{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var proc struct{ Env map[string]string }
|
||||
_ = json.Unmarshal(runner[mustKey(t, "novox", "nats", fp)].Resources[0], &proc)
|
||||
var given map[string]map[string]string
|
||||
if err := json.Unmarshal([]byte(proc.Env[catalogue.RuntimeToolEnv]), &given); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if given["lamp"][FingerprintVar] != fpLamp || given["lamp"]["LAMP_CONF"] != "/c" || given["bare"][FingerprintVar] != fpBare ||
|
||||
len(given["nats"]) != 0 || proc.Env[FingerprintVar] != fp {
|
||||
t.Errorf("the bundles' words are %v and the runner's env %v", given, proc.Env)
|
||||
}
|
||||
}
|
||||
|
||||
func mustKey(t *testing.T, node, module, fp string) string {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
|
||||
@@ -239,6 +240,9 @@ func Split(node string, resources []json.RawMessage, fps map[string]string, fill
|
||||
if raw, err = withFingerprint(raw, head.Type, fps[head.Module]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if raw, err = withBundleFingerprints(raw, head.Type, fps); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
c := out[key]
|
||||
c.Resources = append(c.Resources, raw)
|
||||
@@ -286,3 +290,62 @@ func withFingerprint(raw json.RawMessage, kind, fp string) (json.RawMessage, err
|
||||
fields["env"] = body
|
||||
return json.Marshal(fields)
|
||||
}
|
||||
|
||||
// withBundleFingerprints is raw, when it is a process whose env hands tools bundles their words (catalogue.RuntimeToolEnv),
|
||||
// with each module's words holding FingerprintVar set to that module's fingerprint in fps: a bundle reads the fingerprint of
|
||||
// its own module's want from the environment the tool runner starts it with (design 47 G §519). A module fps names no
|
||||
// fingerprint for keeps its words, and the runner's own fingerprint reaches no bundle but its own module's (§618).
|
||||
func withBundleFingerprints(raw json.RawMessage, kind string, fps map[string]string) (json.RawMessage, error) {
|
||||
if kind != string(declaration.TypeProcess) {
|
||||
return raw, nil
|
||||
}
|
||||
var fields map[string]json.RawMessage
|
||||
if err := json.Unmarshal(raw, &fields); err != nil {
|
||||
return nil, fmt.Errorf("compositions: a %s resource is not JSON: %w", kind, err)
|
||||
}
|
||||
var env map[string]string
|
||||
if had, ok := fields["env"]; !ok || json.Unmarshal(had, &env) != nil || env[catalogue.RuntimeToolModules] == "" {
|
||||
return raw, nil
|
||||
}
|
||||
given := map[string]map[string]string{}
|
||||
if had := env[catalogue.RuntimeToolEnv]; had != "" {
|
||||
if err := json.Unmarshal([]byte(had), &given); err != nil {
|
||||
return nil, fmt.Errorf("compositions: the %s of a process is not words by module: %w", catalogue.RuntimeToolEnv, err)
|
||||
}
|
||||
}
|
||||
for module, words := range given {
|
||||
if fp := fps[module]; fp != "" {
|
||||
if words == nil {
|
||||
words = map[string]string{}
|
||||
given[module] = words
|
||||
}
|
||||
words[FingerprintVar] = fp
|
||||
}
|
||||
}
|
||||
for module, fp := range fps { // a module with bundles and no words of its own still reads its fingerprint
|
||||
if _, has := given[module]; !has && fp != "" && hasLoadedBundle(env, module) {
|
||||
given[module] = map[string]string{FingerprintVar: fp}
|
||||
}
|
||||
}
|
||||
body, err := json.Marshal(given)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
env[catalogue.RuntimeToolEnv] = string(body)
|
||||
envBody, err := json.Marshal(env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fields["env"] = envBody
|
||||
return json.Marshal(fields)
|
||||
}
|
||||
|
||||
// hasLoadedBundle is whether the runtime's served list (catalogue.RuntimeToolModules, `module=path` entries) names a bundle of module.
|
||||
func hasLoadedBundle(env map[string]string, module string) bool {
|
||||
for _, entry := range strings.Split(env[catalogue.RuntimeToolModules], ",") {
|
||||
if strings.HasPrefix(entry, module+"=") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user