Issue an account whose credential is not sealed, and forget an unassigned module's accounts (issue 1945, ADR 0543)
Met a second time live on 2026-10-25 at 20:04 (note 35): mesh-build-go was
assigned to ace again, and its account rows, minted at 17:19, had outlived the
unassignment. The issue minted only when no row stood, so it minted and sealed
nothing; the node had no credential and the bus no user, and the module
crash-looped 20 times. The watch still said "the grants written".
- A bus account now says when its credential was sealed to its node (migration
0108; every account standing before is taken as sealed). An issue under the
assign act, the assignments' watch or a registration mints only an account
that is not issued, a row with no seal counting as none, under the store's
lock on the account across its look, mint and seal, and marks it sealed once
sealed. A seal that fails leaves it unsealed for the next issue.
- Unassigning a module forgets its bus accounts and their credentials on that
node, so an assignment again issues them afresh.
- Only sealed accounts count as minted for a composition and are named in a
grant, so the assigner, which now wants a node only once the grant names its
account (mesh-delivery, same branch), holds the node until it is.
- The assignment's log line says which accounts were issued and sealed, or that
they stood issued and sealed.
The process-only issue drops the atomic insert of the review of 9ff47f6a for
the lock, which also covers the seal. Tests: cases in the existing tables.
Research 072: the grants piece (memberships and credentials heard from placement).
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -195,22 +196,27 @@ func issueAssignmentAccounts(ctx context.Context, inv *inventory.Inventory, shel
|
||||
if !known || mayIssue(m) != nil {
|
||||
return false, "", nil
|
||||
}
|
||||
if user, own := ownAccountOf(m, node); own {
|
||||
_, minted, err := inv.BusUserHash(ctx, user)
|
||||
if _, own := ownAccountOf(m, node); own {
|
||||
minted, err := inv.BusMinted(ctx) // sealed accounts alone: a row with no sealed credential is not issued
|
||||
if err != nil {
|
||||
return false, "", fmt.Errorf("whether %s is minted cannot be read: %w", user, err)
|
||||
return false, "", fmt.Errorf("the issued accounts cannot be read: %w", err)
|
||||
}
|
||||
if !minted {
|
||||
if missingAccounts(m, node, minted) {
|
||||
busAddress, err := broker.BusAddress()
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
// Its processes' accounts too: issueOnTheNewBus issues every one of them with the module's own.
|
||||
// Its processes' and provisioner client's accounts too: issueOnTheNewBus issues each that is not issued.
|
||||
ctx, got := withIssued(ctx)
|
||||
if err := issueOnTheNewBus(ctx, inv, m, node, busAddress); err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
return true, "its bus credential issued as " + user, nil
|
||||
if issued := got.list(); len(issued) > 0 {
|
||||
return true, "issued and sealed to " + node + ": " + strings.Join(issued, ", "), nil
|
||||
}
|
||||
return false, "", nil
|
||||
}
|
||||
return false, "its bus accounts on " + node + " stood issued and sealed", nil
|
||||
}
|
||||
line, err := issueMissingProcessAccounts(ctx, inv, m, node)
|
||||
if err != nil {
|
||||
@@ -219,6 +225,18 @@ func issueAssignmentAccounts(ctx context.Context, inv *inventory.Inventory, shel
|
||||
return line != "", line, nil
|
||||
}
|
||||
|
||||
// missingAccounts says some account of m on node is not issued: its own, a process's, or its provisioner client's.
|
||||
func missingAccounts(m catalogue.Manifest, node string, minted []string) bool {
|
||||
if user, own := ownAccountOf(m, node); own && !slices.Contains(minted, user) {
|
||||
return true
|
||||
}
|
||||
if runsTheProvisionerClient(m) &&
|
||||
!slices.Contains(minted, broker.Principal{Kind: broker.KindProvisioner, Node: node, Module: m.Module}.Username()) {
|
||||
return true
|
||||
}
|
||||
return len(processAccountsMissing(m, node, minted)) > 0
|
||||
}
|
||||
|
||||
// liveAssignmentAccountSteps are the steps on the controller's own stores and the bus: the composer's passes, as the
|
||||
// done keys' take-ins use them, so a node asked for by both is composed once a pass.
|
||||
func liveAssignmentAccountSteps(open *stores) assignmentAccountSteps {
|
||||
|
||||
Reference in New Issue
Block a user