A held module is no dependence of its neighbours: its hold stops spreading (issue 1126)
mesh/delivery merged: source.main moved to novox/mesh-sdk@394fec8a63c1
mesh/delivery-group group fix/1126-held-as-runs merged: every member is merged
mesh/check pass c2999a4e13cc on d4c61ee8ffd0 | unit 3054 run, 234 kept, 36 skipped | integration 3075 run, 266 kept, 29 skipped | over bound: unit (sl…
mesh/delivery merged: source.main moved to novox/mesh-sdk@394fec8a63c1
mesh/delivery-group group fix/1126-held-as-runs merged: every member is merged
mesh/check pass c2999a4e13cc on d4c61ee8ffd0 | unit 3054 run, 234 kept, 36 skipped | integration 3075 run, 266 kept, 29 skipped | over bound: unit (sl…
novox's seed p-20261028t231141-ec84b4 refused 11 modules "what it composes of ..., held, is not what runs of them": de-spiegel's hold spread through mailu to postgres, nftables and route-proxy, and from postgres to every consumer, and gitea, held so, refused the node: "its credential of postgres-database is handed to the provisioner and the module is not: nothing would fill it". Three rounds each moved the error. The kind: a held module still took part in the composition as a dependence, so its hold spread. - The quick fix: let heldAsToday also follow dependsOnHeld's words, and skip the handed refusal for gitea. It moves the error once more and leaves every node's applying path holding consumers. - The thorough fix, chosen: a held module composes only as what runs of it. composeEach no longer compares the composition with each held module as its stub (dependsOnHeld removed): a consumer or collector composes against what runs of the held module like any other module, and a real difference is still a named difference in the answer, a module's own refusal still its refusal. A stub (compose.Stub, catalogue.Manifest.Stubbed) leaves the credentials and own secrets it would hand the provisioner out of its plan as they run, never refused for want of a plan. Only what a held module's new manifest says to others in their own files is still held behind it (dependents: the provider of what it contributes to, the filter where it listens), which heldAsToday already follows. Tests: rows added to existing tests (a held provider with a binding consumer, which the old code held in the seed's words; a held feeder of a collector; a held module with a handed credential and own secret). No new test function.
This commit is contained in:
@@ -2,7 +2,6 @@ package frombus
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"slices"
|
||||
@@ -11,7 +10,6 @@ import (
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/compose"
|
||||
"git.novox.be/novox/mesh-sdk/go/declaration"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
)
|
||||
|
||||
@@ -312,11 +310,14 @@ func standsInFor(x, node string) (string, string) {
|
||||
// **A held module is what runs of it** (review of the apply, round 1): composed from what running holds of it
|
||||
// (compose.Carried of its own composition there; the node's own carries it wherever it runs there), so what the others
|
||||
// read of it (the machine ports its containers publish, the routes reaching it) is what runs, and none of its own
|
||||
// composition is in out: the node keeps what it last applied. **What depends on how it is held is held too:** a module
|
||||
// whose composition differs when the held ones are composed as their stubs instead is held with them, and a node's own
|
||||
// composition that differs (but for the held modules' own resources) refuses the node. And since a held module is
|
||||
// composed from its new manifest, which may not be the build's that runs, what reads that manifest is held with it
|
||||
// (dependents): the providers of what it contributes to (the proxy its routes), and, when it listens, the filter.
|
||||
// composition is in out: the node keeps what it last applied. **A held module is no dependence of its neighbours**
|
||||
// (issue 1126, the spreading hold): a consumer of what it provides, or a collector of its items, composes against what
|
||||
// runs of it like any other module, and is never held for how the held one would compose as its stub (that comparison
|
||||
// held every postgres consumer behind de-spiegel's hold on novox, three rounds in a row). What it composes is compared
|
||||
// with what runs as any module's is: a real difference is still named, and a refusal of its own still refuses it. Only
|
||||
// what a held module's new manifest says to others, which may not be the build's that runs, is held with it
|
||||
// (dependents): the providers of what it contributes to in their own files (the proxy its routes), and, when it
|
||||
// listens, the filter; its items reach their collectors through its own plan, which it keeps as it runs.
|
||||
func composeEach(in compose.Input, node string, fps map[string]string, applied bool, running []delivery.Composed, failed map[string]string) (out map[string]delivery.Composed, skipped, stood []string, err error) {
|
||||
mode := compose.Foreseeing
|
||||
if applied {
|
||||
@@ -392,17 +393,6 @@ func composeEach(in compose.Input, node string, fps map[string]string, applied b
|
||||
return nil, nil, nil, fmt.Errorf("%w on %s: %s", compose.ErrStoodIn, node, strings.Join(nodes, ", "))
|
||||
}
|
||||
}
|
||||
if !again && len(failed) > 0 {
|
||||
dependent, own := dependsOnHeld(in, node, fps, mode, out, src, bareOf, failed)
|
||||
if own {
|
||||
return nil, nil, nil, fmt.Errorf("frombus: %s's own composition depends on how %s, held, is composed, and is not applied",
|
||||
node, strings.Join(sortedKeys(failed), ", "))
|
||||
}
|
||||
for _, m := range dependent {
|
||||
hold(m, "what it composes of "+strings.Join(sortedKeys(failed), ", ")+", held, is not what runs of them", false)
|
||||
again = true
|
||||
}
|
||||
}
|
||||
if !again {
|
||||
break
|
||||
}
|
||||
@@ -411,80 +401,6 @@ func composeEach(in compose.Input, node string, fps map[string]string, applied b
|
||||
return out, skipped, stood, nil
|
||||
}
|
||||
|
||||
// dependsOnHeld composes in again with each held module as its stub rather than as what runs of it, and answers the
|
||||
// modules, not held, whose composition differs between the two (sorted), and own when the node's own composition does
|
||||
// but for the held modules' own resources. A composition of stubs that fails says nothing more: what runs composed.
|
||||
func dependsOnHeld(in compose.Input, node string, fps map[string]string, mode compose.Mode, asRuns map[string]delivery.Composed,
|
||||
src map[string]catalogue.Manifest, bareOf map[string]bool, failed map[string]string) (dependent []string, own bool) {
|
||||
stubs := in
|
||||
for _, m := range sortedKeys(failed) {
|
||||
if man, ok := src[m]; ok {
|
||||
stubs = heldAs(stubs, node, m, man, bareOf[m], nil)
|
||||
}
|
||||
}
|
||||
asStubs, _, _, err := compose.CompositionsIn(stubs, node, fps, mode)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
isHeld := func(m string) bool { _, ok := failed[m]; return ok }
|
||||
keys := map[string]bool{}
|
||||
for k := range asRuns {
|
||||
keys[k] = true
|
||||
}
|
||||
for k := range asStubs {
|
||||
keys[k] = true
|
||||
}
|
||||
for _, k := range sortedKeys(keys) {
|
||||
a, inA := asRuns[k]
|
||||
b, inB := asStubs[k]
|
||||
m := a.Module
|
||||
if !inA {
|
||||
m = b.Module
|
||||
}
|
||||
if m != "" && isHeld(m) {
|
||||
continue
|
||||
}
|
||||
if m == "" {
|
||||
a, b = withoutHeld(a, isHeld), withoutHeld(b, isHeld)
|
||||
}
|
||||
da, errA := delivery.ComposedDigestOf(a)
|
||||
db, errB := delivery.ComposedDigestOf(b)
|
||||
if inA == inB && errA == nil && errB == nil && da == db {
|
||||
continue
|
||||
}
|
||||
if m == "" {
|
||||
own = true
|
||||
continue
|
||||
}
|
||||
dependent = append(dependent, m)
|
||||
}
|
||||
return dependent, own
|
||||
}
|
||||
|
||||
// withoutHeld is the node's own composition c without the resources of a held module (its id naming it) and without
|
||||
// its filled paths, for comparing the rest.
|
||||
func withoutHeld(c delivery.Composed, isHeld func(string) bool) delivery.Composed {
|
||||
out := c
|
||||
out.Filled = nil
|
||||
out.Resources = nil
|
||||
for _, raw := range c.Resources {
|
||||
var head struct {
|
||||
ID string `json:"id"`
|
||||
Module string `json:"module"`
|
||||
}
|
||||
_ = json.Unmarshal(raw, &head)
|
||||
owner := head.Module
|
||||
if owner == "" {
|
||||
owner, _ = declaration.ModuleGuess(head.ID)
|
||||
}
|
||||
if owner != "" && isHeld(owner) {
|
||||
continue
|
||||
}
|
||||
out.Resources = append(out.Resources, raw)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// dependents is, of the modules placed on node and not held, those that read what man says to them: each that provides
|
||||
// what man contributes to (the proxy its routes), and, when man listens on a port, each that holds the filter (the
|
||||
// openings).
|
||||
|
||||
Reference in New Issue
Block a user