A runtime compiled to a binary runs itself (hq ADR 0193)
A compiled bundle records the binary it is (BinaryOf, shared by the builder and the composer), and the node's runtime, when it is one, is run as ./<binary> from its own unpacked bundle rather than by an interpreter and an entrypoint.
This commit is contained in:
@@ -1171,6 +1171,9 @@ func readBy(manifest catalogue.Manifest) []catalogue.ArtifactContext {
|
|||||||
// binaryName is what a compiled bundle's executable is called: what the artifact says, or the name of
|
// binaryName is what a compiled bundle's executable is called: what the artifact says, or the name of
|
||||||
// the package it is built from, which is what a compiler would have chosen anyway.
|
// the package it is built from, which is what a compiler would have chosen anyway.
|
||||||
func binaryName(a catalogue.Artifact) string {
|
func binaryName(a catalogue.Artifact) string {
|
||||||
|
if name := catalogue.BinaryOf(a); name != "" {
|
||||||
|
return name
|
||||||
|
}
|
||||||
if name := strings.TrimSpace(a.Binary); name != "" {
|
if name := strings.TrimSpace(a.Binary); name != "" {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package catalogue
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -96,6 +97,7 @@ func (m Manifest) Resolve(built []Built) (Manifest, error) {
|
|||||||
Name: a.Name, Source: Recorded(made.Reference), Digest: made.Digest,
|
Name: a.Name, Source: Recorded(made.Reference), Digest: made.Digest,
|
||||||
Language: a.Language, Entrypoints: append([]string(nil), a.Entrypoints...),
|
Language: a.Language, Entrypoints: append([]string(nil), a.Entrypoints...),
|
||||||
Loads: loads, Env: copyWords(a.Env), Launchers: copyWords(made.Launchers),
|
Loads: loads, Env: copyWords(a.Env), Launchers: copyWords(made.Launchers),
|
||||||
|
Binary: BinaryOf(a),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
sort.Slice(out.Bundles, func(i, j int) bool { return out.Bundles[i].Name < out.Bundles[j].Name })
|
sort.Slice(out.Bundles, func(i, j int) bool { return out.Bundles[i].Name < out.Bundles[j].Name })
|
||||||
@@ -417,3 +419,20 @@ func copyWords(in map[string]string) map[string]string {
|
|||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BinaryOf is what a bundle compiled to a binary is called once built: what the artifact names, else
|
||||||
|
// the package it is built from, else the artifact's own name (novox/hq 04-ISSUES/142). Empty for a
|
||||||
|
// language that does not compile to one. The builder writes the binary under this name, and the
|
||||||
|
// composer runs it by it, so both ask here.
|
||||||
|
func BinaryOf(a Artifact) string {
|
||||||
|
if !compilesToABinary(a.Language) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if name := strings.TrimSpace(a.Binary); name != "" {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
if from := strings.Trim(a.From, "./"); from != "" {
|
||||||
|
return path.Base(from)
|
||||||
|
}
|
||||||
|
return a.Name
|
||||||
|
}
|
||||||
|
|||||||
@@ -607,6 +607,9 @@ type Bundle struct {
|
|||||||
// Launchers are the executables the build wrote beside its entrypoints, by entrypoint (novox/hq
|
// Launchers are the executables the build wrote beside its entrypoints, by entrypoint (novox/hq
|
||||||
// ADR 0193). A bundle built before them has none, and is served as it was built.
|
// ADR 0193). A bundle built before them has none, and is served as it was built.
|
||||||
Launchers map[string]string `json:"launchers,omitempty"`
|
Launchers map[string]string `json:"launchers,omitempty"`
|
||||||
|
// Binary is the executable a bundle compiled to a binary is, at its root (novox/hq ADR 0193):
|
||||||
|
// what runs it, where an interpreted bundle names an interpreter and an entrypoint.
|
||||||
|
Binary string `json:"binary,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build says how to produce this module's artifacts from its source.
|
// Build says how to produce this module's artifacts from its source.
|
||||||
|
|||||||
@@ -129,14 +129,22 @@ func (r Resolution) runtimeProcess(with Rendering) (map[string]any, error) {
|
|||||||
RuntimeModule, r.Node, len(runtime.Bundles))
|
RuntimeModule, r.Node, len(runtime.Bundles))
|
||||||
}
|
}
|
||||||
bundle := runtime.Bundles[0]
|
bundle := runtime.Bundles[0]
|
||||||
if len(bundle.Entrypoints) != 1 {
|
// What runs it (novox/hq ADR 0193): a runtime compiled to a binary runs itself, from its own
|
||||||
return nil, fmt.Errorf(
|
// unpacked bundle; an interpreted one is its language's interpreter and its one entrypoint.
|
||||||
"%s's bundle %q names %d entrypoint(s); the runtime is run from one, so the module "+
|
var run []any
|
||||||
"declares exactly one (novox/hq to-be 38)", RuntimeModule, bundle.Name, len(bundle.Entrypoints))
|
if bundle.Binary != "" {
|
||||||
}
|
run = []any{"./" + bundle.Binary}
|
||||||
interpreter, err := interpreterFor(bundle.Language)
|
} else {
|
||||||
if err != nil {
|
if len(bundle.Entrypoints) != 1 {
|
||||||
return nil, err
|
return nil, fmt.Errorf(
|
||||||
|
"%s's bundle %q names %d entrypoint(s); the runtime is run from one, so the module "+
|
||||||
|
"declares exactly one (novox/hq to-be 38)", RuntimeModule, bundle.Name, len(bundle.Entrypoints))
|
||||||
|
}
|
||||||
|
interpreter, err := interpreterFor(bundle.Language)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
run = []any{interpreter, bundle.Entrypoints[0]}
|
||||||
}
|
}
|
||||||
credential, declared := runtime.OwnSecrets["broker"]
|
credential, declared := runtime.OwnSecrets["broker"]
|
||||||
if !declared {
|
if !declared {
|
||||||
@@ -198,7 +206,7 @@ func (r Resolution) runtimeProcess(with Rendering) (map[string]any, error) {
|
|||||||
process := map[string]any{
|
process := map[string]any{
|
||||||
"id": RuntimeModule + "." + RuntimeProcessID(), "type": "process", "name": RuntimeModule,
|
"id": RuntimeModule + "." + RuntimeProcessID(), "type": "process", "name": RuntimeModule,
|
||||||
"source": bundle.Source, "digest": bundle.Digest,
|
"source": bundle.Source, "digest": bundle.Digest,
|
||||||
"run": []any{interpreter, bundle.Entrypoints[0]},
|
"run": run,
|
||||||
"env": env,
|
"env": env,
|
||||||
"restart-on": toAny(restartOn),
|
"restart-on": toAny(restartOn),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -362,3 +362,30 @@ func TestTheRuntimeStartsTheLauncherWhereTheBuildWroteOne(t *testing.T) {
|
|||||||
t.Errorf("the runtime is told %q, want %q", env[RuntimeToolModules], want)
|
t.Errorf("the runtime is told %q, want %q", env[RuntimeToolModules], want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// novox/hq ADR 0193: a runtime compiled to a binary runs itself from its own unpacked bundle.
|
||||||
|
func TestARuntimeCompiledToABinaryRunsItself(t *testing.T) {
|
||||||
|
with := Rendering{ArtifactStore: "anchor.internal:5101",
|
||||||
|
Needed: map[string]map[string]string{RuntimeModule: {"broker": "sealed-credential"}}}
|
||||||
|
goRuntime := Manifest{Module: RuntimeModule, Version: "1",
|
||||||
|
OwnSecrets: OwnSecrets{"broker": {Path: "/var/lib/mesh/" + RuntimeModule + "/broker"}},
|
||||||
|
Build: &Build{Artifacts: []Artifact{{Name: "runtime", Kind: ArtifactBundle, Language: "go",
|
||||||
|
System: "arch", From: "cmd/node-tools"}}}}
|
||||||
|
goRuntime, err := goRuntime.Resolve([]Built{{Name: "runtime", Kind: ArtifactBundle,
|
||||||
|
Reference: ArtifactStoreScheme + RuntimeModule + "/runtime/blobs/" + bundleDigest, Digest: bundleDigest}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
out, err := Resolution{Node: "anchor", Account: "ops", Modules: []Manifest{aToolsModule(t, "nftables", "tools/index.js"), goRuntime}}.Declaration(with)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
process := fileNamed(out, RuntimeModule+"."+RuntimeProcessID())
|
||||||
|
if fmt.Sprint(process["run"]) != "[./node-tools]" {
|
||||||
|
t.Errorf("a Go runtime is run as %v, want its own binary", process["run"])
|
||||||
|
}
|
||||||
|
env := process["env"].(map[string]string)
|
||||||
|
if env[RuntimeToolModules] == "" || process["user"] != "ops" {
|
||||||
|
t.Errorf("the Go runtime is not told what to serve or whose it is: %v %v", env, process["user"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user