Revert "Merge pull request 'Revert L3: its node-engine removed every held module on novox, the bus server among them (issue 774)' (#174) from revert/774-l3 into main"
This reverts commit1ec73915b8, reversing changes made to0a4c35f731.
This commit is contained in:
+44
-12
@@ -5,12 +5,14 @@ import (
|
||||
"crypto/ed25519"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/compose/frombus"
|
||||
@@ -343,13 +345,14 @@ func resourcesOf(cs []delivery.Composed) []declaration.Resource {
|
||||
// controller's key the node was enrolled with (novox/hq ADR 0539 §3, §11); a node adopted later has it at its adoption.
|
||||
const operatorKeysFile = "operator-keys"
|
||||
|
||||
// trustedKeys are the keys a composition may be signed by: the controller's, which the node was enrolled with, and the
|
||||
// operator's, read from operatorKeysFile each time it is asked, so a key that arrives while the agent runs is trusted at
|
||||
// the next composition. A file that cannot be read trusts the controller's alone, and says so.
|
||||
func trustedKeys(opts options, controller ed25519.PublicKey) func() []ed25519.PublicKey {
|
||||
// trustedKeys are the keys a composition may be signed by: the controller's, which the node was enrolled with, while the
|
||||
// controller holds its lease (ADR 0550 §2: trusted no more once it is handed away), and the operator's, read from
|
||||
// operatorKeysFile each time it is asked, so a key that arrives while the agent runs is trusted at the next composition.
|
||||
// A file that cannot be read trusts the controller's alone, and says so.
|
||||
func trustedKeys(opts options, controllerNow func() ed25519.PublicKey) func() []ed25519.PublicKey {
|
||||
return func() []ed25519.PublicKey {
|
||||
keys := []ed25519.PublicKey{}
|
||||
if len(controller) == ed25519.PublicKeySize {
|
||||
if controller := controllerNow(); len(controller) == ed25519.PublicKeySize {
|
||||
keys = append(keys, controller)
|
||||
}
|
||||
raw, err := os.ReadFile(filepath.Join(filepath.Dir(opts.state), operatorKeysFile))
|
||||
@@ -373,13 +376,16 @@ func trustedKeys(opts options, controller ed25519.PublicKey) func() []ed25519.Pu
|
||||
}
|
||||
|
||||
// keptOnce reads the kept declaration once and splits it by module: its resources (the node's own are those that say
|
||||
// none, ADR 0539 §9) and its filled paths.
|
||||
// none, ADR 0539 §9) and its filled paths. Once the read is retired (keptRetired) nothing is read.
|
||||
func keptOnce(opts options, signer ed25519.PublicKey) func() (map[string][]json.RawMessage, map[string][]string) {
|
||||
var once sync.Once
|
||||
var by map[string][]json.RawMessage
|
||||
var filled map[string][]string
|
||||
return func() (map[string][]json.RawMessage, map[string][]string) {
|
||||
once.Do(func() {
|
||||
if keptRetired.Load() {
|
||||
return
|
||||
}
|
||||
raw, err := store.LoadDeclared(store.DeclaredPath(opts.state), signer)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -429,7 +435,7 @@ func splitKept(raw []byte) (map[string][]json.RawMessage, map[string][]string) {
|
||||
// nodeAgent runs the node agent under the session's links for as long as ctx lasts: it waits for a link, follows the
|
||||
// node's wants and compositions on it, and begins again with the next link. A watch it cannot make (a bucket this node's
|
||||
// account may not read) is said, and tried again with a growing wait, as the link is.
|
||||
func nodeAgent(ctx context.Context, opts options, signer ed25519.PublicKey, session *link.Session, sched *apply.Scheduler,
|
||||
func nodeAgent(ctx context.Context, opts options, signer ed25519.PublicKey, trust *meshTrust, session *link.Session, sched *apply.Scheduler,
|
||||
say link.Announce, afterApply func(), current *agentNow, sayFacts func(ctx context.Context, ag *agent.Agent)) {
|
||||
wait := 2 * time.Second
|
||||
for ctx.Err() == nil {
|
||||
@@ -446,6 +452,11 @@ func nodeAgent(ctx context.Context, opts options, signer ed25519.PublicKey, sess
|
||||
return
|
||||
}
|
||||
var ag *agent.Agent
|
||||
// The kept release-5 declaration is no longer read once every module the seat's placement puts here has a have of its
|
||||
// own (ADR 0550 §2: its signature is the controller's, trusted no more after the lease write).
|
||||
if retired, why := placedAllHave(linked, session, node); retired && !keptRetired.Swap(true) {
|
||||
say("the kept declaration is no longer read: " + why)
|
||||
}
|
||||
kept := keptOnce(opts, signer)
|
||||
// The mesh's own certificate the declaration kept from before carries, kept for the record before this machine
|
||||
// composes its own (ADR 0555 §3): without it a module that asks for a certificate would be stood in for.
|
||||
@@ -458,7 +469,7 @@ func nodeAgent(ctx context.Context, opts options, signer ed25519.PublicKey, sess
|
||||
}
|
||||
// The bus's user list, written alone from the newest composition of the bus module (ADR 0547 §8): on every
|
||||
// node, and a node whose compositions carry no list writes nothing.
|
||||
users := userListFollower(opts, session, composedBucket, trustedKeys(opts, signer), say, func() {
|
||||
users := userListFollower(opts, session, composedBucket, trustedKeys(opts, trust.Controller), say, func() {
|
||||
// This engine wrote the list, so the bus reloads its accounts and answers no JetStream request for a few
|
||||
// seconds: what failed in them is tried again once that is over, not at its next wait.
|
||||
time.AfterFunc(reloadSettles, func() {
|
||||
@@ -495,7 +506,7 @@ func nodeAgent(ctx context.Context, opts options, signer ed25519.PublicKey, sess
|
||||
}
|
||||
return out, nil
|
||||
},
|
||||
Trusted: trustedKeys(opts, signer),
|
||||
Trusted: trustedKeys(opts, trust.Controller),
|
||||
Backup: backupNode(session),
|
||||
// What the filling refused before this apply may be named now: the provisioner's client is told to fill
|
||||
// again (ace, 2026-10-25 21:17).
|
||||
@@ -572,11 +583,17 @@ func nodeAgent(ctx context.Context, opts options, signer ed25519.PublicKey, sess
|
||||
now.NotComposedEach(run, why, held) // a module held alone marks that module, never the others (issue 1126)
|
||||
}
|
||||
},
|
||||
// And the vault's authority beside the controller's, and this node's certificate asked of the vault when a
|
||||
// module here asks for one (ADR 0550 §2).
|
||||
vaultAuthority: trust.VaultAuthority,
|
||||
certify: func(ctx context.Context) error {
|
||||
return certifyThisNode(ctx, opts.state, node, trust, session.AskVault, func() { sayFacts(ctx, ag) })
|
||||
},
|
||||
}
|
||||
// And its answer to every placement candidate, placed or not, applying nothing (novox/hq ADR 0559 §4): written into
|
||||
// its own key, `<node>.node`, under candidates.
|
||||
shadowHooks := hooks
|
||||
shadowHooks.refused = nil
|
||||
shadowHooks.refused, shadowHooks.certify = nil, nil
|
||||
shadowEnv := composerEnv(session, node, say, shadowHooks)
|
||||
// And, after each answer, what runs of an own secret the answer says the vault holds another value of, handed to
|
||||
// the vault while the node applies the controller's compositions (issue 1126, cause C4; ownresync).
|
||||
@@ -725,8 +742,19 @@ func busyModules() []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// keptDeclaration is the declaration the node kept before the switch, verified with the mesh's key when it is given.
|
||||
// keptRetired says the kept declaration is read no more: every module the seat's placement puts on this node has a have of
|
||||
// its own (placedAllHave), so what runs is the agent's alone (ADR 0550 §2, design 47's L3 s9).
|
||||
var keptRetired atomic.Bool
|
||||
|
||||
// errKeptRetired is keptDeclaration's answer once the read is retired.
|
||||
var errKeptRetired = errors.New("the kept declaration is read no more: every module placed on this node has a have of its own")
|
||||
|
||||
// keptDeclaration is the declaration the node kept before the switch, verified with the mesh's key when it is given;
|
||||
// once the read is retired, nothing is read.
|
||||
func keptDeclaration(statePath string, signer ed25519.PublicKey) (*declaration.Declaration, error) {
|
||||
if keptRetired.Load() {
|
||||
return nil, errKeptRetired
|
||||
}
|
||||
var raw []byte
|
||||
if len(signer) > 0 {
|
||||
var err error
|
||||
@@ -903,6 +931,9 @@ type composerHooks struct {
|
||||
unseal func(string) ([]byte, error)
|
||||
refused func(why string, held map[string]string)
|
||||
held func(module string) (delivery.Seals, []string, error)
|
||||
// vaultAuthority and certify are selfcompose.Env's VaultAuthority and Certify.
|
||||
vaultAuthority func() string
|
||||
certify func(ctx context.Context) error
|
||||
}
|
||||
|
||||
func selfComposer(ctx context.Context, session *link.Session, node string, say func(string), hooks composerHooks) (*selfcompose.Composer, string) {
|
||||
@@ -966,7 +997,8 @@ func composerEnv(session *link.Session, node string, say func(string), hooks com
|
||||
Hear: session.Hear,
|
||||
// And a moved module's templates archive, in the artifact store, as every archive is fetched (issue 1126).
|
||||
Fetch: apply.Fetch,
|
||||
Running: hooks.running, Unseal: hooks.unseal, Refused: hooks.refused, Held: hooks.held}
|
||||
Running: hooks.running, Unseal: hooks.unseal, Refused: hooks.refused, Held: hooks.held,
|
||||
VaultAuthority: hooks.vaultAuthority, Certify: hooks.certify}
|
||||
}
|
||||
|
||||
// endWhenUnplaced calls stop once this node's placement key is deleted from the seat's placement (after the watch
|
||||
|
||||
Reference in New Issue
Block a user