Take a module, converge a node after a preview, and return it to adopted, from the command line and the API (hq ADR 0100)

This commit is contained in:
2026-09-22 17:27:35 +02:00
parent 28894fa5bd
commit 1ea84f8b8f
6 changed files with 683 additions and 39 deletions
+34 -22
View File
@@ -318,10 +318,30 @@ const (
func declarationWith(ctx context.Context, open *stores, node string,
plan catalogue.Resolution, settings catalogue.SettingsBy,
gens map[string]catalogue.Generator, choosing Choosing) (sendable, error) {
with, record, err := renderingFor(ctx, open, node, plan, settings, gens, choosing)
if err != nil {
return sendable{}, err
}
composed, err := plan.Compose(with)
if err != nil {
return sendable{}, err
}
// And what was taken on it, said in every declaration it is sent from this one place.
adoption, err := adoptionOf(ctx, open.inventory, record, plan, composed)
if err != nil {
return sendable{}, err
}
return sendable{Resources: composed.Resources, Adoption: adoption}, nil
}
// renderingFor is everything a node's declaration is composed with, and the node's record.
func renderingFor(ctx context.Context, open *stores, node string,
plan catalogue.Resolution, settings catalogue.SettingsBy,
gens map[string]catalogue.Generator, choosing Choosing) (catalogue.Rendering, inventory.Node, error) {
inv := open.inventory
grants, err := grantsFor(ctx, open, node)
if err != nil {
return sendable{}, err
return catalogue.Rendering{}, inventory.Node{}, err
}
// Where this machine puts what each module needs reachable (novox/hq ADR 0038).
//
@@ -334,7 +354,7 @@ func declarationWith(ctx context.Context, open *stores, node string,
if choosing == Reading {
held, err := inv.PortsFor(ctx, node)
if err != nil {
return sendable{}, err
return catalogue.Rendering{}, inventory.Node{}, err
}
for _, a := range held {
if already[a.Module] == nil {
@@ -358,7 +378,7 @@ func declarationWith(ctx context.Context, open *stores, node string,
case mayAssign && choosing == Allocating:
at, err := inv.PortFor(ctx, node, m.Module, l.Port, l.Fixed)
if err != nil {
return sendable{}, fmt.Errorf(
return catalogue.Rendering{}, inventory.Node{}, fmt.Errorf(
"%s needs %d reachable on %s and it could not be assigned: %w",
m.Module, l.Port, node, err)
}
@@ -399,7 +419,7 @@ func declarationWith(ctx context.Context, open *stores, node string,
}
}
if err != nil {
return sendable{}, err
return catalogue.Rendering{}, inventory.Node{}, err
}
if needed[m.Module] == nil {
needed[m.Module] = map[string]string{}
@@ -417,7 +437,7 @@ func declarationWith(ctx context.Context, open *stores, node string,
}
issued, meshCA, err := certificateFor(ctx, open, node)
if err != nil {
return sendable{}, err
return catalogue.Rendering{}, inventory.Node{}, err
}
certificate, authority = issued, meshCA
break
@@ -430,11 +450,11 @@ func declarationWith(ctx context.Context, open *stores, node string,
// One reading of the catalogue for the three questions below that resolve the whole mesh.
shelf, err := inv.Catalogue(ctx)
if err != nil {
return sendable{}, err
return catalogue.Rendering{}, inventory.Node{}, err
}
private, err := onThePrivateNetwork(ctx, inv, shelf)
if err != nil {
return sendable{}, err
return catalogue.Rendering{}, inventory.Node{}, err
}
// And every machine's name, so a container can reach one. The same set that writes the
@@ -442,7 +462,7 @@ func declarationWith(ctx context.Context, open *stores, node string,
// about where another machine is.
names, err := namesInTheMesh(ctx, inv, shelf)
if err != nil {
return sendable{}, err
return catalogue.Rendering{}, inventory.Node{}, err
}
// And every routed name → the node that serves it (novox/hq ADR 0066). Alongside the
@@ -451,7 +471,7 @@ func declarationWith(ctx context.Context, open *stores, node string,
// to serve and knows nothing about what they mean.
routes, err := routeNamesInTheMesh(ctx, open)
if err != nil {
return sendable{}, err
return catalogue.Rendering{}, inventory.Node{}, err
}
for name, at := range routes {
names[name] = at
@@ -480,7 +500,7 @@ func declarationWith(ctx context.Context, open *stores, node string,
continue
}
if kept, err = inv.OperatorExport(ctx); err != nil {
return sendable{}, err
return catalogue.Rendering{}, inventory.Node{}, err
}
break
}
@@ -489,21 +509,13 @@ func declarationWith(ctx context.Context, open *stores, node string,
// the declaration carries openings and the mesh's guard in place of a filter.
record, err := inv.NodeByName(ctx, node)
if err != nil {
return sendable{}, err
return catalogue.Rendering{}, inventory.Node{}, err
}
composed, err := plan.Compose(catalogue.Rendering{
return catalogue.Rendering{
Settings: settings, Generators: gens, Grants: grants, Needed: needed, Ports: ports,
Certificate: certificate, Authority: authority, Mesh: private, Names: names,
Suffix: overlay.Suffix(), Foundation: foundation, Kept: kept, Adopted: record.Adopted})
if err != nil {
return sendable{}, err
}
// And what was taken on it, said in every declaration it is sent from this one place.
adoption, err := adoptionOf(ctx, inv, record, plan, composed)
if err != nil {
return sendable{}, err
}
return sendable{Resources: composed.Resources, Adoption: adoption}, nil
Suffix: overlay.Suffix(), Foundation: foundation, Kept: kept, Adopted: record.Adopted,
}, record, nil
}
// routeNamesInTheMesh is every routed name and the address of the node that serves it (novox/hq