Skip to main content

Core

Struct Core 

Source
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: u64

How 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: u64

Slow 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: Manifest

The 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: bool

The 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: bool

The 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: bool

Quiet 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: Timestamp

When to next check the §12b collection bounds.

§space_noted: Timestamp

The space report last noticed.

§awaiting_post: Vec<LogRecord>

Executor log records waiting for their post-state (I7).

§defer: bool

Set 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: Hash

The 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>

Source

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.

Source

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.

Source

pub fn last_observation(&self) -> Option<&(SystemState, UnitDefs)>

The observation the last tick (or request) acted on.

Source

pub fn notice(&mut self, s: String)

Source

fn say(&mut self, s: String)

Source

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.

Source

fn journal(&mut self, r: Record)

Source

pub fn ledger(&mut self) -> Ledger

Source

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.

Source

pub fn core_hash(&self) -> Hash

The core hash the observed state carries (P19).

Source

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

Source

fn context(&self, l: &Ledger, current: GenerationId) -> Context

Source

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.

Source

pub fn pending_recovery(&self) -> Option<String>

What finish_recovery will do, for “busy with …”; None if nothing.

Source

pub fn finish_recovery(&mut self)

After ready: run the recoveries start left (CoreConfig::defer_recovery).

Source

pub fn observe(&mut self) -> (SystemState, UnitDefs)

Observe without acting (also used to answer requests).

Source

fn proposal( &self, t: Transition, s: &SystemState, defs: &UnitDefs, source: Source, reason: String, ) -> Proposal

Source

fn submit( &mut self, p: Proposal, authz: Authorization, s: &SystemState, defs: &UnitDefs, ) -> Submitted

Source

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.

Source

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.

Source

fn hold_spent(&mut self, t0: Timestamp)

Spends what a hold call begun at t0 took from the tick’s budget.

Source

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.

Source

fn network_holds(&mut self, s: &SystemState, defs: &UnitDefs) -> bool

Source

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.

Source

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.

Source

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.

Source

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

Source

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

Source

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.

Source

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

Source

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.

Source

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.

Source

fn generation_active(&mut self) -> bool

A generation transaction is live, in any state (I6: one waiting in Built counts).

Source

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.

Source

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.

Source

fn is_canonical(&self, u: &UnitId, defs: &UnitDefs) -> bool

Source

fn canonical_healthy(&self, s: &SystemState, defs: &UnitDefs) -> bool

Source

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

Source

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.

Source

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

Source

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.

Source

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

Source

pub fn health_report(&mut self) -> HealthReport

The health report (§10 hook), with the profile the core computes.

Source

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.

Source

pub fn set_external(&mut self, doc: Option<DesiredDoc>)

Source

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.

Source

pub fn tick(&mut self)

Source

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.

Source

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.

Source

fn note_space(&mut self)

§12b: a collection that could not meet the space budget says so.

Source

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

Source

fn repair_one(&mut self, s: &SystemState, defs: &UnitDefs, l: &Ledger)

Source

fn confirm_boot(&mut self, s: &SystemState, defs: &UnitDefs, now: Timestamp)

Source

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.

Source

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.

Source

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.

Source

fn user_submit( &mut self, t: Transition, peer: Peer, source: Source, reason: String, ) -> Response

Source

fn status(&mut self) -> StatusReport

Source

fn console(&mut self) -> ConsoleReport

§16a: what the read-only console shows.

Source

fn intent_index(&self, defs: &UnitDefs) -> Index

Source

pub fn handle(&mut self, peer: Peer, req: Request) -> Response

Source

fn handle_as(&mut self, peer: Peer, req: Request) -> Response

Auto Trait Implementations§

§

impl<B, S> Freeze for Core<B, S>
where B: Freeze, S: Freeze, <B as Backends>::Gens: Freeze,

§

impl<B, S> !RefUnwindSafe for Core<B, S>

§

impl<B, S> Send for Core<B, S>
where B: Send, S: Send,

§

impl<B, S> Sync for Core<B, S>
where B: Sync, S: Sync, <B as Backends>::Gens: Sync,

§

impl<B, S> Unpin for Core<B, S>
where B: Unpin, S: Unpin, <B as Backends>::Gens: Unpin,

§

impl<B, S> UnsafeUnpin for Core<B, S>

§

impl<B, S> !UnwindSafe for Core<B, S>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.