Carry an unassigned port as the declaration publishes it, refusing only a port a module does not listen on (issue 774, research 072 row 34)
mesh/delivery merged: source.main moved to novox/mesh-sdk@fea48f19cea5
mesh/delivery-group group fix/route-ports merged: every member is merged
mesh/check failed: integration: mesh-vault/cmd/mesh-vault.TestTheVaultWholeMintsOnTheBusWhoeverHoldsTheLease: never: the account minted under the cont…
mesh/delivery merged: source.main moved to novox/mesh-sdk@fea48f19cea5
mesh/delivery-group group fix/route-ports merged: every member is merged
mesh/check failed: integration: mesh-vault/cmd/mesh-vault.TestTheVaultWholeMintsOnTheBusWhoeverHoldsTheLease: never: the account minted under the cont…
influxdb and unifi publish bare ports that mesh-placement assigns none: the machine runs them at the software's own number, so a plan refusing them held their whole plan for a route that works.
This commit is contained in:
+15
-19
@@ -221,12 +221,9 @@ type Rendering struct {
|
||||
// They win over anything the mesh would assign and over a manifest's own long-form mapping.
|
||||
Given map[string]map[int]int
|
||||
|
||||
// Unassigned is each port the mesh may assign that the placement holds no machine port for yet, by module and by the
|
||||
// port the software uses: in Ports it stands as the software's own number, which nothing on the machine published.
|
||||
Unassigned map[string]map[int]bool
|
||||
// Planned says this rendering composes the plans the seat mesh-provisioner keeps (compose.Planning). A contribution a
|
||||
// plan carries is then refused where its port has no machine port assigned (Ports, Given, Unassigned), never carried
|
||||
// as the software's own number: its provider dials what the plan says (issue 774, research 072 row 34).
|
||||
// plan carries is then refused where its port is none the module listens on: no machine port stands for it, and its
|
||||
// provider dials what the plan says (issue 774, research 072 row 34).
|
||||
Planned bool
|
||||
|
||||
// Taken is the modules taken on this adopted node (novox/hq ADR 0100). The guard is derived
|
||||
@@ -1891,30 +1888,29 @@ func (r Resolution) contributedOf(m Manifest, to string, with Rendering) (json.R
|
||||
return EncodeContributed(form)
|
||||
}
|
||||
|
||||
// atAssignedPort is a contribution of m with its port the machine port m's placement assigned it on this node, the
|
||||
// number `${port:<software port>}` gives m itself (port_into.go): what its provider dials, on this machine over loopback
|
||||
// and from another at m's address.
|
||||
// atAssignedPort is a contribution of m with its port where this machine publishes it for m: the number
|
||||
// `${port:<software port>}` gives m itself and its declaration publishes (machinePort, port_into.go), the placement's
|
||||
// assignment where it holds one and the software's own number where it holds none (a bare port not yet moved, a fixed
|
||||
// mapping, the host's network). What its provider dials, on this machine over loopback and from another at m's address.
|
||||
//
|
||||
// **Refused, never guessed, where a plan carries it** (with.Planned): a port the placement holds no machine port for is
|
||||
// said by module, node and port, since the software's own number is where nothing listens. Elsewhere (a declaration,
|
||||
// a composition with no placement) a port not known is left as it is, as machinePort leaves it.
|
||||
// **Refused where a plan carries a port m does not listen on** (with.Planned): no machine port stands for it, so the
|
||||
// provider would dial a number nothing on the machine is known to publish. Elsewhere (a declaration, a composition
|
||||
// with no ports) such a port is left as it is, as machinePort leaves it.
|
||||
func (r Resolution) atAssignedPort(m Manifest, to string, values map[string]any, with Rendering) (map[string]any, error) {
|
||||
number, ok := asPort(values["port"])
|
||||
if !ok {
|
||||
return values, nil
|
||||
}
|
||||
at, known := with.Given[m.Module][number]
|
||||
if !known && !with.Unassigned[m.Module][number] {
|
||||
at, known = with.Ports[m.Module][number]
|
||||
}
|
||||
if !known {
|
||||
_, given := with.Given[m.Module][number]
|
||||
_, placed := with.Ports[m.Module][number]
|
||||
if !given && !placed {
|
||||
if with.Planned {
|
||||
return nil, fmt.Errorf("%s contributing to %s: its port %d on %s has no machine port assigned in its placement, "+
|
||||
"so its provider would dial the software's own port, where nothing listens", m.Module, to, number, r.Node)
|
||||
return nil, fmt.Errorf("%s contributing to %s: its port %d on %s is none of the ports it listens on, so no "+
|
||||
"machine port stands for it", m.Module, to, number, r.Node)
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
return atMachinePort(values, m.Module, map[string]map[int]int{m.Module: {number: at}}), nil
|
||||
return atMachinePort(values, m.Module, map[string]map[int]int{m.Module: {number: with.machinePort(m.Module, number)}}), nil
|
||||
}
|
||||
|
||||
// composed is one contribution as its provider receives it: settled with this node's settings, its
|
||||
|
||||
+19
-18
@@ -114,29 +114,30 @@ func TestAModuleNotHandedHasAPlanForWhatAHelperAnswers(t *testing.T) {
|
||||
string(given.Each[1].Values) != `{"internal-name":"notify-api.anchor.internal","label":"notify-api","name":"notify-api.example.org","port":9000}` {
|
||||
t.Fatalf("the plan gives %+v (%v)", given, err)
|
||||
}
|
||||
// Its port is the machine port the placement assigned, the number ${port:9000} gives the module, never the software's
|
||||
// own (2026-10-31: route-proxy dialled gitea's 3000, published at 20000): its provider dials what the plan says, on
|
||||
// this machine over loopback and from another at the plan's address. Where a plan carries it, a port with none
|
||||
// assigned is refused by module, node and port.
|
||||
// Its port is where the machine publishes it, the number ${port:9000} gives the module and its declaration publishes,
|
||||
// never the software's own where the placement moved it (2026-10-31: route-proxy dialled gitea's 3000, published at
|
||||
// 20000): its provider dials what the plan says. Where a plan carries it, a port the module does not listen on is
|
||||
// refused by module, node and port.
|
||||
for _, p := range []struct {
|
||||
name string
|
||||
ports map[string]map[int]int
|
||||
given map[string]map[int]int
|
||||
unassigned map[string]map[int]bool
|
||||
planned bool
|
||||
port float64
|
||||
refused string
|
||||
name string
|
||||
ports map[string]map[int]int
|
||||
given map[string]map[int]int
|
||||
planned bool
|
||||
port float64
|
||||
refused string
|
||||
}{
|
||||
{"assigned by the placement", map[string]map[int]int{"notify": {9000: 20009}}, nil, nil, true, 20009, ""},
|
||||
{"assigned by the placement (gitea 3000 at 20000)", map[string]map[int]int{"notify": {9000: 20009}}, nil, true, 20009, ""},
|
||||
{"given by the node over the placement", map[string]map[int]int{"notify": {9000: 20009}},
|
||||
map[string]map[int]int{"notify": {9000: 9900}}, nil, true, 9900, ""},
|
||||
{"the placement holds none (foreseen)", map[string]map[int]int{"notify": {9000: 9000}}, nil,
|
||||
map[string]map[int]bool{"notify": {9000: true}}, true, 0, "notify contributing to route: its port 9000 on workstation has no machine port"},
|
||||
{"the module's ports are not on the machine at all", nil, nil, nil, true, 0, "its port 9000 on workstation"},
|
||||
{"a declaration with no placement leaves it as written", nil, nil, nil, false, 9000, ""},
|
||||
map[string]map[int]int{"notify": {9000: 9900}}, true, 9900, ""},
|
||||
{"a bare published port the placement holds none for keeps its number (influxdb 8086)",
|
||||
map[string]map[int]int{"notify": {9000: 9000}}, nil, true, 9000, ""},
|
||||
{"a mapping the module fixed (as mailu 7080:80)", map[string]map[int]int{"notify": {9000: 7080}}, nil, true, 7080, ""},
|
||||
{"a port the module does not listen on", nil, nil, true, 0,
|
||||
"notify contributing to route: its port 9000 on workstation is none of the ports it listens on"},
|
||||
{"a declaration with no ports leaves it as written", nil, nil, false, 9000, ""},
|
||||
} {
|
||||
with := handingTo("store:5000")
|
||||
with.Ports, with.Given, with.Unassigned, with.Planned = p.ports, p.given, p.unassigned, p.planned
|
||||
with.Ports, with.Given, with.Planned = p.ports, p.given, p.planned
|
||||
c, err := r.Compose(with)
|
||||
if p.refused != "" {
|
||||
if err == nil || !strings.Contains(err.Error(), p.refused) {
|
||||
|
||||
@@ -245,13 +245,6 @@ func (c *composer) portsFor(node Node, plan catalogue.Resolution, settings catal
|
||||
where = at
|
||||
} else {
|
||||
*foreseen = append(*foreseen, fmt.Sprintf("%s:%d", m.Module, l.Port))
|
||||
if r.Unassigned == nil {
|
||||
r.Unassigned = map[string]map[int]bool{}
|
||||
}
|
||||
if r.Unassigned[m.Module] == nil {
|
||||
r.Unassigned[m.Module] = map[int]bool{}
|
||||
}
|
||||
r.Unassigned[m.Module][l.Port] = true
|
||||
}
|
||||
}
|
||||
if ports[m.Module] == nil {
|
||||
|
||||
@@ -52,12 +52,12 @@ func TestAnAllocatedPortIsComposedAndAnUnallocatedOneIsNamedForeseenNotInvented(
|
||||
if p := got.Rendering.Ports["web"][8080]; p != 8080 {
|
||||
t.Errorf("a port nobody allocated is composed as %d, not as the manifest's own", p)
|
||||
}
|
||||
if len(got.ForeseenPorts) != 1 || got.ForeseenPorts[0] != "web:8080" || !got.Rendering.Unassigned["web"][8080] {
|
||||
t.Errorf("foreseen ports are %v (unassigned %v)", got.ForeseenPorts, got.Rendering.Unassigned)
|
||||
if len(got.ForeseenPorts) != 1 || got.ForeseenPorts[0] != "web:8080" {
|
||||
t.Errorf("foreseen ports are %v", got.ForeseenPorts)
|
||||
}
|
||||
nodeOf(t, &in, "laptop").Ports = map[string]map[int]int{"web": {8080: 20123}}
|
||||
got = placed(t, in, "laptop")
|
||||
if p := got.Rendering.Ports["web"][8080]; p != 20123 || len(got.ForeseenPorts) != 0 || got.Rendering.Unassigned != nil {
|
||||
if p := got.Rendering.Ports["web"][8080]; p != 20123 || len(got.ForeseenPorts) != 0 {
|
||||
t.Errorf("the allocated port is composed as %d (foreseen %v)", p, got.ForeseenPorts)
|
||||
}
|
||||
// A port the module does not publish is not the mesh's to move, so it is never foreseen.
|
||||
@@ -70,7 +70,7 @@ func TestAnAllocatedPortIsComposedAndAnUnallocatedOneIsNamedForeseenNotInvented(
|
||||
t.Errorf("an unpublished port: %v foreseen %v", got.Rendering.Ports, got.ForeseenPorts)
|
||||
}
|
||||
unchanged(t, mk, func(in Input) { placed(t, in, "laptop") })
|
||||
// Only a composition for plans refuses a contribution whose port none assigned (issue 774): a declaration still composes.
|
||||
// Only a composition for plans refuses a contribution whose port the module does not listen on (issue 774).
|
||||
for _, mode := range []Mode{Reading, Foreseeing, Planning} {
|
||||
if got := rendered(t, mk(), "laptop", mode).Rendering; got.Planned != (mode == Planning) {
|
||||
t.Errorf("mode %d composes with Planned %v", mode, got.Planned)
|
||||
|
||||
Reference in New Issue
Block a user