Keep the client filling secrets and reading the controller's assignments until the lease write; plans for held modules; warrant says yes
Review round 3 (issue 1954): the node-engine of today writes ${secret:} as given and the new one fills only
provision keys, so the client fills secrets this release; plans exist only for modules with a want, so a
module without a seat plan is read from the controller's assignment and never leaves for want of one, and
the holder composes held modules at the build they run; the SDK's provider lets go only on "yes".
This commit is contained in:
@@ -103,6 +103,13 @@ func (h *Holder) ComposeNode(ctx context.Context, node string) (Composed, error)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
// A module held on the node with no want (the bus on the control-node) is composed at the build its have says it
|
||||
// runs, so it has a plan too and its client keeps filling it (review of 2026-10-30).
|
||||
for module, fp := range h.runningOn(node) {
|
||||
if _, ok := wanted[module]; !ok {
|
||||
wanted[module] = fp
|
||||
}
|
||||
}
|
||||
atWants, err := h.Compose(ctx, node, wanted)
|
||||
if err != nil {
|
||||
return out, fmt.Errorf("the plans of %s cannot be composed: %w", node, err)
|
||||
@@ -266,6 +273,30 @@ func (h *Holder) wantedOn(node string) (map[string]string, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// runningOn is the fingerprint each module's have on a node says it runs, by module: what a module held without a want
|
||||
// is composed at.
|
||||
func (h *Holder) runningOn(node string) map[string]string {
|
||||
out := map[string]string{}
|
||||
keys, err := h.Store.Keys(HaveRead)
|
||||
if err != nil {
|
||||
return out
|
||||
}
|
||||
for _, k := range keys {
|
||||
n, module, isNode, err := delivery.ParseHaveKey(k)
|
||||
if err != nil || isNode || n != node {
|
||||
continue
|
||||
}
|
||||
e, err := h.Store.Get(HaveRead, k)
|
||||
if err != nil || e == nil {
|
||||
continue
|
||||
}
|
||||
if have, err := delivery.DecodeHave(e.Value); err == nil && have.FP != "" {
|
||||
out[module] = have.FP
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// writePlans writes each plan that differs and removes the node's plans of modules no longer composed there.
|
||||
func (h *Holder) writePlans(node string, plans map[string]catalogue.Plan, out *Composed) error {
|
||||
var problems []error
|
||||
@@ -589,10 +620,12 @@ func (h *Holder) retired(key string, p provisions.Provision) (bool, string) {
|
||||
|
||||
// ---- the retiring ask ----------------------------------------------------------------------------------------------
|
||||
|
||||
// The options a retiring ask offers.
|
||||
// The options a retiring ask offers. The chosen one is the warrant's option in the key, and a provider lets its entry go
|
||||
// only on "yes" (mesh-sdk provider.go, the pass's retiring keys), so the approving option is "yes" (review of
|
||||
// 2026-10-30: the holder wrote "approve", which no provider acted on).
|
||||
const (
|
||||
OptionApprove = "approve"
|
||||
OptionDecline = "decline"
|
||||
OptionApprove = "yes"
|
||||
OptionDecline = "no"
|
||||
)
|
||||
|
||||
// askLasts is how long a retiring ask stays open.
|
||||
|
||||
@@ -290,6 +290,10 @@ func TestRetiringIsAskedAndActsOnlyOnTheWarrant(t *testing.T) {
|
||||
if w := m.state(t, pg).Warrant; w == nil || w.Option != OptionApprove || !strings.Contains(w.By, "42") {
|
||||
t.Fatalf("the warrant is not in the key: %+v", w)
|
||||
}
|
||||
// The word the SDK's provider lets an entry go on (provider.go): any other, and no provider ever retires it.
|
||||
if w := m.state(t, pg).Warrant; w.Option != "yes" {
|
||||
t.Fatalf("the warrant says %q, and a provider lets go only on \"yes\"", w.Option)
|
||||
}
|
||||
if said, _ := m.h.Rejudge(pg); said != "" || m.state(t, pg).State != provisions.Retiring {
|
||||
t.Errorf("retired while the provider's entry stands: %q", said)
|
||||
}
|
||||
@@ -310,6 +314,30 @@ func TestRetiringIsAskedAndActsOnlyOnTheWarrant(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Review of 2026-10-30: a module held on a node with no want (the bus on the control-node) is composed at the build
|
||||
// its have says it runs, so the holder writes it a plan and its client keeps filling it.
|
||||
func TestAModuleHeldWithoutAWantIsComposedAtTheBuildItRuns(t *testing.T) {
|
||||
m := newMesh()
|
||||
fp := "src2:" + strings.Repeat("dd", 32)
|
||||
m.s.write(t, HaveRead, "novox.nats", `{"v":1,"fp":"`+fp+`","phase":"running","health":"ok"}`)
|
||||
m.s.write(t, HaveRead, "g14.dunst", `{"v":1,"fp":"src2:`+strings.Repeat("ee", 32)+`","phase":"running","health":"ok"}`)
|
||||
var keptAt map[string]string
|
||||
m.h.Compose = func(_ context.Context, node string, at map[string]string) (map[string]catalogue.Plan, error) {
|
||||
if at != nil {
|
||||
keptAt = at
|
||||
return map[string]catalogue.Plan{"nats": {}}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
c := m.compose(t, "novox")
|
||||
if keptAt["nats"] != fp || len(keptAt) != 1 {
|
||||
t.Fatalf("composed at %v, want nats at the build it runs and nothing of another node", keptAt)
|
||||
}
|
||||
if !slices.Contains(c.Plans, "novox.nats") {
|
||||
t.Fatalf("no plan written for a module held without a want: %+v", c)
|
||||
}
|
||||
}
|
||||
|
||||
// The holder holds no ticker: it composes on change events alone (ADR 0570 clause 2; issue 1954 H1).
|
||||
func TestTheHolderHoldsNoTimer(t *testing.T) {
|
||||
files, _ := filepath.Glob("*.go")
|
||||
|
||||
Reference in New Issue
Block a user