131 lines
4.5 KiB
Go
131 lines
4.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
|
|
"github.com/novox/mesh-controller/internal/broker"
|
|
"github.com/novox/mesh-controller/internal/inventory"
|
|
)
|
|
|
|
// processUser is the bus user of one process of a module on a node (novox/hq ADR 0436 §1).
|
|
func processUser(node, module, process string) string {
|
|
return broker.Principal{Kind: broker.KindProcess, Node: node, Module: module, Process: process}.Username()
|
|
}
|
|
|
|
// processAccountWarning is the warning line for the own secret broker-<process id> of a process that declares bus
|
|
// when nobody issued its account (novox/hq ADR 0436 §2, issue 1226): "" for any other secret and for an issued
|
|
// account. The send goes on with the stand-in until the composition leaves the module off (issue 1753), so the
|
|
// line is the only loud thing about it.
|
|
func processAccountWarning(m catalogue.Manifest, node, secret string, minted []string) string {
|
|
id, isProcess := strings.CutPrefix(secret, "broker-")
|
|
if !isProcess {
|
|
return ""
|
|
}
|
|
if _, declared := m.ProcessBuses()[id]; !declared {
|
|
return ""
|
|
}
|
|
user := processUser(node, m.Module, id)
|
|
for _, u := range minted {
|
|
if u == user {
|
|
return ""
|
|
}
|
|
}
|
|
return fmt.Sprintf("%s/%s process %s: its bus account is not issued — mesh-controller.issue %s %s",
|
|
node, m.Module, id, node, m.Module)
|
|
}
|
|
|
|
// sayWarning writes a line where the compose's other warnings go: the act's answer when it carries a writer,
|
|
// else the controller's journal.
|
|
func sayWarning(ctx context.Context, line string) {
|
|
var w io.Writer = os.Stderr
|
|
if lw, ok := ctx.Value(leftOutKey{}).(io.Writer); ok {
|
|
w = lw
|
|
}
|
|
fmt.Fprintln(w, line)
|
|
}
|
|
|
|
// processAccountsMissing is each process of m that declares bus and whose account is not minted yet on node.
|
|
func processAccountsMissing(m catalogue.Manifest, node string, minted []string) []broker.ProcessPrincipal {
|
|
have := map[string]bool{}
|
|
for _, u := range minted {
|
|
have[u] = true
|
|
}
|
|
var out []broker.ProcessPrincipal
|
|
for _, pr := range inventory.ProcessesOf(m) {
|
|
if !have[processUser(node, m.Module, pr.Process)] {
|
|
out = append(out, pr)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// issueMissingProcessAccounts issues the accounts of m's bus processes on node that are not minted, and no
|
|
// other: an account already issued is rotated on purpose, never by a later delivery or assignment (issue 1226).
|
|
// It says what it issued, one line, and nothing when nothing was missing.
|
|
func issueMissingProcessAccounts(ctx context.Context, inv *inventory.Inventory, m catalogue.Manifest, node string) (string, error) {
|
|
if len(m.ProcessBuses()) == 0 || mayIssue(m) != nil {
|
|
return "", nil
|
|
}
|
|
minted, err := inv.BusMinted(ctx)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
missing := processAccountsMissing(m, node, minted)
|
|
if len(missing) == 0 {
|
|
return "", nil
|
|
}
|
|
known, err := broker.FromEnvironment()
|
|
if err != nil {
|
|
return "", fmt.Errorf("cannot deliver a credential without knowing where the bus is: %w", err)
|
|
}
|
|
reachable, err := brokerReachableAt(ctx, inv, known, node)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
busAddress, err := broker.BusAddress()
|
|
if err != nil {
|
|
busAddress = ""
|
|
}
|
|
var ids []string
|
|
for _, pr := range missing {
|
|
if err := issueProcess(ctx, inv, m, pr, node, busAddress, known, reachable); err != nil {
|
|
return "", err
|
|
}
|
|
ids = append(ids, pr.Process)
|
|
}
|
|
return fmt.Sprintf("its process account(s) %s issued and sealed to %s, and arrive with the push",
|
|
strings.Join(ids, ", "), node), nil
|
|
}
|
|
|
|
// issueGainedProcessAccounts runs after a module's new definition is registered: on each machine assigned it, the
|
|
// accounts of its bus processes not yet minted are issued, so a process a delivery adds is not pushed with a
|
|
// random stand-in (issue 1226). Never fatal: the build worked and the module is registered, so a failure is said,
|
|
// and the push refuses the module until `mesh-controller.issue` is run.
|
|
func issueGainedProcessAccounts(ctx context.Context, inv *inventory.Inventory, m catalogue.Manifest) {
|
|
if len(m.ProcessBuses()) == 0 {
|
|
return
|
|
}
|
|
nodes, err := inv.Running(ctx, m.Module)
|
|
if err != nil {
|
|
fmt.Printf("%s: its machines are not read to issue its process accounts: %v\n", m.Module, err)
|
|
return
|
|
}
|
|
for _, node := range nodes {
|
|
line, err := issueMissingProcessAccounts(ctx, inv, m, node)
|
|
if err != nil {
|
|
fmt.Printf("%s on %s: its process accounts are not issued (%v): `mesh-controller.issue %s %s` first\n",
|
|
m.Module, node, err, node, m.Module)
|
|
continue
|
|
}
|
|
if line != "" {
|
|
fmt.Printf("%s on %s: %s\n", m.Module, node, line)
|
|
}
|
|
}
|
|
}
|