The mesh may only move a port it actually publishes
The lab caught this: a module declaring a port and running no container had its rule set opened on 20000 while its service sat on 9101. The firewall reported success and blocked the thing it was told to admit, which is the precise failure the filtering comment warns about, arrived at from the other side. Assignment was applied to every declared port. But a container's mapping is the thing that translates, and where there is none the software binds what it binds — the mesh choosing a number does not move the service, it only makes the mesh wrong about where it is. The declaration side already knew this: publishedOn rewrites container ports and nothing else. Filtering did not, so the two disagreed about the same fact. MachineSide is now the one derivation both follow. It also fixes a second case nobody had hit yet: a mapping the manifest wrote itself, like the mail system's 7080:80. That is passed through untouched when composing, so assigning it a machine port would have opened a rule on a port the container does not publish. Either side of such a mapping now names it, and the host side is the answer — a module may read `listens` as what its software binds or as what the machine exposes, and both readings want the same number. Recorded either way, assigned or not: the map means where this module's port is on this machine, and every reader needs that answer regardless of who chose it. Tests bite — making it always assignable reproduces the lab failure.
This commit is contained in:
@@ -266,16 +266,26 @@ func declarationWith(ctx context.Context, open *stores, node string,
|
||||
ports := map[string]map[int]int{}
|
||||
for _, m := range plan.Modules {
|
||||
for _, l := range m.Listens {
|
||||
at, err := inv.PortFor(ctx, node, m.Module, l.Port, l.Fixed)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"%s needs %d reachable on %s and it could not be assigned: %w",
|
||||
m.Module, l.Port, node, err)
|
||||
// **Only a port the module actually publishes is the mesh's to move.** A container's
|
||||
// mapping is the thing that translates; without one the software binds what it binds,
|
||||
// and an assignment would not move the service — it would open the wrong number in the
|
||||
// rule set and leave the real one shut. Recorded either way, because this map means
|
||||
// *where this module's port is on this machine* and every reader of it needs that
|
||||
// answer whether or not the mesh was the one who chose it.
|
||||
where, mayAssign := m.MachineSide(l.Port)
|
||||
if mayAssign {
|
||||
at, err := inv.PortFor(ctx, node, m.Module, l.Port, l.Fixed)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"%s needs %d reachable on %s and it could not be assigned: %w",
|
||||
m.Module, l.Port, node, err)
|
||||
}
|
||||
where = at.Machine
|
||||
}
|
||||
if ports[m.Module] == nil {
|
||||
ports[m.Module] = map[int]int{}
|
||||
}
|
||||
ports[m.Module][l.Port] = at.Machine
|
||||
ports[m.Module][l.Port] = where
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user