diff --git a/go/delivery/placement_proposal.go b/go/delivery/placement_proposal.go index 4d774ab..80656ec 100644 --- a/go/delivery/placement_proposal.go +++ b/go/delivery/placement_proposal.go @@ -85,9 +85,9 @@ type PlacementProposalChange struct { // BeforeLease is why the change cannot be proposed before the lease write, or "" (ADR 0567 §8): until then the holder // keeps the controller's assignments in step through its verbs assign, unassign, pin and unpin, so only those are -// proposable — a module placed or taken off with no host port or binding, a pin set or removed, and the seed. A host -// port, a binding, a holding, a decided field and a config layer's places or accesses wait for the lease write, which -// the refusal names. +// proposable — a module placed or taken off with no host port or binding, a pin set or removed, a module's config values +// and the seed. A host port, a binding, a holding, a decided field and a config layer's places or accesses wait for the +// lease write, which the refusal names. func (c PlacementProposalChange) BeforeLease() string { const lease = "which the controller's verbs cannot take from a caller, so it waits for the lease write (ADR 0567 §8)" switch c.Op { @@ -96,6 +96,12 @@ func (c PlacementProposalChange) BeforeLease() string { return fmt.Sprintf("the place of %s on %s names host ports or bindings, %s", c.Module, c.Node, lease) } case OpTakeOff, OpPin, OpUnpin, OpSeed: + case OpConfig: + // A module's config values are the state's alone (§13); its layers' places and accesses are the controller's + // until the lease write. + if c.MeshWide != nil || c.Layer != nil { + return fmt.Sprintf("the config of %s on %s sets a layer's places or accesses, %s", c.Module, c.Node, lease) + } default: return fmt.Sprintf("a change %s of %s is no assignment or pin, %s", c.Op, c.Node, lease) } diff --git a/go/delivery/placement_test.go b/go/delivery/placement_test.go index 78cffc3..bca020c 100644 --- a/go/delivery/placement_test.go +++ b/go/delivery/placement_test.go @@ -503,7 +503,9 @@ func TestPlacement(t *testing.T) { {Op: OpPin, Node: "g14"}: false, {Op: OpUnpin, Node: "g14"}: false, {Op: OpSeed, Node: "g14"}: false, {Op: OpPlace, Node: "g14", Module: "x", Ports: map[string]int{"80": 80}}: true, {Op: OpPlace, Node: "g14", Module: "x", Bindings: map[string]Provider{"p": {}}}: true, - {Op: OpHold, Node: "g14"}: true, {Op: OpDecide, Node: "g14"}: true, {Op: OpConfig, Node: "g14"}: true, + {Op: OpHold, Node: "g14"}: true, {Op: OpDecide, Node: "g14"}: true, + {Op: OpConfig, Node: "g14", Values: map[string]any{"puid": 1}}: false, {Op: OpConfig, Node: "g14", MeshValues: map[string]any{"a": 1}}: false, + {Op: OpConfig, Node: "g14", Layer: map[string]any{"places": 1}}: true, {Op: OpConfig, Node: "g14", MeshWide: map[string]any{"accesses": 1}}: true, } { if got := change.BeforeLease(); (got != "") != waits || (waits && !strings.Contains(got, "lease write")) { t.Errorf("%+v before the lease write: %q", *change, got)