Files
mesh-controller/cmd/mesh-controller/process_accounts.go
T

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)
}
}
}