Unify trunk on main: initialization → main #3
+29
-1
@@ -15,6 +15,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
@@ -733,7 +734,7 @@ func applyAndKeep(ctx context.Context, opts options, raw []byte, signed *store.D
|
|||||||
saveErr.Error()}
|
saveErr.Error()}
|
||||||
}
|
}
|
||||||
|
|
||||||
report := link.Report{}
|
report := link.Report{Carried: carriedPorts(updated)}
|
||||||
for _, change := range outcome.Outcomes {
|
for _, change := range outcome.Outcomes {
|
||||||
report.Applied = append(report.Applied, change.ID)
|
report.Applied = append(report.Applied, change.ID)
|
||||||
}
|
}
|
||||||
@@ -798,3 +799,30 @@ func sealOpener(statePath string) apply.Unseal {
|
|||||||
return key.Unseal(sealed)
|
return key.Unseal(sealed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// carriedPorts is every machine port held by what this host raised from its own bundle.
|
||||||
|
//
|
||||||
|
// **What the mesh must assign around** (novox/hq ADR 0038). The substrate is not a module: a node
|
||||||
|
// raises it before any mesh exists, so the control plane has never heard of the store or the
|
||||||
|
// broker. Told this, it can put a module somewhere else; not told, it hands out a port one of them
|
||||||
|
// holds and finds out from a container runtime.
|
||||||
|
//
|
||||||
|
// Only what was carried. What the mesh itself put here it already knows about, and reporting it
|
||||||
|
// back would make the machine an authority on the mesh's own bookkeeping.
|
||||||
|
func carriedPorts(state store.State) []int {
|
||||||
|
seen := map[int]bool{}
|
||||||
|
var out []int
|
||||||
|
for _, applied := range state.Resources {
|
||||||
|
if applied.Origin == store.OriginDeclared {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, port := range applied.Holds {
|
||||||
|
if !seen[port] {
|
||||||
|
seen[port] = true
|
||||||
|
out = append(out, port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Ints(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ func Apply(
|
|||||||
ID: resource.Identity(), Type: string(resource.Kind()),
|
ID: resource.Identity(), Type: string(resource.Kind()),
|
||||||
Target: outcome.Target, AppliedAt: time.Now().UTC(),
|
Target: outcome.Target, AppliedAt: time.Now().UTC(),
|
||||||
Wrote: outcome.wrote,
|
Wrote: outcome.wrote,
|
||||||
|
Holds: holds(resource),
|
||||||
})
|
})
|
||||||
report.Outcomes = append(report.Outcomes, outcome)
|
report.Outcomes = append(report.Outcomes, outcome)
|
||||||
if outcome.Action != "unchanged" {
|
if outcome.Action != "unchanged" {
|
||||||
@@ -1063,3 +1064,31 @@ func digestOf(content string) string {
|
|||||||
sum := sha256.Sum256([]byte(content))
|
sum := sha256.Sum256([]byte(content))
|
||||||
return hex.EncodeToString(sum[:])
|
return hex.EncodeToString(sum[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// holds is the machine's own ports a resource occupies.
|
||||||
|
//
|
||||||
|
// **What the declaration binds, not what is open.** A machine's open ports are a moving target —
|
||||||
|
// something a person started, a connection the kernel handed out — and assigning around them would
|
||||||
|
// mean a port that was free when it was asked for and taken when it was used. What a resource
|
||||||
|
// declares is stable, and it is the half the mesh can be responsible for.
|
||||||
|
func holds(resource declaration.Resource) []int {
|
||||||
|
container, ok := resource.(*declaration.Container)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var out []int
|
||||||
|
for _, mapping := range container.Ports {
|
||||||
|
// "8080:80", or "127.0.0.1:8080:80" when an address was named. The machine's port is the
|
||||||
|
// one before the last colon; the last is inside the container and is not the machine's.
|
||||||
|
parts := strings.Split(mapping, ":")
|
||||||
|
if len(parts) < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
port, err := strconv.Atoi(strings.TrimSpace(parts[len(parts)-2]))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out = append(out, port)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|||||||
@@ -56,4 +56,15 @@ type Report struct {
|
|||||||
|
|
||||||
// Refused is set when the declaration was rejected whole rather than applied in part.
|
// Refused is set when the declaration was rejected whole rather than applied in part.
|
||||||
Refused string `json:"refused,omitempty"`
|
Refused string `json:"refused,omitempty"`
|
||||||
|
|
||||||
|
// Carried are the machine's ports held by what this host raised from its own bundle.
|
||||||
|
//
|
||||||
|
// **So the mesh can assign around what it did not put here** (novox/hq ADR 0038). A node
|
||||||
|
// raises its substrate before any mesh exists, so the control plane has never heard of the
|
||||||
|
// store or the broker — and would hand a module a port one of them holds, discovering it only
|
||||||
|
// when a container runtime refused to start.
|
||||||
|
//
|
||||||
|
// A node *states* and the mesh writes, which is the whole shape of this message: this is the
|
||||||
|
// machine saying what is true of it, not asking for anything.
|
||||||
|
Carried []int `json:"carried,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,18 @@ type Applied struct {
|
|||||||
// Empty means carried, for state written before this field existed: everything a host had
|
// Empty means carried, for state written before this field existed: everything a host had
|
||||||
// applied at that point came from its bundle.
|
// applied at that point came from its bundle.
|
||||||
Origin string `json:"origin,omitempty"`
|
Origin string `json:"origin,omitempty"`
|
||||||
|
|
||||||
|
// Holds are the machine's own ports this resource occupies.
|
||||||
|
//
|
||||||
|
// **So the mesh can assign around what it did not put here** (novox/hq ADR 0038). A node
|
||||||
|
// raises its substrate from the bundle before any mesh exists, so the control plane has never
|
||||||
|
// heard of the store, the broker or the control plane's own container — and a module assigned
|
||||||
|
// afterwards would be given a port one of them already holds, and would be told so by a
|
||||||
|
// container runtime rather than by anything that could have prevented it.
|
||||||
|
//
|
||||||
|
// Recorded per resource rather than counted per machine, because what a machine happens to
|
||||||
|
// have open right now is a moving target, and what its declaration binds is not.
|
||||||
|
Holds []int `json:"holds,omitempty"`
|
||||||
// Target is what was changed — a path, a unit — so removal knows what to undo without
|
// Target is what was changed — a path, a unit — so removal knows what to undo without
|
||||||
// re-reading a declaration that may no longer exist.
|
// re-reading a declaration that may no longer exist.
|
||||||
Target string `json:"target"`
|
Target string `json:"target"`
|
||||||
|
|||||||
Reference in New Issue
Block a user