pub struct Core<B: Backends + Clone, S: Store> {Show 61 fields
pub admin_of: Arc<dyn Fn(u32) -> bool + Send + Sync>,
acting_agent: Option<String>,
after_ready: Vec<TxnId>,
pub ex: Executor<B, S>,
pub b: B,
pub asm: Assembler,
pub incidents: Manager,
pub notices: VecDeque<String>,
pub notices_total: u64,
pub log: Vec<LogRecord>,
cfg: CoreConfig,
last: Option<(SystemState, UnitDefs)>,
choices: BTreeMap<u32, Vec<Match>>,
incident_parked: BTreeMap<IncidentId, TxnId>,
pub slow_tick_warnings: u64,
last_slow_warning: Option<Timestamp>,
slow_ticks_unwarned: u64,
writebacks: Vec<(Proposal, Authorization)>,
confirm: Option<(GenerationId, Timestamp)>,
manifest_gen: GenerationId,
gen_manifest: Manifest,
pub external: Option<DesiredDoc>,
pub new_declarations: Vec<(String, String)>,
new_declarations_since: Timestamp,
interlock_noted: bool,
restart_reminded: BTreeMap<TxnId, Timestamp>,
residue_taught: bool,
repaired_before_confirmation: BTreeSet<UnitId>,
diag_noted: BTreeSet<IncidentId>,
unreachable: BTreeMap<UnitId, (Timestamp, bool)>,
chain_checked: Option<Timestamp>,
pub integrity: Option<String>,
prev_status: BTreeMap<UnitId, UnitStatus>,
prev_auto_restarts: BTreeMap<UnitId, u32>,
boot_report_due: bool,
last_boot_report: Option<(Timestamp, GenerationId, String)>,
quiet: bool,
quiet_queue: Vec<String>,
reprepare: Vec<(TxnId, Transition)>,
hold_table_seen: bool,
hold_missing_noted: bool,
hold_retry: Option<(Timestamp, Millis)>,
daemon_held: BTreeSet<UnitId>,
hold_unconfirmed: BTreeMap<UnitId, Timestamp>,
lift_unconfirmed: BTreeMap<UnitId, Timestamp>,
hold_left: Millis,
withdrawn: Vec<(TxnId, Transition, Option<Timestamp>)>,
pub earlier: BTreeMap<TxnId, (Proposal, Actor)>,
touched: BTreeSet<UnitId>,
generation_touched: bool,
next_gc_check: Timestamp,
space_noted: Timestamp,
awaiting_post: Vec<LogRecord>,
pub defer: bool,
pub building: Option<(String, Timestamp)>,
deferred: Option<(PrebuildJob<B::Gens>, Resume)>,
core_hash: Hash,
core_hash_record: Option<PathBuf>,
parked_agents: BTreeMap<TxnId, Option<String>>,
hold_released: BTreeSet<UnitId>,
hold_notified: BTreeSet<UnitId>,
}Fields§
§admin_of: Arc<dyn Fn(u32) -> bool + Send + Sync>Whether a uid is an administrator (root or planarian-admin), for
the user an agent acts for; set by the daemon from the group file.
acting_agent: Option<String>The agent behind the request being handled, for its log records.
after_ready: Vec<TxnId>Recoveries left by start until after ready (finish_recovery).
ex: Executor<B, S>§b: B§asm: Assembler§incidents: Manager§notices: VecDeque<String>§notices_total: u64How many notices there have ever been (the deque keeps the last
NOTICES_KEPT), so the binary can print each new one once.
log: Vec<LogRecord>Drained by the binary into the executor log file.
cfg: CoreConfig§last: Option<(SystemState, UnitDefs)>§choices: BTreeMap<u32, Vec<Match>>§incident_parked: BTreeMap<IncidentId, TxnId>§slow_tick_warnings: u64Slow ticks warned (P9), and when the last warning was.
last_slow_warning: Option<Timestamp>§slow_ticks_unwarned: u64§writebacks: Vec<(Proposal, Authorization)>§12a write-backs queued behind an active generation transaction, with their caller (P7). Submitted once none is live.
confirm: Option<(GenerationId, Timestamp)>§manifest_gen: GenerationId§gen_manifest: ManifestThe running generation’s manifest, before the external source joins it.
external: Option<DesiredDoc>The external desired-state document in force (§9 hook), verified by main.
new_declarations: Vec<(String, String)>Services the running generation declares that the one before it did not, with where each came from, and since when (§15: a malicious declaration is reported with its origin).
new_declarations_since: Timestamp§interlock_noted: bool§restart_reminded: BTreeMap<TxnId, Timestamp>When each transaction in AwaitingBoot was last said to need a
restart (CLOCK_BOOTTIME); repeated daily (§12f).
residue_taught: boolThe attributed way to stop a unit has been taught once (§16, P23).
repaired_before_confirmation: BTreeSet<UnitId>Canonical units repaired while an admitted boot-only change waits for its confirmation; any one means it is not confirmed (§10).
diag_noted: BTreeSet<IncidentId>Incidents whose opening was already announced.
unreachable: BTreeMap<UnitId, (Timestamp, bool)>External dependencies whose probes time out: since when, and whether that was said (§10: Unknown, never Failed, so no incident).
chain_checked: Option<Timestamp>When the journal’s hash chain was last re-read from disk (I18).
integrity: Option<String>A broken chain found while running; main stops on it (§12d: the
response is in the posture units, not here).
prev_status: BTreeMap<UnitId, UnitStatus>Each unit’s status at the previous tick, to see transitions (§11 residue).
prev_auto_restarts: BTreeMap<UnitId, u32>Security units’ systemd restart counts at the previous tick (§11: a kill systemd itself repaired is still alarmed).
boot_report_due: boolThe boot report runs on the first tick after boot (§10).
last_boot_report: Option<(Timestamp, GenerationId, String)>The last boot report this daemon ran, for planarian report boot.
quiet: boolQuiet mode (§12f) and the notices it holds back.
quiet_queue: Vec<String>§reprepare: Vec<(TxnId, Transition)>Waiting generations interrupted by a restart, to prepare again (§12f).
hold_table_seen: bool§12d: the hold’s firewall table was there at the last check (or no hold was active). The alarm is raised once, on the change to missing or uncheckable.
hold_missing_noted: bool§12d: this episode’s “removed” alarm and HoldApplied are written
(separately from the “could not be checked” one, so an episode that
starts uncheckable still journals the re-apply).
hold_retry: Option<(Timestamp, Millis)>§12d: while the table is missing, the next re-apply (boot clock) and
the wait after it, doubling to HOLD_RETRY_MAX.
daemon_held: BTreeSet<UnitId>§12d: units the daemon itself asked the host to hold for a stop
outside Planarian (the residue path); their HoldApplied is by it.
hold_unconfirmed: BTreeMap<UnitId, Timestamp>§12d: units whose hold the host has not confirmed in time (alarmed once), and when to ask again: a wedged hold job is not re-called on every tick, where it would spend the whole hold budget and starve other units’ lifts.
lift_unconfirmed: BTreeMap<UnitId, Timestamp>§12d: units whose lift the host has not confirmed (HoldLifted is
journaled; the host may still hold them), and when to ask again. While
one stands, the unit is not journaled as held again, and its lift is
retried quietly at HOLD_UNCONFIRMED_RETRY’s cadence, so a hung lift
neither churns the journal nor spends every tick’s budget.
hold_left: Millis§12d: the end of this tick’s hold budget (hold_wait).
withdrawn: Vec<(TxnId, Transition, Option<Timestamp>)>Generation transactions withdrawn from Built for a rollback about to
run (§12f, I6; owner decision, Nov 2), with when each began waiting,
to prepare again once no generation transaction is active.
earlier: BTreeMap<TxnId, (Proposal, Actor)>From the executor log of earlier runs: each transaction’s proposal and caller, so one prepared again keeps its source and caller (§12, C21).
touched: BTreeSet<UnitId>Units Planarian’s own transactions touched since the previous tick, and whether a generation changed: their stops are not someone else’s.
generation_touched: bool§next_gc_check: TimestampWhen to next check the §12b collection bounds.
space_noted: TimestampThe space report last noticed.
awaiting_post: Vec<LogRecord>Executor log records waiting for their post-state (I7).
defer: boolSet by the daemon: a catalog change’s stage, evaluate and build are
handed back as a PrebuildJob (take_deferred) to run on another
thread, instead of running inside handle. Off in tests and the gym.
building: Option<(String, Timestamp)>Set by the daemon while a deferred change builds elsewhere: what, and since when.
deferred: Option<(PrebuildJob<B::Gens>, Resume)>§core_hash: HashThe hash of the core-hash record the running generation installs
(/etc/planarian/core.sha256, I2), for SystemState.core_hash and
so for digest() (P19). Read when the daemon names the record
(set_core_hash_record) and again whenever the running generation
changes; zero where no record exists (tests, the fake harness).
core_hash_record: Option<PathBuf>§parked_agents: BTreeMap<TxnId, Option<String>>The agent behind each change parked for approval, for the approved execution’s log record (I7).
hold_released: BTreeSet<UnitId>§12d: held units whose hold an attested release lifted, until the release ends; and held units whose failed repair administrators have been told about (once per hold).
hold_notified: BTreeSet<UnitId>Implementations§
Source§impl<B: Backends + Clone, S: Store> Core<B, S>
impl<B: Backends + Clone, S: Store> Core<B, S>
Sourcepub fn start(
journal: Journal<S>,
b: B,
me: OwnerId,
cfg: CoreConfig,
) -> Core<B, S>
pub fn start( journal: Journal<S>, b: B, me: OwnerId, cfg: CoreConfig, ) -> Core<B, S>
Start: adopt the running generation, reconcile the journal, restore incidents, load the manifest, and schedule boot confirmation.
Sourcepub fn remember(&mut self, records: impl IntoIterator<Item = LogRecord>)
pub fn remember(&mut self, records: impl IntoIterator<Item = LogRecord>)
Records from the executor log of earlier runs (§12, C21): what each transaction was proposed as, and by whom.
Sourcepub fn last_observation(&self) -> Option<&(SystemState, UnitDefs)>
pub fn last_observation(&self) -> Option<&(SystemState, UnitDefs)>
The observation the last tick (or request) acted on.
pub fn notice(&mut self, s: String)
fn say(&mut self, s: String)
Sourcepub fn notices_since(&self, printed: u64) -> impl Iterator<Item = &String>
pub fn notices_since(&self, printed: u64) -> impl Iterator<Item = &String>
The notices made since printed of them (counted by
notices_total) were seen, oldest first: what to journal next.
fn journal(&mut self, r: Record)
pub fn ledger(&mut self) -> Ledger
Sourcepub fn set_core_hash_record(&mut self, record: PathBuf)
pub fn set_core_hash_record(&mut self, record: PathBuf)
P19: the record the running generation installs, for the state’s
core_hash; read now and on every generation change.
Sourcefn read_core_hash(&mut self)
fn read_core_hash(&mut self)
An unreadable record (not a missing one) keeps the value already held and says so: nothing is derived from a failed read (rule 21).
fn context(&self, l: &Ledger, current: GenerationId) -> Context
Sourcefn protect(&self, l: &Ledger, current: GenerationId) -> Vec<GenerationId>
fn protect(&self, l: &Ledger, current: GenerationId) -> Vec<GenerationId>
Generations GC must keep (I3): known-good, previous, current, boot default, live-tested, accepted baseline, and every in-flight candidate.
Sourcepub fn pending_recovery(&self) -> Option<String>
pub fn pending_recovery(&self) -> Option<String>
What finish_recovery will do, for “busy with …”; None if nothing.
Sourcepub fn finish_recovery(&mut self)
pub fn finish_recovery(&mut self)
After ready: run the recoveries start left (CoreConfig::defer_recovery).
Sourcepub fn observe(&mut self) -> (SystemState, UnitDefs)
pub fn observe(&mut self) -> (SystemState, UnitDefs)
Observe without acting (also used to answer requests).
fn proposal( &self, t: Transition, s: &SystemState, defs: &UnitDefs, source: Source, reason: String, ) -> Proposal
fn submit( &mut self, p: Proposal, authz: Authorization, s: &SystemState, defs: &UnitDefs, ) -> Submitted
Sourcefn submit_from(
&mut self,
p: Proposal,
authz: Authorization,
s: &SystemState,
defs: &UnitDefs,
again: Option<TxnId>,
) -> Submitted
fn submit_from( &mut self, p: Proposal, authz: Authorization, s: &SystemState, defs: &UnitDefs, again: Option<TxnId>, ) -> Submitted
again: the withdrawn transaction this prepares again (§12f), set
only by prepare_again.
Sourcefn hold_wait(&self) -> Option<Millis>
fn hold_wait(&self) -> Option<Millis>
§12d Network security fails closed, each tick. The journal’s holds
(Ledger::holds) are the source of truth after a restart; they are
reconciled with the host’s (held), and any disagreement keeps the
hold (fail closed).
Returns whether it applied a hold the observed state does not show.
What is left of this tick’s hold budget: every hold call on the tick
(apply, lift, the table check, a re-apply) waits
at most this, and none is made once it is spent (the caller takes it
as “cannot say”, the fail-closed side). So a stuck systemctl or
nft holds the tick up for HOLD_WAIT in all, not per call (reviewer,
#61). The budget is not counted from the tick’s
start: only the time the hold calls take is spent (hold_spent), so
probes the hold itself slows (their traffic is dropped) never spend it
(catalog 41644729493, vm-netsec; reviewer, 7c2edfc); and lifts are
made first (network_holds), so other units’ calls cannot keep a unit
that is back held (a livelock). A call skipped for want of budget is
not news: it is made next tick, and alarms nothing.
Sourcefn hold_spent(&mut self, t0: Timestamp)
fn hold_spent(&mut self, t0: Timestamp)
Spends what a hold call begun at t0 took from the tick’s budget.
Sourcepub fn compact_saving(&mut self) -> Result<Vec<Entry>, JournalError>
pub fn compact_saving(&mut self) -> Result<Vec<Entry>, JournalError>
Compact the journal and return the entries it discarded (the segment
it checkpointed), read in the same core call: no tick of this daemon
can journal between the two, so they are exactly what the checkpoint
replaced. The gym’s forced compaction saves them for the judge’s
full-history replay (replay_equivalent); reading the segment from
outside first left a gap a tick could journal into.
fn network_holds(&mut self, s: &SystemState, defs: &UnitDefs) -> bool
Sourcefn lift_back(&mut self, u: &UnitId) -> bool
fn lift_back(&mut self, u: &UnitId) -> bool
Lifts a back unit’s hold: journaled, then asked of the host. False when the tick has no budget left: nothing is done, and it is lifted on a later tick.
Sourcefn lift_host(&mut self, u: &UnitId)
fn lift_host(&mut self, u: &UnitId)
Asks the host to lift a hold already journaled as lifted. A lift the host has not confirmed is noticed once, then retried quietly.
Sourcefn hold_table(&mut self, holding: &BTreeSet<UnitId>, units: &[UnitId])
fn hold_table(&mut self, holding: &BTreeSet<UnitId>, units: &[UnitId])
§12d: the hold’s table, while a hold stands. Missing: alarm once, then
re-apply (a reload, which never lifts; HoldApplied journaled
first), and retry with backoff until a check finds it. Uncheckable:
alarm once and check again next tick; nothing is re-applied blind.
Sourcefn prepare_again(
&mut self,
list: Vec<(TxnId, Transition, Option<Timestamp>)>,
why: &str,
s: &SystemState,
defs: &UnitDefs,
)
fn prepare_again( &mut self, list: Vec<(TxnId, Transition, Option<Timestamp>)>, why: &str, s: &SystemState, defs: &UnitDefs, )
Prepare again transactions interrupted before they mutated (by a restart, or withdrawn for a repair rollback).
Sourcefn waiting_built(&mut self) -> Vec<(TxnId, Transition, Option<Timestamp>)>
fn waiting_built(&mut self) -> Vec<(TxnId, Transition, Option<Timestamp>)>
Generation transactions waiting in Built, with when each began
waiting: what a rollback about to run would withdraw (§12f, I6).
Sourcefn note_withdrawn(
&mut self,
before: Vec<(TxnId, Transition, Option<Timestamp>)>,
)
fn note_withdrawn( &mut self, before: Vec<(TxnId, Transition, Option<Timestamp>)>, )
§12f, I6 (owner decision, Nov 2): a rollback of any source withdraws
what waits in Built at the moment it is about to run (admitted, and
approved if it asked; exec::schedule). Those of before the
executor withdrew are remembered, with their proposal, caller and
parking start, to prepare again once the rollback is terminal.
Sourcefn respond(&self, r: &Submitted) -> Response
fn respond(&self, r: &Submitted) -> Response
The response to a submission; one parked for approval says, in one line, what it would change (§16 Approvals show the change).
Sourcefn approval_diff(
&self,
txn: TxnId,
t: &Transition,
f: &DerivedFacts,
) -> ApprovalDiff
fn approval_diff( &self, txn: TxnId, t: &Transition, f: &DerivedFacts, ) -> ApprovalDiff
§16 Approvals show the change: built from the derived facts (from the evaluated generations), never from the proposal.
Sourcefn evaluated_diff(&self, txn: TxnId) -> Option<ConfigDiff>
fn evaluated_diff(&self, txn: TxnId) -> Option<ConfigDiff>
Every option whose value differs between a live generation transaction’s base and its candidate, as both evaluate.
Sourcefn generation_active(&mut self) -> bool
fn generation_active(&mut self) -> bool
A generation transaction is live, in any state (I6: one waiting in
Built counts).
Sourcefn flush_writebacks(&mut self)
fn flush_writebacks(&mut self)
§12a (P7): submit the queued write-backs, unless a generation transaction is active: then they stay queued, which is not a failure and gives no notice. One refused as busy goes back on the queue.
Sourcefn lost_changes(
&self,
l: &Ledger,
) -> BTreeMap<UnitId, (ChangeId, BTreeMap<String, Value>)>
fn lost_changes( &self, l: &Ledger, ) -> BTreeMap<UnitId, (ChangeId, BTreeMap<String, Value>)>
§13 (P22): for each unit, the catalog change last committed for it, if the override file no longer carries what it set.
fn is_canonical(&self, u: &UnitId, defs: &UnitDefs) -> bool
fn canonical_healthy(&self, s: &SystemState, defs: &UnitDefs) -> bool
Sourcepub fn set_posture(&mut self, p: Posture)
pub fn set_posture(&mut self, p: Posture)
One tick of the loop.
Change the posture (the gym’s set_setting posture; on a machine the
generation declares it, §12d).
Sourcefn residue(&mut self, s: &SystemState, defs: &UnitDefs) -> bool
fn residue(&mut self, s: &SystemState, defs: &UnitDefs) -> bool
§11, the unattributed residue: a unit seen running at the last tick and
now ended by a termination signal (a kill, or a systemctl stop
Planarian did not issue), which systemd will not restart and which is
not Security-sensitive, is taken as intended under the Relaxed and
Standard postures: an inferred Override until the next boot, recorded
as an observation (it never passes through decide), with a notice
and an undo. Units that went down with it are linked to it. A
Security-sensitive unit’s stop is always a fault, and alarmed; crash
signals, exit statuses and OOM kills are faults. Owner decision Q5.
Returns whether it recorded anything.
Sourcefn note_declarations(
&mut self,
prev: Option<GenerationId>,
cur: GenerationId,
announce: bool,
)
fn note_declarations( &mut self, prev: Option<GenerationId>, cur: GenerationId, announce: bool, )
The services cur declares that prev (default: the boot entry
before it) did not, and where each came from: the transaction that
built cur (from the journal’s Prepared record: its caller and
transition, written to planarian/overrides.nix), or else a rebuild
outside Planarian (the generation’s creator and time, and the files
that define the service).
Sourcefn effective_manifest(&self) -> (Manifest, Vec<UnitId>)
fn effective_manifest(&self) -> (Manifest, Vec<UnitId>)
The generation’s manifest with the external document’s units joined (§9): a unit the generation declares stays the generation’s. Returns the units the document declared that the generation overrode.
Sourcepub fn origin_of(&self, unit: &UnitId) -> Option<String>
pub fn origin_of(&self, unit: &UnitId) -> Option<String>
Where a unit’s declaration came from, when not the generation (§9; future-work T5: an implant has a provenance trail).
Sourcepub fn health_report(&mut self) -> HealthReport
pub fn health_report(&mut self) -> HealthReport
The health report (§10 hook), with the profile the core computes.
Sourcepub fn accept_external(&mut self, doc: DesiredDoc, digest: Hash)
pub fn accept_external(&mut self, doc: DesiredDoc, digest: Hash)
A verified external document is now in force (or, with None, the
configuration dropped the source).
A verified external document accepted: journaled (its sequence and
digest, B-16) when newer than the last one the journal accepted, then
put in force.
pub fn set_external(&mut self, doc: Option<DesiredDoc>)
Sourcepub fn boot_report(&mut self) -> Option<String>
pub fn boot_report(&mut self) -> Option<String>
The boot report (§10), once per boot: units from outside the
generation. main runs it before signalling ready, so nothing that
waits for planarian-ready.target starts before it is clean; the first
tick runs it otherwise (the gym). The finding, if any.
pub fn tick(&mut self)
Sourcefn remind_restart(&mut self, l: &Ledger)
fn remind_restart(&mut self, l: &Ledger)
§12f: a transaction in AwaitingBoot has no time limit; the “restart
to finish” notice is repeated once a day until that restart.
Sourcefn note_unreachable(&mut self, s: &SystemState, defs: &UnitDefs, now: Timestamp)
fn note_unreachable(&mut self, s: &SystemState, defs: &UnitDefs, now: Timestamp)
§10: a probe that times out yields Unknown, never Failed, so an external dependency that stops answering (traffic dropped at a gateway) opens no incident and nothing local is touched. Still, say so once it has lasted, and again when it answers.
Sourcefn note_space(&mut self)
fn note_space(&mut self)
§12b: a collection that could not meet the space budget says so.
Sourcefn collect_if_over(&mut self, s: &SystemState, defs: &UnitDefs)
fn collect_if_over(&mut self, s: &SystemState, defs: &UnitDefs)
§12b: when the generations exceed a bound and something can be collected, collect (Runtime, daemon-initiated).
fn repair_one(&mut self, s: &SystemState, defs: &UnitDefs, l: &Ledger)
fn confirm_boot(&mut self, s: &SystemState, defs: &UnitDefs, now: Timestamp)
Sourcefn authz(&mut self, peer: &Peer) -> Authorization
fn authz(&mut self, peer: &Peer) -> Authorization
§10: Actor::User { uid, session, seat, active } from the caller’s
logind session; a remote session has no seat and is never local.
Sourcepub fn take_deferred(&mut self) -> Option<(PrebuildJob<B::Gens>, Resume)>
pub fn take_deferred(&mut self) -> Option<(PrebuildJob<B::Gens>, Resume)>
The slow part of the request just handled, if handle deferred it:
run the job anywhere, then pass its result to resume. Until then the
answer handle returned is a placeholder, not for the caller.
Sourcepub fn resume(&mut self, r: Resume, prebuilt: Prebuilt) -> Response
pub fn resume(&mut self, r: Resume, prebuilt: Prebuilt) -> Response
Finish a deferred request with its prebuilt candidate: plan, decide
and run it as handle would have, against a fresh observation.
fn user_submit( &mut self, t: Transition, peer: Peer, source: Source, reason: String, ) -> Response
fn status(&mut self) -> StatusReport
Sourcefn console(&mut self) -> ConsoleReport
fn console(&mut self) -> ConsoleReport
§16a: what the read-only console shows.