A taken container keeps a found network, a left-out module is kept, and genesis raises the forge as its module declares (hq ADR 0163)
A container may name networks it also joins once created, for the per-machine setting that keeps a found network while a neighbour still resolves it there: joined after the run, part of the spec, refused when it cannot be joined. A declaration may say which modules the mesh left out because a stored setting cannot compose with its definition. Absence used to read as removal; a left-out module's records are kept and said, and its holds are not released. Genesis raises the bootstrap forge under the gitea module's container name, with its image digest and its data directory mounted at /data, so the module holds it by the found rule instead of raising a second forge beside it (issue 090). The network is the one difference left for a take to say. Before this the forge had no volume: its repositories were the container's, lost with it.
This commit is contained in:
@@ -940,6 +940,13 @@ type Container struct {
|
||||
// its siblings can name before any of them can resolve anything.
|
||||
Dns []string `json:"dns,omitempty"`
|
||||
|
||||
// Networks are networks this container also joins once created, by name — a found network a
|
||||
// per-machine setting keeps for a taken container (novox/hq ADR 0163, rule 4), so a
|
||||
// neighbour that resolves it there keeps resolving it until the neighbour is taken too.
|
||||
// Joined after creation, because a runtime starts a container on one network; part of the
|
||||
// container's spec, so a network kept or let go recreates it.
|
||||
Networks []string `json:"networks,omitempty"`
|
||||
|
||||
// IP is this container's address on its network, passed to the runtime unchanged.
|
||||
//
|
||||
// Only meaningful on a user-defined network, and refused by the runtime elsewhere. Exists for
|
||||
@@ -1032,6 +1039,16 @@ func (c *Container) validate(where string, _ bool) []string {
|
||||
"static address anywhere but a user-defined one")
|
||||
}
|
||||
}
|
||||
for _, n := range c.Networks {
|
||||
problems = append(problems, (&Network{Name: n}).validate(where+": networks", false)...)
|
||||
if n == c.Network {
|
||||
problems = append(problems, where+": networks names "+n+", which is already the container's network")
|
||||
}
|
||||
}
|
||||
if len(c.Networks) > 0 && (c.RunOnce || c.Schedule != "") {
|
||||
problems = append(problems, where+": networks is for a container that keeps running; a step "+
|
||||
"runs and exits, and joins nothing afterwards")
|
||||
}
|
||||
return append(problems, checkImage(where, c.Image)...)
|
||||
}
|
||||
|
||||
@@ -1150,6 +1167,28 @@ type Declaration struct {
|
||||
// backlog longer than the batch, or a slow broker, applied a declaration the mesh had already
|
||||
// superseded.
|
||||
Sequence int64
|
||||
|
||||
// LeftOut names the modules of this machine's set the mesh left out of this declaration,
|
||||
// because a setting stored for one cannot compose with its definition (novox/hq ADR 0163,
|
||||
// rule 6). A machine is told everything or nothing about what it IS told; this is what it is
|
||||
// not told, said. The host keeps what it holds for a left-out module and touches none of
|
||||
// what it wrote for it — its resources are absent from the declaration, and absence would
|
||||
// otherwise read as removal.
|
||||
LeftOut []string
|
||||
}
|
||||
|
||||
// LeftOutModuleOf says which left-out module a recorded resource belongs to, if any: its id is the
|
||||
// module's name, a dot, and the module's own id for it. A module's name may contain a dot, so the
|
||||
// longest left-out name that prefixes the id wins; a false match keeps a thing an apply would
|
||||
// otherwise remove, which is the conservative mistake.
|
||||
func (d *Declaration) LeftOutModuleOf(id string) (string, bool) {
|
||||
best := ""
|
||||
for _, m := range d.LeftOut {
|
||||
if strings.HasPrefix(id, m+".") && len(m) > len(best) {
|
||||
best = m
|
||||
}
|
||||
}
|
||||
return best, best != ""
|
||||
}
|
||||
|
||||
// Adoption is a node's mode, as the controller records it: the node is adopted, and these are
|
||||
@@ -1290,6 +1329,8 @@ type envelope struct {
|
||||
// Sequence is optional on the wire, so a controller that does not send one is still
|
||||
// understood: absent reads as zero, which is "no ordering claimed" rather than "first".
|
||||
Sequence int64 `json:"sequence,omitempty"`
|
||||
// LeftOut is optional on the wire too, and absent when nothing was left out (ADR 0163).
|
||||
LeftOut []string `json:"left_out,omitempty"`
|
||||
}
|
||||
|
||||
func parse(raw []byte, allowActions bool) (*Declaration, error) {
|
||||
@@ -1306,8 +1347,20 @@ func parse(raw []byte, allowActions bool) (*Declaration, error) {
|
||||
env.Version, Version)}}
|
||||
}
|
||||
|
||||
d := &Declaration{Version: env.Version, For: env.For, Adoption: env.Adoption, Sequence: env.Sequence}
|
||||
d := &Declaration{Version: env.Version, For: env.For, Adoption: env.Adoption, Sequence: env.Sequence,
|
||||
LeftOut: env.LeftOut}
|
||||
var problems []string
|
||||
if len(env.LeftOut) > 0 && allowActions {
|
||||
// The bundle is carried with the binary and leaves nothing out: which module a setting
|
||||
// stopped composing for is the mesh's record (ADR 0163).
|
||||
problems = append(problems, "a carried bundle says modules were left out, and only the "+
|
||||
"mesh can say that")
|
||||
}
|
||||
for _, m := range env.LeftOut {
|
||||
if strings.TrimSpace(m) == "" {
|
||||
problems = append(problems, "left_out names a module with no name")
|
||||
}
|
||||
}
|
||||
|
||||
if len(env.Resources) == 0 && !env.OwnsNothing {
|
||||
problems = append(problems, "no resources. An empty declaration is a mistake, not a "+
|
||||
|
||||
Reference in New Issue
Block a user