The switch to release 6 is today's controller's last plan, and the bus runs the user list it composes until the new controller writes one: so the new controller's writes of each node's compositions and their digests, each new node-engine's reads of its own compositions and wants and its backup holder's verbs and word, and the assigner's read of the digests must be granted by this controller already (ADR 0539 clauses 2, 6, 9 and 16; the review's A1).
97 lines
4.3 KiB
Go
97 lines
4.3 KiB
Go
package broker
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
"github.com/nats-io/nats.go/jetstream"
|
|
)
|
|
|
|
// Release 6's grants, carried ahead of it (novox/hq ADR 0539 clauses 2, 6, 9 and 16; issue 1945, the review's A1). The
|
|
// switch to release 6 is the last delivery plan of today's controller, and the bus's user list after it is the one
|
|
// today's controller composes: so the subjects the new controller, every new node-engine and the assigner use after the
|
|
// switch are granted by this controller already, before the group merges. Unused until then: nothing writes or reads
|
|
// these buckets before release 6.
|
|
//
|
|
// Names as mesh-sdk's release 6 gives them (delivery.ComposedBucketFor, ControllerComposedBucket); written out here
|
|
// because this controller's mesh-sdk predates them, and held equal by release 6's own tests.
|
|
|
|
// ComposedBucketPrefix starts a node's bucket of compositions, `composed-<node>`.
|
|
const ComposedBucketPrefix = "composed-"
|
|
|
|
// ControllerComposed is the local name of the compositions' digests, `mesh-controller_composed`, which the assigner reads.
|
|
const ControllerComposed = "composed"
|
|
|
|
// ControllerComposedBucket is the bucket of the compositions' digests.
|
|
var ControllerComposedBucket = BucketName(ControllerSeat, ControllerComposed)
|
|
|
|
// composedBucketOf is a node's bucket of compositions; a node name a subject would widen is refused.
|
|
func composedBucketOf(node string) (string, error) {
|
|
if !safeSubject.MatchString(node) {
|
|
return "", fmt.Errorf("%q cannot be part of a subject: a permission is a subject pattern, and this would widen it", node)
|
|
}
|
|
return ComposedBucketPrefix + node, nil
|
|
}
|
|
|
|
// ComposedWrites is what the controller publishes to write a node's compositions: the bucket's own subjects.
|
|
func ComposedWrites(node string) (string, error) {
|
|
bucket, err := composedBucketOf(node)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return "$KV." + bucket + ".>", nil
|
|
}
|
|
|
|
// ComposedReads is what a node's node-engine publishes to follow its wants and compositions: every key of its own
|
|
// composition bucket, and its own wants (`want.<node>.<module>`, `want.<node>.node`) in the assigner's bucket; nothing
|
|
// of another node's, nor the digests.
|
|
func ComposedReads(node string) ([]string, error) {
|
|
bucket, err := composedBucketOf(node)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return append(readGrants(bucket, ""), readGrants(delivery.AssignerWantsBucket, "want."+node+".>")...), nil
|
|
}
|
|
|
|
// VerbsTheNodeAgentAsks are the seat verbs a node's node-engine calls of its own machine while it applies a want: its
|
|
// backup holder backs a data module up before it moves, and says when it was (ADR 0539 clause 16).
|
|
var VerbsTheNodeAgentAsks = []SeatVerb{{Seat: "node-backup", Verb: "now"}, {Seat: "node-backup", Verb: "backed-up"}}
|
|
|
|
// NodeAgentAsks are the subjects of VerbsTheNodeAgentAsks for one node: `mesh.seat.<seat>.tool.<verb>.<node>`.
|
|
func NodeAgentAsks(node string) ([]string, error) {
|
|
if !safeSubject.MatchString(node) {
|
|
return nil, fmt.Errorf("%q cannot be part of a subject: a permission is a subject pattern, and this would widen it", node)
|
|
}
|
|
var out []string
|
|
for _, v := range VerbsTheNodeAgentAsks {
|
|
out = append(out, "mesh.seat."+v.Seat+".tool."+v.Verb+"."+node)
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// NodeAgentHears are the events a node's node-engine subscribes while it applies a want: the backup holder's word that a
|
|
// backup is taken, from whichever module holds node-backup on its machine.
|
|
var NodeAgentHears = []string{"mesh.mod.*.event.backed-up"}
|
|
|
|
// ComposedDigestsConfig is the bucket of the compositions' digests as the controller asserts it: five revisions a key.
|
|
func ComposedDigestsConfig() jetstream.KeyValueConfig {
|
|
return jetstream.KeyValueConfig{
|
|
Bucket: ControllerComposedBucket,
|
|
Description: "each composition's digest and the judgement of its move from what the node runs (novox/hq ADR 0539 " +
|
|
"clauses 2 and 14): written by the controller alone, read by the assigner; empty until release 6",
|
|
History: 5,
|
|
MaxValueSize: 4 << 10,
|
|
MaxBytes: 64 << 20,
|
|
Storage: jetstream.FileStorage,
|
|
}
|
|
}
|
|
|
|
// EnsureComposedDigests asserts the bucket of the compositions' digests.
|
|
func EnsureComposedDigests(ctx context.Context, js jetstream.JetStream) error {
|
|
if _, err := js.CreateOrUpdateKeyValue(ctx, ComposedDigestsConfig()); err != nil {
|
|
return fmt.Errorf("asserting bucket %s: %w", ControllerComposedBucket, err)
|
|
}
|
|
return nil
|
|
}
|