Why: the grants part writes grants.<module>.<fp> in shadow beside the controller's; the assigner switches source only when the lease is handed away.
129 lines
5.4 KiB
Go
129 lines
5.4 KiB
Go
package delivery
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
)
|
|
|
|
// The controller's grants (novox/hq ADR 0528 clause 2, ADR 0429 §6 rule 6): when the controller has issued a module's
|
|
// bus credential for a fingerprint, it writes `<module>.<fingerprint hex>` in its bucket grants. The assigner reads
|
|
// it: a node's want moves to a fingerprint only once its grant exists. Only the controller writes the bucket.
|
|
//
|
|
// The names say Controller, since the catalogue's GrantKey (catalogue/streams.go) is a stream's grant pattern, unrelated.
|
|
const (
|
|
// ControllerGrantsBucket is the controller's bucket of issued credentials by fingerprint.
|
|
ControllerGrantsBucket = "mesh-controller_grants"
|
|
// ControllerGrantsHistory is the revisions the bucket keeps per key.
|
|
ControllerGrantsHistory = 5
|
|
)
|
|
|
|
// ControllerGrantKey is the key, in ControllerGrantsBucket, of a module's credential issued for a fingerprint:
|
|
// `<module>.<hex>`, the hex being the fingerprint's key part (FingerprintKeyPart).
|
|
func ControllerGrantKey(module, fingerprint string) (string, error) {
|
|
return BuilderBuildKey(module, fingerprint)
|
|
}
|
|
|
|
// ParseControllerGrantKey is the inverse of ControllerGrantKey; it refuses a want or held key, naming it.
|
|
func ParseControllerGrantKey(key string) (module, fingerprint string, err error) {
|
|
if module, fingerprint, err = ParseBuilderBuildKey(key); err != nil {
|
|
return "", "", fmt.Errorf("delivery: %q is not a grant key, <module>.<fingerprint hex>: %w", key, err)
|
|
}
|
|
return module, fingerprint, nil
|
|
}
|
|
|
|
// ControllerGrant is the value of a grant key: the bus accounts (their public keys) the module's processes were issued
|
|
// for that fingerprint, none for a module whose grants the tool runner's account carries, so a reissue for another
|
|
// account is a new revision. The entry's own time says when it was issued.
|
|
type ControllerGrant struct {
|
|
V int `json:"v"`
|
|
Accounts []string `json:"accounts,omitempty"`
|
|
}
|
|
|
|
func (g ControllerGrant) check() error {
|
|
for _, a := range g.Accounts {
|
|
if strings.TrimSpace(a) == "" || strings.ContainsAny(a, " \t\n") {
|
|
return fmt.Errorf("delivery: a grant names an empty or spaced account %q", a)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// EncodeControllerGrant is g as JSON at Version; it refuses an empty or spaced account.
|
|
func EncodeControllerGrant(g ControllerGrant) ([]byte, error) {
|
|
if err := g.check(); err != nil {
|
|
return nil, err
|
|
}
|
|
g.V = Version
|
|
return json.Marshal(g)
|
|
}
|
|
|
|
// DecodeControllerGrant reads a grant; it refuses an unknown version (ErrUnknownVersion) and an empty or spaced account.
|
|
func DecodeControllerGrant(data []byte) (ControllerGrant, error) {
|
|
var g ControllerGrant
|
|
if err := decode(data, &g); err != nil {
|
|
return ControllerGrant{}, err
|
|
}
|
|
if err := g.check(); err != nil {
|
|
return ControllerGrant{}, err
|
|
}
|
|
return g, nil
|
|
}
|
|
|
|
// SameControllerGrant says whether two grants are the same value.
|
|
func SameControllerGrant(a, b ControllerGrant) bool { return reflect.DeepEqual(a, b) }
|
|
|
|
// NamesNode says whether the grant names module's accounts on node: its own `<node>.<module>` or a process's
|
|
// `<node>.<module>.<process>`. A grant that names no account (a module that does not speak on the bus) names every
|
|
// node. The assigner wants a node only once the grant names its account (issue 1945), and a put waits for it (ADR
|
|
// 0546 clause 4).
|
|
func (g ControllerGrant) NamesNode(node, module string) bool {
|
|
if len(g.Accounts) == 0 {
|
|
return true
|
|
}
|
|
own := node + "." + module
|
|
for _, a := range g.Accounts {
|
|
if a == own || strings.HasPrefix(a, own+".") {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// **The grants part's grants** (novox/hq ADR 0547 §4, §5, ADR 0561 §2, §6; issue 774). The grants part writes the same
|
|
// keys, with the same value, into its own state `grants` (the bucket PartGrantsBucket), beside the controller's: first in
|
|
// shadow, which nobody reads, so a tool can compare the two before anything switches. The assigner reads the part's keys
|
|
// only once the controller's lease is handed away (GrantSource), and the controller's until then.
|
|
const (
|
|
// PartGrantsState is the grants part's state of issued credentials by fingerprint, as its manifest names it.
|
|
PartGrantsState = "grants"
|
|
// PartGrantsBucket is that state's bucket, `<owner module>_<name>`.
|
|
PartGrantsBucket = "mesh-grants_" + PartGrantsState
|
|
// PartGrantsRead is that state as a reader names it in `reads`.
|
|
PartGrantsRead = "mesh-grants." + PartGrantsState
|
|
// PartGrantsHistory is the revisions the bucket keeps per key.
|
|
PartGrantsHistory = ControllerGrantsHistory
|
|
)
|
|
|
|
// PartGrantKey is the key, in PartGrantsBucket, of a module's credential issued for a fingerprint: the layout of the
|
|
// controller's key (ControllerGrantKey), so a key of one is the key of the other and a compare is by key.
|
|
func PartGrantKey(module, fingerprint string) (string, error) {
|
|
return ControllerGrantKey(module, fingerprint)
|
|
}
|
|
|
|
// ParsePartGrantKey is the inverse of PartGrantKey.
|
|
func ParsePartGrantKey(key string) (module, fingerprint string, err error) {
|
|
return ParseControllerGrantKey(key)
|
|
}
|
|
|
|
// GrantSource names the bucket the assigner reads grants from, and the `reads` name that grants it: the grants part's
|
|
// once the controller's lease is handed away (buscompose.LeaseHandedAway, which refuses every other value of the lease,
|
|
// an unreadable one included), the controller's in every other case.
|
|
func GrantSource(leaseHandedAway bool) (bucket, read string) {
|
|
if leaseHandedAway {
|
|
return PartGrantsBucket, PartGrantsRead
|
|
}
|
|
return ControllerGrantsBucket, "mesh-controller.grants"
|
|
}
|