Files
mesh-controller/cmd/mesh-controller/own_grants.go
T
jschoubben c40e15268e Compose where a declaration was sent: secrets, credentials, acceptances, the hub's peers, adoption, assignments and the bus's user list (issue 1945, B2, B6)
Each act that changed what a node runs now writes that node's compositions, and its wants follow by the assigner's
rules; a bus upgrade composes the bus's machines and answers the want the operator writes, since the assigner never
moves the bus (ADR 0539 clauses 5, 7 and 15). A node-engine may ask its own backup holder before a data module moves.
2026-10-24 16:59:06 +02:00

72 lines
3.7 KiB
Go

package main
import (
"context"
"fmt"
)
// A new controller's own grants reach the bus before it writes (novox/hq issue 1800).
//
// A controller's grants are composed by the controller binary itself (broker.PermissionsFor), so the controller that
// walks a delivery cannot put its successor's grants in the bus's user list: the list that carries them was sent only
// once the new controller passed its gate on its first machine (carryUserList). Until then the new controller wrote
// buckets its account was not granted, and the bus refused them: plans-building on 2026-10-21, declared-packages on
// 2026-10-22, and R4e's states-announced would be the third.
//
// So a controller that starts, holding the lease and before it starts anything that writes its buckets, sends the
// machine holding the bus its user list when the list it composes is not the one that machine was last sent: the grants
// step's send (release.go grantsStep), every build there kept at the one it runs, refused unsent when the declaration
// would change more than the user list (errNotGrantsOnly). No build of a running plan reaches that machine before the
// plan's own tier sends it (ADR 0503 §8). A send that cannot be made is said once, and the controller serves on.
//
// It does not ask heldMachines, as carryUserList does: every reason that gives is a build that would move with the
// list (a policy, a plan not yet sent there, no gate passed), and here none can. The running plan that brought this
// controller holds the bus's machine until its tier sends it; asking would leave the list behind exactly when 1800
// meets it. The refusal unsent (errNotGrantsOnly) is the guard instead.
// ownGrantsCarrier is what the start's send reads and does: whether the bus's list is behind and on which machine, and
// the grants-only send to it. Variables so a test needs no store and no bus.
type ownGrantsCarrier struct {
behind func(ctx context.Context) (holder string, behind bool, err error)
send func(ctx context.Context, holder string) error
}
// carry sends the machine holding the bus the controller's own user list when it is behind, and says what it did.
func (c ownGrantsCarrier) carry(ctx context.Context) string {
holder, behind, err := c.behind(ctx)
switch {
case err != nil:
return fmt.Sprintf("whether the bus's user list carries this controller's grants cannot be read, so it is not sent "+
"at start; a bucket it newly writes may be refused until the gate carries it: %v", err)
case holder == "" || !behind:
return ""
}
if err := c.send(ctx, holder); err != nil {
return fmt.Sprintf("this controller's grants could not be sent to %s, which holds the bus, at its start; a bucket "+
"it newly writes may be refused until the gate carries them: %v", holder, err)
}
return fmt.Sprintf("sent %s, which holds the bus, this controller's user list alone, every build there kept, "+
"before it writes", holder)
}
// startWithOwnGrants carries the controller's own grants to the bus and only then starts what writes (then).
func startWithOwnGrants(ctx context.Context, c ownGrantsCarrier, then func()) {
if said := c.carry(ctx); said != "" {
fmt.Println(said)
}
then()
}
// ownGrantsOf is the carrier of the serving controller: the grants step's reading and its grants-only send.
func ownGrantsOf(open *stores) ownGrantsCarrier {
return ownGrantsCarrier{
behind: func(ctx context.Context) (string, bool, error) { return brokerBehind(ctx, open, nil) },
send: func(ctx context.Context, holder string) error {
// The user list is a file of the bus module's composition (novox/hq ADR 0539 clause 7): composed, and the
// assigner writes the bus node's want for that revision at once.
_, err := composeModules(ctx, open, []string{holder})
return err
},
}
}