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