A-342 engine-node-env: every process runs with its node's name as MESH_NODE
The apply gives each process the declaration's For as MESH_NODE beside its own env, so a process that reads MESH_NODE (mesh-sdk, the zfs follower's writer and its node-service-manager calls) names its node. Builds: design 47 G A-342 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -785,7 +785,7 @@ func applyScoped(
|
|||||||
// change one apply late, and never misses it.
|
// change one apply late, and never misses it.
|
||||||
// And one patience with the artifact store for the whole apply (novox/hq issue 291): a fetch it
|
// And one patience with the artifact store for the whole apply (novox/hq issue 291): a fetch it
|
||||||
// does not answer during a maintenance window waits for the window instead of failing.
|
// does not answer during a maintenance window waits for the window instead of failing.
|
||||||
in := inputs{declares: map[string]string{}, known: &known, windows: windows, away: newStoreAway(windows, log),
|
in := inputs{node: d.For, declares: map[string]string{}, known: &known, windows: windows, away: newStoreAway(windows, log),
|
||||||
groups: wanted, handed: handed}
|
groups: wanted, handed: handed}
|
||||||
// Where nothing is placed or mounted from, judged before anything is applied (novox/hq issue 339), and
|
// Where nothing is placed or mounted from, judged before anything is applied (novox/hq issue 339), and
|
||||||
// which declared directories were already here: one this apply makes is the mesh's, one found may not be.
|
// which declared directories were already here: one this apply makes is the mesh's, one found may not be.
|
||||||
@@ -1625,7 +1625,7 @@ func applyOne(ctx context.Context, sys system.System, r declaration.Resource, ru
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return begin(r), err
|
return begin(r), err
|
||||||
}
|
}
|
||||||
return applyProcess(ctx, res, run, changed, previous, held, in.away)
|
return applyProcess(ctx, withNode(res, in.node), run, changed, previous, held, in.away)
|
||||||
case *declaration.Action:
|
case *declaration.Action:
|
||||||
return applyAction(ctx, res, run)
|
return applyAction(ctx, res, run)
|
||||||
case *declaration.Network:
|
case *declaration.Network:
|
||||||
@@ -2816,6 +2816,9 @@ type inputs struct {
|
|||||||
// fetched is every archive's and process's bytes this apply fetched before anything was replaced (fetchFirst), each
|
// fetched is every archive's and process's bytes this apply fetched before anything was replaced (fetchFirst), each
|
||||||
// taken by its applier once (artifact).
|
// taken by its applier once (artifact).
|
||||||
fetched map[string]fetchedArtifact
|
fetched map[string]fetchedArtifact
|
||||||
|
// node is the node's own name, the declaration's For: every process runs with it as MESH_NODE beside its own env
|
||||||
|
// (design 47 G A-342). Empty where the declaration names none (the first node's carried bundle).
|
||||||
|
node string
|
||||||
}
|
}
|
||||||
|
|
||||||
// fileDigest is what a file the container reads holds, by digest.
|
// fileDigest is what a file the container reads holds, by digest.
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ func WriteFilledWith(
|
|||||||
"yet taken (%s), so nothing was written", path, held.Why)}
|
"yet taken (%s), so nothing was written", path, held.Why)}
|
||||||
}
|
}
|
||||||
|
|
||||||
in := inputs{declares: map[string]string{}, known: &known, windows: windows, away: newStoreAway(windows, log),
|
in := inputs{node: d.For, declares: map[string]string{}, known: &known, windows: windows, away: newStoreAway(windows, log),
|
||||||
groups: groupsWanted(d.Resources), handed: Handed{}}
|
groups: groupsWanted(d.Resources), handed: Handed{}}
|
||||||
in.refused = refusedPlaces(d.Resources)
|
in.refused = refusedPlaces(d.Resources)
|
||||||
in.agentHomes = rootNeverHomes(d)
|
in.agentHomes = rootNeverHomes(d)
|
||||||
|
|||||||
@@ -274,6 +274,25 @@ func applyProcess(ctx context.Context, r *declaration.Process, run Runner,
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NodeEnv is the variable every process the node-engine runs reads its node's name from (design 47 G A-342), the one
|
||||||
|
// mesh-sdk reads (MESH_NODE).
|
||||||
|
const NodeEnv = "MESH_NODE"
|
||||||
|
|
||||||
|
// withNode is the process as it runs on node: its own env with NodeEnv beside it (design 47 G A-342). The validator
|
||||||
|
// refuses a resource that sets it, so the mesh's value is the only one; with no node named the process is as declared.
|
||||||
|
func withNode(r *declaration.Process, node string) *declaration.Process {
|
||||||
|
if node == "" {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
p := *r
|
||||||
|
p.Env = make(map[string]string, len(r.Env)+1)
|
||||||
|
for k, v := range r.Env {
|
||||||
|
p.Env[k] = v
|
||||||
|
}
|
||||||
|
p.Env[NodeEnv] = node
|
||||||
|
return &p
|
||||||
|
}
|
||||||
|
|
||||||
// unitFor is the unit the mesh writes for a daemon.
|
// unitFor is the unit the mesh writes for a daemon.
|
||||||
//
|
//
|
||||||
// **Generated whole and never edited in place**, the same rule as every other managed file: an
|
// **Generated whole and never edited in place**, the same rule as every other managed file: an
|
||||||
|
|||||||
@@ -319,11 +319,17 @@ func TestAProcessAppliedAgainIsUnchangedAndNotRestarted(t *testing.T) {
|
|||||||
}
|
}
|
||||||
d := declare(t, `{"id":"node-tools.runtime","type":"process","name":"node-tools","source":"`+serving(t, body)+
|
d := declare(t, `{"id":"node-tools.runtime","type":"process","name":"node-tools","source":"`+serving(t, body)+
|
||||||
`","digest":"`+digest+`","run":["node","main.js"],"env":{"MESH_TOOL_MODULES":"a=/x/index.js"}}`)
|
`","digest":"`+digest+`","run":["node","main.js"],"env":{"MESH_TOOL_MODULES":"a=/x/index.js"}}`)
|
||||||
|
d.For = "anchor"
|
||||||
|
|
||||||
first, state, err := Apply(context.Background(), archHost(t), d, store.State{}, store.OriginDeclared, run, nil, nil)
|
first, state, err := Apply(context.Background(), archHost(t), d, store.State{}, store.OriginDeclared, run, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
// Design 47 G A-342: the process runs with its node's name as MESH_NODE beside its own env.
|
||||||
|
if b, err := os.ReadFile(filepath.Join(units, "node-tools.service")); err != nil || !strings.Contains(string(b), `Environment="MESH_NODE=anchor"`) ||
|
||||||
|
!strings.Contains(string(b), `Environment="MESH_TOOL_MODULES=`) {
|
||||||
|
t.Errorf("the unit does not carry the node's name beside its env (%v):\n%s", err, b)
|
||||||
|
}
|
||||||
if o := outcomeOf(first, "node-tools.runtime"); o.Action != "created" {
|
if o := outcomeOf(first, "node-tools.runtime"); o.Action != "created" {
|
||||||
t.Fatalf("first apply: %+v, want created", o)
|
t.Fatalf("first apply: %+v, want created", o)
|
||||||
}
|
}
|
||||||
@@ -360,6 +366,7 @@ func TestAProcessAppliedAgainIsUnchangedAndNotRestarted(t *testing.T) {
|
|||||||
// An input of its unit that differs restarts it, and the line says which (issue 1966).
|
// An input of its unit that differs restarts it, and the line says which (issue 1966).
|
||||||
changed := declare(t, `{"id":"node-tools.runtime","type":"process","name":"node-tools","source":"`+serving(t, body)+
|
changed := declare(t, `{"id":"node-tools.runtime","type":"process","name":"node-tools","source":"`+serving(t, body)+
|
||||||
`","digest":"`+digest+`","run":["node","main.js"],"env":{"MESH_TOOL_MODULES":"a=/x/index.js,b=/y/index.js"}}`)
|
`","digest":"`+digest+`","run":["node","main.js"],"env":{"MESH_TOOL_MODULES":"a=/x/index.js,b=/y/index.js"}}`)
|
||||||
|
changed.For = "anchor"
|
||||||
fourth, _, err := Apply(context.Background(), archHost(t), changed, state, store.OriginDeclared, run, nil, nil)
|
fourth, _, err := Apply(context.Background(), archHost(t), changed, state, store.OriginDeclared, run, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
Reference in New Issue
Block a user