mint a live agent's missing store identity from the renewal pass, and log the step a mint stopped at
This commit is contained in:
parent
0ad1dad8b5
commit
8126e0fffa
1 changed files with 286 additions and 39 deletions
|
|
@ -24,10 +24,10 @@
|
|||
//! tests pin them; the IO on either side only reads or acts.
|
||||
//!
|
||||
//! **Only agents some hive is declared to run are renewed** ([`live_agents`]):
|
||||
//! the wanted-state declarations are where a destroy is recorded, and an agent
|
||||
//! declared nowhere, or only as `Destroyed`, is skipped. A credential that is
|
||||
//! not stored is skipped too — creating one is agent creation's job, and a
|
||||
//! destroy deletes it.
|
||||
//! a destroy is recorded in the wanted-state declarations, and an agent declared
|
||||
//! nowhere, or only as `Destroyed`, is skipped. A live agent with no stored
|
||||
//! certificate gets one minted, as a failed mint at creation is retried nowhere
|
||||
//! else, unless its mint is in flight. A missing queue secret stays missing.
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::sync::Arc;
|
||||
|
|
@ -141,7 +141,8 @@ pub enum Observed {
|
|||
Unstamped,
|
||||
/// Stored and not yet due.
|
||||
Current,
|
||||
/// Nothing stored. Never renewed: see the module doc.
|
||||
/// Nothing stored. A certificate is minted for a live agent; a queue secret
|
||||
/// is left alone (see the module doc).
|
||||
Absent,
|
||||
/// The read or the decode failed. Nothing is known, so nothing is done.
|
||||
Unknown,
|
||||
|
|
@ -163,14 +164,14 @@ pub struct Renewal {
|
|||
}
|
||||
|
||||
/// The renewals a pass queues: one per agent with a certificate that is
|
||||
/// [`Observed::Due`], or a queue secret that is [`Observed::Due`] or
|
||||
/// [`Observed::Unstamped`].
|
||||
/// [`Observed::Due`] or [`Observed::Absent`], or a queue secret that is
|
||||
/// [`Observed::Due`] or [`Observed::Unstamped`].
|
||||
pub fn plan(observed: &[(String, AgentObserved)]) -> Vec<Renewal> {
|
||||
observed
|
||||
.iter()
|
||||
.map(|(agent, o)| Renewal {
|
||||
agent: agent.clone(),
|
||||
cert: matches!(o.cert, Observed::Due(_)),
|
||||
cert: matches!(o.cert, Observed::Due(_) | Observed::Absent),
|
||||
secret: matches!(o.secret, Observed::Due(_) | Observed::Unstamped),
|
||||
})
|
||||
.filter(|r| r.cert || r.secret)
|
||||
|
|
@ -319,6 +320,12 @@ async fn observe_all(
|
|||
if let Observed::Due(age) = o.cert {
|
||||
tracing::info!(agent, age = %Age(age), "agent certificate past half its life; re-issuing");
|
||||
}
|
||||
if o.cert == Observed::Absent {
|
||||
tracing::info!(
|
||||
agent,
|
||||
"agent has no stored certificate; minting its store identity"
|
||||
);
|
||||
}
|
||||
if let Observed::Due(age) = o.secret {
|
||||
tracing::info!(agent, age = %Age(age), "agent queue credential due; re-minting");
|
||||
}
|
||||
|
|
@ -525,16 +532,19 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn only_due_credentials_are_planned() {
|
||||
fn due_and_missing_certificates_and_due_secrets_are_planned() {
|
||||
use Observed::{Absent, Current, Due, Unknown, Unstamped};
|
||||
let o = |cert, secret| AgentObserved { cert, secret };
|
||||
let observed = [
|
||||
("both".to_owned(), o(Due(46 * DAY), Due(45 * DAY))),
|
||||
("cert".to_owned(), o(Due(46 * DAY), Current)),
|
||||
("secret".to_owned(), o(Absent, Due(45 * DAY))),
|
||||
("secret".to_owned(), o(Current, Due(45 * DAY))),
|
||||
("unstamped".to_owned(), o(Current, Unstamped)),
|
||||
("neither".to_owned(), o(Current, Absent)),
|
||||
("unknown".to_owned(), o(Unknown, Unknown)),
|
||||
("no identity".to_owned(), o(Absent, Absent)),
|
||||
("no cert, old secret".to_owned(), o(Absent, Due(45 * DAY))),
|
||||
("unreadable cert".to_owned(), o(Unknown, Absent)),
|
||||
];
|
||||
let r = |agent: &str, cert, secret| Renewal {
|
||||
agent: agent.to_owned(),
|
||||
|
|
@ -548,6 +558,40 @@ mod tests {
|
|||
r("cert", true, false),
|
||||
r("secret", false, true),
|
||||
r("unstamped", false, true),
|
||||
r("no identity", true, false),
|
||||
r("no cert, old secret", true, true),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// A pass over declarations: the agent with no stored identity is minted
|
||||
/// for when it is live and not when it is destroyed. The destroyed agent is
|
||||
/// never observed, which is what [`live_agents`] does before the store is
|
||||
/// read.
|
||||
#[test]
|
||||
fn a_missing_identity_is_minted_for_a_live_agent_and_not_a_destroyed_one() {
|
||||
let declarations = [declared(&[
|
||||
("sock", AgentState::Up),
|
||||
("paused", AgentState::Paused),
|
||||
("gone", AgentState::Destroyed),
|
||||
])];
|
||||
let nothing_stored = AgentObserved {
|
||||
cert: Observed::Absent,
|
||||
secret: Observed::Absent,
|
||||
};
|
||||
let observed: Vec<_> = live_agents(&declarations)
|
||||
.into_iter()
|
||||
.map(|agent| (agent, nothing_stored))
|
||||
.collect();
|
||||
let planned: Vec<_> = plan(&observed)
|
||||
.into_iter()
|
||||
.map(|r| (r.agent, r.cert, r.secret))
|
||||
.collect();
|
||||
assert_eq!(
|
||||
planned,
|
||||
[
|
||||
("paused".to_owned(), true, false),
|
||||
("sock".to_owned(), true, false)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue