node-engine: typed layouts for the states have (both forms), composed (both forms, wire names), data and health, with fixtures; Candidates typed as CandidateAnswer (ADR 0634 §1, §6; issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 14:50:04 +01:00
parent 99adc0eb98
commit f00aac3847
5 changed files with 2290 additions and 151 deletions
+430 -60
View File
@@ -185,6 +185,37 @@ func DecodeComposedByNodeModuleFingerprintValue(raw []byte) (ComposedByNodeModul
return v, nil return v, nil
} }
// ComposedByNodeNodeKey is the key of one value of the state composed under the form "<node>.node".
func ComposedByNodeNodeKey(node string) string { return node + ".node" }
// ParseComposedByNodeNodeKey reads the parts of a key of the form "<node>.node", in the order of the form; the last result is false for a key of another form.
func ParseComposedByNodeNodeKey(key string) (string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".node")
if !found0 || v0 == "" {
return "", false
}
rest = after0
if rest != "" {
return "", false
}
return v0, true
}
// DecodeComposedByNodeNodeValue reads one value of the state composed under the form "<node>.node", refusing a field ComposedByNodeNodeValue does not know and any text after the value.
func DecodeComposedByNodeNodeValue(raw []byte) (ComposedByNodeNodeValue, error) {
var v ComposedByNodeNodeValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// DataByNodeModuleKey is the key of one value of the state data under the form "<node>.<module>". // DataByNodeModuleKey is the key of one value of the state data under the form "<node>.<module>".
func DataByNodeModuleKey(node, module string) string { return node + "." + module } func DataByNodeModuleKey(node, module string) string { return node + "." + module }
@@ -314,6 +345,17 @@ func DecodeFindingsByKeyValue(raw []byte) (FindingsByKeyValue, error) {
return v, nil return v, nil
} }
// AccountsHanded is the hashes of the users of the list, sealed to the vault.
type AccountsHanded struct {
// when
At string `json:"at"`
Box SealedBox `json:"box"`
From string `json:"from"`
// the fingerprint of the vault's key
To string `json:"to"`
Users int64 `json:"users"`
}
// Act is one act asked through the seat, as acts reads it (ADR 0563 §9). // Act is one act asked through the seat, as acts reads it (ADR 0563 §9).
type Act struct { type Act struct {
// the act: hand-over, access-act, judge-directories or setuid-search // the act: hand-over, access-act, judge-directories or setuid-search
@@ -395,6 +437,14 @@ type Acts struct {
Node string `json:"node"` Node string `json:"node"`
} }
// Adoption is the node is adopted and which of its modules are taken.
type Adoption struct {
// the modules taken
Taken []string `json:"taken"`
// by module, the resources left untaken
Untaken map[string][]string `json:"untaken,omitempty"`
}
// Asked is the answer of an act the operator is asked. // Asked is the answer of an act the operator is asked.
type Asked struct { type Asked struct {
// the ask's id: acts shows where it stands // the ask's id: acts shows where it stands
@@ -405,6 +455,112 @@ type Asked struct {
Says string `json:"says"` Says string `json:"says"`
} }
// AttachedNetwork is a network attached to a link.
type AttachedNetwork struct {
Link string `json:"link"`
Network string `json:"network"`
}
// CandidateAdded is a module the candidate adds.
type CandidateAdded struct {
Composed string `json:"composed,omitempty"`
Module string `json:"module"`
Unissued []string `json:"unissued,omitempty"`
}
// CandidateAnswer is the node's answer to one placement candidate naming it.
type CandidateAnswer struct {
Added []CandidateAdded `json:"added,omitempty"`
Differs []CandidateDiffers `json:"differs,omitempty"`
Held []CandidateRefusal `json:"held,omitempty"`
Note string `json:"note,omitempty"`
Proposal string `json:"proposal"`
Refusals []CandidateRefusal `json:"refusals,omitempty"`
// why the node cannot compose with the candidate at all
Refused string `json:"refused,omitempty"`
// modules the candidate removes
Removed []string `json:"removed,omitempty"`
Returns string `json:"returns,omitempty"`
Revision int64 `json:"revision"`
// modules whose composition is the one running
Same []string `json:"same,omitempty"`
ValuesDiffer int64 `json:"values_differ,omitempty"`
// same, differs or refused
Verdict string `json:"verdict"`
}
// The values of CandidateAnswer's verdict.
const (
CandidateAnswerVerdictSame = "same"
CandidateAnswerVerdictDiffers = "differs"
CandidateAnswerVerdictRefused = "refused"
)
// CandidateBodies is the bodies of one resource that differ.
type CandidateBodies struct {
Composed string `json:"composed,omitempty"`
ID string `json:"id"`
Paths []string `json:"paths,omitempty"`
Running string `json:"running,omitempty"`
Why string `json:"why"`
}
// CandidateDiffers is a module whose composition with the candidate differs from the one running.
type CandidateDiffers struct {
Bodies []CandidateBodies `json:"bodies,omitempty"`
Composed string `json:"composed,omitempty"`
Module string `json:"module"`
Resource string `json:"resource,omitempty"`
Running string `json:"running,omitempty"`
Why string `json:"why"`
}
// CandidateRefusal is a module refused or held with the candidate.
type CandidateRefusal struct {
Module string `json:"module"`
Today string `json:"today,omitempty"`
Why string `json:"why"`
}
// DeclaredGroup is a group.
type DeclaredGroup struct {
Gid int64 `json:"gid"`
Name string `json:"name"`
}
// DeclaredIdentity is the identity of a module assigned to the node.
type DeclaredIdentity struct {
Gid int64 `json:"gid"`
Groups []int64 `json:"groups,omitempty"`
Module string `json:"module"`
Name string `json:"name"`
Runner string `json:"runner,omitempty"`
Uid int64 `json:"uid"`
}
// DeclaredLibrary is a library the node is reached by.
type DeclaredLibrary struct {
Gid int64 `json:"gid"`
Group string `json:"group"`
Home bool `json:"home"`
Library string `json:"library"`
Paths []string `json:"paths,omitempty"`
Root string `json:"root"`
Runner string `json:"runner,omitempty"`
Taken bool `json:"taken,omitempty"`
}
// FailedUnit is a unit that failed.
type FailedUnit struct {
Load string `json:"load,omitempty"`
Resource string `json:"resource,omitempty"`
Result string `json:"result,omitempty"`
Scope string `json:"scope"`
// since when
Since string `json:"since"`
Unit string `json:"unit"`
}
// FindingAction is one answer the operator may give from a notification. // FindingAction is one answer the operator may give from a notification.
type FindingAction struct { type FindingAction struct {
Arguments map[string]string `json:"arguments,omitempty"` Arguments map[string]string `json:"arguments,omitempty"`
@@ -439,6 +595,15 @@ type FindingSubject struct {
Scope string `json:"scope"` Scope string `json:"scope"`
} }
// LoginFallback is a login that fell back to another node.
type LoginFallback struct {
// when
At string `json:"at"`
From string `json:"from"`
Node string `json:"node"`
Why string `json:"why"`
}
// ManifestReadsChanged is what a node-engine says when what it reads changed or its node returned (ADR 0618 §4). // ManifestReadsChanged is what a node-engine says when what it reads changed or its node returned (ADR 0618 §4).
type ManifestReadsChanged struct { type ManifestReadsChanged struct {
// when it says it, RFC 3339 // when it says it, RFC 3339
@@ -482,6 +647,115 @@ const (
ModuleStateHeld = "held" ModuleStateHeld = "held"
) )
// NetworkHealth is the node's network.
type NetworkHealth struct {
Parts []NetworkPart `json:"parts"`
// since when
Since string `json:"since"`
// running, degraded or unknown
State string `json:"state"`
}
// NetworkPart is one part of the node's network.
type NetworkPart struct {
Owner string `json:"owner,omitempty"`
Part string `json:"part"`
Reason string `json:"reason,omitempty"`
Said string `json:"said,omitempty"`
// since when
Since string `json:"since"`
State string `json:"state"`
Streak int64 `json:"streak,omitempty"`
Targets []string `json:"targets,omitempty"`
Toward []string `json:"toward,omitempty"`
Writer string `json:"writer,omitempty"`
}
// NodeAccount is an account the node needs to log in again.
type NodeAccount struct {
Account string `json:"account"`
Module string `json:"module,omitempty"`
Reason string `json:"reason"`
Resource string `json:"resource,omitempty"`
// since when
Since string `json:"since"`
}
// NodeDirectory is a directory found where the node expected none.
type NodeDirectory struct {
Module string `json:"module"`
Path string `json:"path"`
Reason string `json:"reason"`
Resource string `json:"resource"`
// since when
Since string `json:"since"`
}
// NodeOwn is what a node's own composition carries beside its resources.
type NodeOwn struct {
Adoption *Adoption `json:"adoption,omitempty"`
Groups []DeclaredGroup `json:"groups,omitempty"`
Identities []DeclaredIdentity `json:"identities,omitempty"`
Libraries []DeclaredLibrary `json:"libraries,omitempty"`
// the account the provisioner's client runs as on the node
ProvisionerAccount string `json:"provisioner_account,omitempty"`
}
// NodeRecord is what the machine observes of itself, for every node and composing part to read.
type NodeRecord struct {
Authority string `json:"authority,omitempty"`
Capabilities []string `json:"capabilities,omitempty"`
Certificate string `json:"certificate,omitempty"`
Contract int64 `json:"contract,omitempty"`
ManifestReads []string `json:"manifest-reads,omitempty"`
Networks []AttachedNetwork `json:"networks,omitempty"`
NetworksSaid bool `json:"networks-said,omitempty"`
Node string `json:"node"`
OutwardLinks []string `json:"outward-links,omitempty"`
SealingKey string `json:"sealing-key,omitempty"`
ServingKey string `json:"serving-key,omitempty"`
Trusts []string `json:"trusts,omitempty"`
TunnelKey string `json:"tunnel-key,omitempty"`
V int64 `json:"v"`
}
// PeerSeen is a tunnel peer and whether it is seen.
type PeerSeen struct {
Addresses []string `json:"addresses,omitempty"`
Key string `json:"key"`
Seen bool `json:"seen"`
}
// PlacedDataItem is one data item a module declares, as placed on a node.
type PlacedDataItem struct {
Class string `json:"class"`
// the path whose snapshot keeps it, empty when it is not backed up
CoveredBy string `json:"covered_by,omitempty"`
Item string `json:"item"`
// walk, dataset or shallow
Measure string `json:"measure,omitempty"`
Module string `json:"module"`
// the item's place on the node
Path string `json:"path"`
// backup, redundancy, both or none
Protection string `json:"protection,omitempty"`
}
// PullWait is the pull from a store a failed apply waits on.
type PullWait struct {
// when the pull began
Began string `json:"began"`
// that seat's holder, whose settling the apply waits for
Holder string `json:"holder"`
Image string `json:"image"`
// what triggered the last try again, in words
Retried string `json:"retried,omitempty"`
// when the apply was last tried again
RetriedAt string `json:"retried-at,omitempty"`
// the seat the pull came through
Seat string `json:"seat,omitempty"`
}
// Revision is one revision of a composition key. // Revision is one revision of a composition key.
type Revision struct { type Revision struct {
// its digest // its digest
@@ -498,6 +772,17 @@ type Revision struct {
Revision int64 `json:"revision,omitempty"` Revision int64 `json:"revision,omitempty"`
} }
// RootAccountVerdict is the engine's verdict of whether an account's resource is root-free, as the node's health lists it.
type RootAccountVerdict struct {
Account string `json:"account"`
Module string `json:"module"`
Reason string `json:"reason,omitempty"`
Resource string `json:"resource"`
// since when
Since string `json:"since"`
State string `json:"state"`
}
// RootVerdict is the engine's root-free verdict (ADR 0563 §6). // RootVerdict is the engine's root-free verdict (ADR 0563 §6).
type RootVerdict struct { type RootVerdict struct {
// the machine is root-free // the machine is root-free
@@ -518,6 +803,15 @@ type Said struct {
Said string `json:"said"` Said string `json:"said"`
} }
// SealedBox is a value sealed to a key.
type SealedBox struct {
Ct string `json:"ct"`
Eph string `json:"eph"`
Iv string `json:"iv"`
Tag string `json:"tag"`
V int64 `json:"v"`
}
// SeatListStatus is a type of the contract. // SeatListStatus is a type of the contract.
type SeatListStatus struct { type SeatListStatus struct {
// the seat mesh-catalog has answered // the seat mesh-catalog has answered
@@ -554,6 +848,37 @@ const (
SeatListHeldSourceBootstrap = "bootstrap" SeatListHeldSourceBootstrap = "bootstrap"
) )
// UnitsHealth is the node's units.
type UnitsHealth struct {
Away []string `json:"away,omitempty"`
Failed []FailedUnit `json:"failed"`
State string `json:"state"`
Unread []string `json:"unread,omitempty"`
}
// UserListWritten is the bus's user list as the engine of the bus node wrote it to the bus module's file.
type UserListWritten struct {
// when
At string `json:"at"`
// the digest of the file on the machine after the write
Digest string `json:"digest,omitempty"`
// why a write failed
Error string `json:"error,omitempty"`
// which list the node follows now
Follows string `json:"follows,omitempty"`
Handed *AccountsHanded `json:"handed,omitempty"`
// the bus node's sealing key, its public half
Key string `json:"key,omitempty"`
Revision int64 `json:"revision"`
// the key the list was taken from
Source string `json:"source"`
// why the bus node does not watch the grants part's key now
Unwatched string `json:"unwatched,omitempty"`
Users int64 `json:"users"`
// the digest of the list the source holds, sha256:<hex>
Wanted string `json:"wanted"`
}
// HandOverInput is what hand-over takes. // HandOverInput is what hand-over takes.
type HandOverInput struct { type HandOverInput struct {
// the directory's absolute path, as the engine states it // the directory's absolute path, as the engine states it
@@ -905,75 +1230,119 @@ type ManifestReadsChangedEvent = ManifestReadsChanged
// HaveByNodeModuleValue is one value of the state have under the key <node>.<module>. // HaveByNodeModuleValue is one value of the state have under the key <node>.<module>.
type HaveByNodeModuleValue struct { type HaveByNodeModuleValue struct {
Build string `json:"build,omitempty"` Build string `json:"build,omitempty"`
BuildAlone bool `json:"build-alone,omitempty"` // the move changes the build alone
// the composition's digest BuildAlone bool `json:"build-alone,omitempty"`
// the digest of the composition the node runs
Composed string `json:"composed,omitempty"` Composed string `json:"composed,omitempty"`
Detail string `json:"detail,omitempty"` Detail string `json:"detail,omitempty"`
// the fingerprint held // the fingerprint held
Fp string `json:"fp,omitempty"` Fp string `json:"fp,omitempty"`
// the accounts handed Handed *AccountsHanded `json:"handed,omitempty"`
Handed map[string]any `json:"handed,omitempty"` // what the module's own check says
// how it is Health string `json:"health"`
Health string `json:"health"` // in phase waiting-yes, the judgement of the move
Judgement string `json:"judgement,omitempty"` Judgement string `json:"judgement,omitempty"`
Kept []string `json:"kept,omitempty"` // what the node keeps of the module as it runs
Kept []string `json:"kept,omitempty"`
// how far it has come // how far it has come
Phase string `json:"phase"` Phase string `json:"phase"`
// a pull the engine waits for PullWait *PullWait `json:"pull-wait,omitempty"`
PullWait map[string]any `json:"pull-wait,omitempty"` // each value sealed to the node's key
Sealed []string `json:"sealed,omitempty"` Sealed []string `json:"sealed,omitempty"`
SealedAt map[string]any `json:"sealed-at,omitempty"` // the sealed values by slot
// the user list written SealedAt map[string]string `json:"sealed-at,omitempty"`
UserList map[string]any `json:"user-list,omitempty"` UserList *UserListWritten `json:"user-list,omitempty"`
V int64 `json:"v"` V int64 `json:"v"`
// what it waits for // in phase waiting-yes, the digest of the composition that waits
Waits string `json:"waits,omitempty"` Waits string `json:"waits,omitempty"`
} }
// The values of HaveByNodeModuleValue's health.
const (
HaveByNodeModuleValueHealthOk = "ok"
HaveByNodeModuleValueHealthFailed = "failed"
HaveByNodeModuleValueHealthWaits = "waits"
HaveByNodeModuleValueHealthUnknown = "unknown"
)
// The values of HaveByNodeModuleValue's judgement.
const (
HaveByNodeModuleValueJudgementRecreates = "recreates"
HaveByNodeModuleValueJudgementMovesData = "moves-data"
HaveByNodeModuleValueJudgementCannotJudge = "cannot-judge"
)
// The values of HaveByNodeModuleValue's phase.
const (
HaveByNodeModuleValuePhaseBackingUp = "backing-up"
HaveByNodeModuleValuePhaseApplying = "applying"
HaveByNodeModuleValuePhaseChecking = "checking"
HaveByNodeModuleValuePhaseRunning = "running"
HaveByNodeModuleValuePhaseFailed = "failed"
HaveByNodeModuleValuePhaseRemoved = "removed"
HaveByNodeModuleValuePhaseHeld = "held"
HaveByNodeModuleValuePhaseWaitingYes = "waiting-yes"
)
// HaveByNodeNodeValue is one value of the state have under the key <node>.node. // HaveByNodeNodeValue is one value of the state have under the key <node>.node.
type HaveByNodeNodeValue struct { type HaveByNodeNodeValue struct {
Busy map[string]any `json:"busy,omitempty"` Busy map[string]any `json:"busy,omitempty"`
Candidates map[string]map[string]any `json:"candidates,omitempty"` // the node's answer to each placement candidate naming it, by proposal id
Composed string `json:"composed,omitempty"` Candidates map[string]CandidateAnswer `json:"candidates,omitempty"`
// own, or the controller's // the digest of the node's own composition it runs
Composes string `json:"composes,omitempty"` Composed string `json:"composed,omitempty"`
ComposesWhy string `json:"composes-why,omitempty"` // own, or none (empty)
Filters map[string]any `json:"filters,omitempty"` Composes string `json:"composes,omitempty"`
Profile map[string]any `json:"profile,omitempty"` ComposesWhy string `json:"composes-why,omitempty"`
// the node's record: its tunnel and certificate Filters map[string]any `json:"filters,omitempty"`
Record map[string]any `json:"record,omitempty"` Profile map[string]any `json:"profile,omitempty"`
Sealed []string `json:"sealed,omitempty"` Record *NodeRecord `json:"record,omitempty"`
SealedAt map[string]any `json:"sealed-at,omitempty"` Sealed []string `json:"sealed,omitempty"`
Strays map[string]any `json:"strays,omitempty"` SealedAt map[string]string `json:"sealed-at,omitempty"`
V int64 `json:"v"` Strays map[string]any `json:"strays,omitempty"`
Windows map[string]any `json:"windows,omitempty"` V int64 `json:"v"`
Windows map[string]any `json:"windows,omitempty"`
} }
// ComposedByNodeModuleFingerprintValue is one value of the state composed under the key <node>.<module>.<fingerprint>. // ComposedByNodeModuleFingerprintValue is one value of the state composed under the key <node>.<module>.<fingerprint>.
type ComposedByNodeModuleFingerprintValue struct { type ComposedByNodeModuleFingerprintValue struct {
Data bool `json:"Data,omitempty"` // the module declares data
FP string `json:"FP"` Data bool `json:"data,omitempty"`
Filled []string `json:"Filled,omitempty"` // the files the provisioner fills
Module string `json:"Module"` FilledFiles []string `json:"filled_files,omitempty"`
Node string `json:"Node"` Fp string `json:"fp"`
// the node's own adoption, identities, groups, libraries and provisioner account Module string `json:"module"`
Own map[string]any `json:"Own,omitempty"` Node string `json:"node"`
// the module's plan // the module's whole provisioning plan, catalogue.Plan, kept whole: it is the manifest layer's type
Plan map[string]any `json:"Plan,omitempty"` Plan map[string]any `json:"plan,omitempty"`
// why the composition was refused // why the module cannot be composed at this fingerprint
Refused string `json:"Refused,omitempty"` Refused string `json:"refused,omitempty"`
Resources []map[string]any `json:"Resources,omitempty"` // the declaration resources, each saying its module
V int64 `json:"V,omitempty"` Resources []map[string]any `json:"resources"`
V int64 `json:"v"`
}
// ComposedByNodeNodeValue is one value of the state composed under the key <node>.node.
type ComposedByNodeNodeValue struct {
// the module declares data
Data bool `json:"data,omitempty"`
// the files the provisioner fills
FilledFiles []string `json:"filled_files,omitempty"`
Node string `json:"node"`
Own *NodeOwn `json:"own,omitempty"`
// the declaration resources, each saying its module
Resources []map[string]any `json:"resources"`
V int64 `json:"v"`
} }
// DataByNodeModuleValue is one value of the state data under the key <node>.<module>. // DataByNodeModuleValue is one value of the state data under the key <node>.<module>.
type DataByNodeModuleValue struct { type DataByNodeModuleValue struct {
Digest string `json:"digest"` Digest string `json:"digest"`
Items []map[string]any `json:"items"` Items []PlacedDataItem `json:"items"`
Module string `json:"module"` Module string `json:"module"`
Node string `json:"node"` Node string `json:"node"`
V int64 `json:"v,omitempty"` V int64 `json:"v"`
} }
// PackagesByNodeValuePackagesItem is a type of the contract. // PackagesByNodeValuePackagesItem is a type of the contract.
@@ -991,17 +1360,18 @@ type PackagesByNodeValue struct {
// HealthByNodeValue is one value of the state health under the key <node>. // HealthByNodeValue is one value of the state health under the key <node>.
type HealthByNodeValue struct { type HealthByNodeValue struct {
At string `json:"at"` // when
Contract int64 `json:"contract,omitempty"` At string `json:"at"`
Fallback map[string]any `json:"fallback,omitempty"` Contract int64 `json:"contract,omitempty"`
Found []map[string]any `json:"found,omitempty"` Fallback *LoginFallback `json:"fallback,omitempty"`
Network map[string]any `json:"network,omitempty"` Found []NodeDirectory `json:"found,omitempty"`
Node string `json:"node"` Network *NetworkHealth `json:"network,omitempty"`
Peers []map[string]any `json:"peers,omitempty"` Node string `json:"node"`
Relogin []map[string]any `json:"relogin,omitempty"` Peers []PeerSeen `json:"peers,omitempty"`
Root []map[string]any `json:"root,omitempty"` Relogin []NodeAccount `json:"relogin,omitempty"`
Units map[string]any `json:"units,omitempty"` Root []RootAccountVerdict `json:"root,omitempty"`
V int64 `json:"v"` Units *UnitsHealth `json:"units,omitempty"`
V int64 `json:"v"`
} }
// FindingsByKeyValue is one value of the state findings under the key <key>. // FindingsByKeyValue is one value of the state findings under the key <key>.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+361 -40
View File
@@ -112,6 +112,22 @@ export function parseComposedByNodeModuleFingerprintKey(key: string): { node: st
return { node, module, fingerprint }; return { node, module, fingerprint };
} }
/** The key of one value of the state composed under the form "<node>.node". */
export function composedByNodeNodeKey(node: string): string {
return node + ".node";
}
/** The parts of a key of the form "<node>.node", or undefined for a key of another form. */
export function parseComposedByNodeNodeKey(key: string): { node: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".node");
if (at0 <= 0) return undefined;
const node = rest.slice(0, at0);
rest = rest.slice(at0 + 5);
if (rest !== "") return undefined;
return { node };
}
/** The key of one value of the state data under the form "<node>.<module>". */ /** The key of one value of the state data under the form "<node>.<module>". */
export function dataByNodeModuleKey(node: string, module: string): string { export function dataByNodeModuleKey(node: string, module: string): string {
return node + "." + module; return node + "." + module;
@@ -176,6 +192,17 @@ export function parseFindingsByKeyKey(key: string): { key: string } | undefined
return { key }; return { key };
} }
/** the hashes of the users of the list, sealed to the vault */
export interface AccountsHanded {
/** when */
"at": string;
"box": SealedBox;
"from": string;
/** the fingerprint of the vault's key */
"to": string;
"users": number;
}
/** one act asked through the seat, as acts reads it (ADR 0563 §9) */ /** one act asked through the seat, as acts reads it (ADR 0563 §9) */
export interface Act { export interface Act {
/** the act: hand-over, access-act, judge-directories or setuid-search */ /** the act: hand-over, access-act, judge-directories or setuid-search */
@@ -242,6 +269,14 @@ export interface Acts {
"node": string; "node": string;
} }
/** the node is adopted and which of its modules are taken */
export interface Adoption {
/** the modules taken */
"taken": string[];
/** by module, the resources left untaken */
"untaken"?: Record<string, string[]>;
}
/** the answer of an act the operator is asked */ /** the answer of an act the operator is asked */
export interface Asked { export interface Asked {
/** the ask's id: acts shows where it stands */ /** the ask's id: acts shows where it stands */
@@ -252,6 +287,105 @@ export interface Asked {
"says": string; "says": string;
} }
/** a network attached to a link */
export interface AttachedNetwork {
"link": string;
"network": string;
}
/** a module the candidate adds */
export interface CandidateAdded {
"composed"?: string;
"module": string;
"unissued"?: string[];
}
/** the node's answer to one placement candidate naming it */
export interface CandidateAnswer {
"added"?: CandidateAdded[];
"differs"?: CandidateDiffers[];
"held"?: CandidateRefusal[];
"note"?: string;
"proposal": string;
"refusals"?: CandidateRefusal[];
/** why the node cannot compose with the candidate at all */
"refused"?: string;
/** modules the candidate removes */
"removed"?: string[];
"returns"?: string;
"revision": number;
/** modules whose composition is the one running */
"same"?: string[];
"values_differ"?: number;
/** same, differs or refused */
"verdict": "same" | "differs" | "refused";
}
/** the bodies of one resource that differ */
export interface CandidateBodies {
"composed"?: string;
"id": string;
"paths"?: string[];
"running"?: string;
"why": string;
}
/** a module whose composition with the candidate differs from the one running */
export interface CandidateDiffers {
"bodies"?: CandidateBodies[];
"composed"?: string;
"module": string;
"resource"?: string;
"running"?: string;
"why": string;
}
/** a module refused or held with the candidate */
export interface CandidateRefusal {
"module": string;
"today"?: string;
"why": string;
}
/** a group */
export interface DeclaredGroup {
"gid": number;
"name": string;
}
/** the identity of a module assigned to the node */
export interface DeclaredIdentity {
"gid": number;
"groups"?: number[];
"module": string;
"name": string;
"runner"?: string;
"uid": number;
}
/** a library the node is reached by */
export interface DeclaredLibrary {
"gid": number;
"group": string;
"home": boolean;
"library": string;
"paths"?: string[];
"root": string;
"runner"?: string;
"taken"?: boolean;
}
/** a unit that failed */
export interface FailedUnit {
"load"?: string;
"resource"?: string;
"result"?: string;
"scope": string;
/** since when */
"since": string;
"unit": string;
}
/** one answer the operator may give from a notification */ /** one answer the operator may give from a notification */
export interface FindingAction { export interface FindingAction {
"arguments"?: Record<string, string>; "arguments"?: Record<string, string>;
@@ -280,6 +414,15 @@ export interface FindingSubject {
"scope": string; "scope": string;
} }
/** a login that fell back to another node */
export interface LoginFallback {
/** when */
"at": string;
"from": string;
"node": string;
"why": string;
}
/** what a node-engine says when what it reads changed or its node returned (ADR 0618 §4) */ /** what a node-engine says when what it reads changed or its node returned (ADR 0618 §4) */
export interface ManifestReadsChanged { export interface ManifestReadsChanged {
/** when it says it, RFC 3339 */ /** when it says it, RFC 3339 */
@@ -310,6 +453,115 @@ export interface Module {
"words"?: string; "words"?: string;
} }
/** the node's network */
export interface NetworkHealth {
"parts": NetworkPart[];
/** since when */
"since": string;
/** running, degraded or unknown */
"state": string;
}
/** one part of the node's network */
export interface NetworkPart {
"owner"?: string;
"part": string;
"reason"?: string;
"said"?: string;
/** since when */
"since": string;
"state": string;
"streak"?: number;
"targets"?: string[];
"toward"?: string[];
"writer"?: string;
}
/** an account the node needs to log in again */
export interface NodeAccount {
"account": string;
"module"?: string;
"reason": string;
"resource"?: string;
/** since when */
"since": string;
}
/** a directory found where the node expected none */
export interface NodeDirectory {
"module": string;
"path": string;
"reason": string;
"resource": string;
/** since when */
"since": string;
}
/** what a node's own composition carries beside its resources */
export interface NodeOwn {
"adoption"?: Adoption;
"groups"?: DeclaredGroup[];
"identities"?: DeclaredIdentity[];
"libraries"?: DeclaredLibrary[];
/** the account the provisioner's client runs as on the node */
"provisioner_account"?: string;
}
/** what the machine observes of itself, for every node and composing part to read */
export interface NodeRecord {
"authority"?: string;
"capabilities"?: string[];
"certificate"?: string;
"contract"?: number;
"manifest-reads"?: string[];
"networks"?: AttachedNetwork[];
"networks-said"?: boolean;
"node": string;
"outward-links"?: string[];
"sealing-key"?: string;
"serving-key"?: string;
"trusts"?: string[];
"tunnel-key"?: string;
"v": number;
}
/** a tunnel peer and whether it is seen */
export interface PeerSeen {
"addresses"?: string[];
"key": string;
"seen": boolean;
}
/** one data item a module declares, as placed on a node */
export interface PlacedDataItem {
"class": string;
/** the path whose snapshot keeps it, empty when it is not backed up */
"covered_by"?: string;
"item": string;
/** walk, dataset or shallow */
"measure"?: string;
"module": string;
/** the item's place on the node */
"path": string;
/** backup, redundancy, both or none */
"protection"?: string;
}
/** the pull from a store a failed apply waits on */
export interface PullWait {
/** when the pull began */
"began": string;
/** that seat's holder, whose settling the apply waits for */
"holder": string;
"image": string;
/** what triggered the last try again, in words */
"retried"?: string;
/** when the apply was last tried again */
"retried-at"?: string;
/** the seat the pull came through */
"seat"?: string;
}
/** one revision of a composition key */ /** one revision of a composition key */
export interface Revision { export interface Revision {
/** its digest */ /** its digest */
@@ -326,6 +578,17 @@ export interface Revision {
"revision"?: number; "revision"?: number;
} }
/** the engine's verdict of whether an account's resource is root-free, as the node's health lists it */
export interface RootAccountVerdict {
"account": string;
"module": string;
"reason"?: string;
"resource": string;
/** since when */
"since": string;
"state": string;
}
/** the engine's root-free verdict (ADR 0563 §6) */ /** the engine's root-free verdict (ADR 0563 §6) */
export interface RootVerdict { export interface RootVerdict {
/** the machine is root-free */ /** the machine is root-free */
@@ -346,6 +609,15 @@ export interface Said {
"said": string; "said": string;
} }
/** a value sealed to a key */
export interface SealedBox {
"ct": string;
"eph": string;
"iv": string;
"tag": string;
"v": number;
}
export interface SeatListStatus { export interface SeatListStatus {
/** the seat mesh-catalog has answered */ /** the seat mesh-catalog has answered */
"heard": boolean; "heard": boolean;
@@ -374,6 +646,37 @@ export interface SeatListHeld {
"source": "trunk" | "bootstrap"; "source": "trunk" | "bootstrap";
} }
/** the node's units */
export interface UnitsHealth {
"away"?: string[];
"failed": FailedUnit[];
"state": string;
"unread"?: string[];
}
/** the bus's user list as the engine of the bus node wrote it to the bus module's file */
export interface UserListWritten {
/** when */
"at": string;
/** the digest of the file on the machine after the write */
"digest"?: string;
/** why a write failed */
"error"?: string;
/** which list the node follows now */
"follows"?: string;
"handed"?: AccountsHanded;
/** the bus node's sealing key, its public half */
"key"?: string;
"revision": number;
/** the key the list was taken from */
"source": string;
/** why the bus node does not watch the grants part's key now */
"unwatched"?: string;
"users": number;
/** the digest of the list the source holds, sha256:<hex> */
"wanted": string;
}
/** is what hand-over takes. */ /** is what hand-over takes. */
export interface HandOverInput { export interface HandOverInput {
/** the directory's absolute path, as the engine states it */ /** the directory's absolute path, as the engine states it */
@@ -711,45 +1014,48 @@ export type ManifestReadsChangedEvent = ManifestReadsChanged;
/** is one value of the state have under the key <node>.<module>. */ /** is one value of the state have under the key <node>.<module>. */
export interface HaveByNodeModuleValue { export interface HaveByNodeModuleValue {
"build"?: string; "build"?: string;
/** the move changes the build alone */
"build-alone"?: boolean; "build-alone"?: boolean;
/** the composition's digest */ /** the digest of the composition the node runs */
"composed"?: string; "composed"?: string;
"detail"?: string; "detail"?: string;
/** the fingerprint held */ /** the fingerprint held */
"fp"?: string; "fp"?: string;
/** the accounts handed */ "handed"?: AccountsHanded;
"handed"?: Record<string, unknown>; /** what the module's own check says */
/** how it is */ "health": "ok" | "failed" | "waits" | "unknown";
"health": string; /** in phase waiting-yes, the judgement of the move */
"judgement"?: string; "judgement"?: "recreates" | "moves-data" | "cannot-judge";
/** what the node keeps of the module as it runs */
"kept"?: string[]; "kept"?: string[];
/** how far it has come */ /** how far it has come */
"phase": string; "phase": "backing-up" | "applying" | "checking" | "running" | "failed" | "removed" | "held" | "waiting-yes";
/** a pull the engine waits for */ "pull-wait"?: PullWait;
"pull-wait"?: Record<string, unknown>; /** each value sealed to the node's key */
"sealed"?: string[]; "sealed"?: string[];
"sealed-at"?: Record<string, unknown>; /** the sealed values by slot */
/** the user list written */ "sealed-at"?: Record<string, string>;
"user-list"?: Record<string, unknown>; "user-list"?: UserListWritten;
"v": number; "v": number;
/** what it waits for */ /** in phase waiting-yes, the digest of the composition that waits */
"waits"?: string; "waits"?: string;
} }
/** is one value of the state have under the key <node>.node. */ /** is one value of the state have under the key <node>.node. */
export interface HaveByNodeNodeValue { export interface HaveByNodeNodeValue {
"busy"?: Record<string, unknown>; "busy"?: Record<string, unknown>;
"candidates"?: Record<string, Record<string, unknown>>; /** the node's answer to each placement candidate naming it, by proposal id */
"candidates"?: Record<string, CandidateAnswer>;
/** the digest of the node's own composition it runs */
"composed"?: string; "composed"?: string;
/** own, or the controller's */ /** own, or none (empty) */
"composes"?: string; "composes"?: string;
"composes-why"?: string; "composes-why"?: string;
"filters"?: Record<string, unknown>; "filters"?: Record<string, unknown>;
"profile"?: Record<string, unknown>; "profile"?: Record<string, unknown>;
/** the node's record: its tunnel and certificate */ "record"?: NodeRecord;
"record"?: Record<string, unknown>;
"sealed"?: string[]; "sealed"?: string[];
"sealed-at"?: Record<string, unknown>; "sealed-at"?: Record<string, string>;
"strays"?: Record<string, unknown>; "strays"?: Record<string, unknown>;
"v": number; "v": number;
"windows"?: Record<string, unknown>; "windows"?: Record<string, unknown>;
@@ -757,28 +1063,42 @@ export interface HaveByNodeNodeValue {
/** is one value of the state composed under the key <node>.<module>.<fingerprint>. */ /** is one value of the state composed under the key <node>.<module>.<fingerprint>. */
export interface ComposedByNodeModuleFingerprintValue { export interface ComposedByNodeModuleFingerprintValue {
"Data"?: boolean; /** the module declares data */
"FP": string; "data"?: boolean;
"Filled"?: string[]; /** the files the provisioner fills */
"Module": string; "filled_files"?: string[];
"Node": string; "fp": string;
/** the node's own adoption, identities, groups, libraries and provisioner account */ "module": string;
"Own"?: Record<string, unknown>; "node": string;
/** the module's plan */ /** the module's whole provisioning plan, catalogue.Plan, kept whole: it is the manifest layer's type */
"Plan"?: Record<string, unknown>; "plan"?: Record<string, unknown>;
/** why the composition was refused */ /** why the module cannot be composed at this fingerprint */
"Refused"?: string; "refused"?: string;
"Resources"?: Record<string, unknown>[]; /** the declaration resources, each saying its module */
"V"?: number; "resources": Record<string, unknown>[];
"v": number;
}
/** is one value of the state composed under the key <node>.node. */
export interface ComposedByNodeNodeValue {
/** the module declares data */
"data"?: boolean;
/** the files the provisioner fills */
"filled_files"?: string[];
"node": string;
"own"?: NodeOwn;
/** the declaration resources, each saying its module */
"resources": Record<string, unknown>[];
"v": number;
} }
/** is one value of the state data under the key <node>.<module>. */ /** is one value of the state data under the key <node>.<module>. */
export interface DataByNodeModuleValue { export interface DataByNodeModuleValue {
"digest": string; "digest": string;
"items": Record<string, unknown>[]; "items": PlacedDataItem[];
"module": string; "module": string;
"node": string; "node": string;
"v"?: number; "v": number;
} }
export interface PackagesByNodeValuePackagesItem { export interface PackagesByNodeValuePackagesItem {
@@ -795,16 +1115,17 @@ export interface PackagesByNodeValue {
/** is one value of the state health under the key <node>. */ /** is one value of the state health under the key <node>. */
export interface HealthByNodeValue { export interface HealthByNodeValue {
/** when */
"at": string; "at": string;
"contract"?: number; "contract"?: number;
"fallback"?: Record<string, unknown>; "fallback"?: LoginFallback;
"found"?: Record<string, unknown>[]; "found"?: NodeDirectory[];
"network"?: Record<string, unknown>; "network"?: NetworkHealth;
"node": string; "node": string;
"peers"?: Record<string, unknown>[]; "peers"?: PeerSeen[];
"relogin"?: Record<string, unknown>[]; "relogin"?: NodeAccount[];
"root"?: Record<string, unknown>[]; "root"?: RootAccountVerdict[];
"units"?: Record<string, unknown>; "units"?: UnitsHealth;
"v": number; "v": number;
} }