drop the proposed config repo: applied seeds from forge main, and the dead pending-init topology list goes with it
This commit is contained in:
parent
08b8eb3f73
commit
25295fd33f
1 changed files with 225 additions and 520 deletions
|
|
@ -102,19 +102,14 @@ pub fn all_agents_in(topo: &BTreeSet<String>) -> Vec<String> {
|
|||
/// caller. The write is atomic, as a sorted array (`BTreeSet` iterates in
|
||||
/// key order) to keep git diffs minimal.
|
||||
///
|
||||
/// `pending` lists agents that have a provisioned proposed config repo
|
||||
/// but no container yet (provisioned, not yet spawned). They are KEPT
|
||||
/// (not dropped) so an agent that exists on disk but has never booted is
|
||||
/// still a name the hive knows about.
|
||||
///
|
||||
/// Fails without writing when the existing file can't be read or parsed:
|
||||
/// rebuilding it from the live set alone would drop every pending name.
|
||||
pub fn reconcile(agent_names: &[String], pending: &[String]) -> std::io::Result<bool> {
|
||||
reconcile_at(&topology_path(), agent_names, pending)
|
||||
/// rebuilding it from the live set alone would silently rewrite it.
|
||||
pub fn reconcile(agent_names: &[String]) -> std::io::Result<bool> {
|
||||
reconcile_at(&topology_path(), agent_names)
|
||||
}
|
||||
|
||||
fn reconcile_at(path: &Path, agent_names: &[String], pending: &[String]) -> std::io::Result<bool> {
|
||||
let (next, changed) = apply_reconcile(&read_from(path)?, agent_names, pending);
|
||||
fn reconcile_at(path: &Path, agent_names: &[String]) -> std::io::Result<bool> {
|
||||
let (next, changed) = apply_reconcile(&read_from(path)?, agent_names);
|
||||
if changed {
|
||||
super::write_map(path, &next)?;
|
||||
}
|
||||
|
|
@ -122,13 +117,12 @@ fn reconcile_at(path: &Path, agent_names: &[String], pending: &[String]) -> std:
|
|||
}
|
||||
|
||||
/// Pure form of [`reconcile`] for unit tests. Adds missing live agents,
|
||||
/// drops entries for agents that are neither live nor pending-init, and
|
||||
/// reports whether anything changed.
|
||||
/// drops entries for agents that are not live, and reports whether anything
|
||||
/// changed.
|
||||
#[must_use]
|
||||
pub fn apply_reconcile(
|
||||
current: &BTreeSet<String>,
|
||||
agent_names: &[String],
|
||||
pending: &[String],
|
||||
) -> (BTreeSet<String>, bool) {
|
||||
let mut next = current.clone();
|
||||
let mut changed = false;
|
||||
|
|
@ -137,8 +131,7 @@ pub fn apply_reconcile(
|
|||
changed = true;
|
||||
}
|
||||
}
|
||||
let known: std::collections::HashSet<&String> =
|
||||
agent_names.iter().chain(pending.iter()).collect();
|
||||
let known: std::collections::HashSet<&String> = agent_names.iter().collect();
|
||||
next.retain(|name| {
|
||||
let keep = known.contains(name);
|
||||
if !keep {
|
||||
|
|
@ -166,7 +159,7 @@ mod tests {
|
|||
#[test]
|
||||
fn apply_reconcile_adds_missing_live_agent() {
|
||||
let live = vec!["alice".to_owned(), "newbie".to_owned()];
|
||||
let (next, changed) = apply_reconcile(&BTreeSet::new(), &live, &[]);
|
||||
let (next, changed) = apply_reconcile(&BTreeSet::new(), &live);
|
||||
assert!(changed);
|
||||
assert!(next.contains("newbie"));
|
||||
assert!(next.contains("alice"));
|
||||
|
|
@ -175,30 +168,17 @@ mod tests {
|
|||
#[test]
|
||||
fn apply_reconcile_drops_vanished_agent() {
|
||||
let live = vec!["alice".to_owned()];
|
||||
let (next, changed) = apply_reconcile(&roster_three(), &live, &[]);
|
||||
let (next, changed) = apply_reconcile(&roster_three(), &live);
|
||||
assert!(changed);
|
||||
assert!(!next.contains("bob"));
|
||||
assert!(!next.contains("carol"));
|
||||
assert!(next.contains("alice"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_reconcile_keeps_pending_init_agent() {
|
||||
// `dora` was provisioned but has no container yet, so it's absent
|
||||
// from the live set. It must NOT be dropped.
|
||||
let mut roster = roster_three();
|
||||
roster.insert("dora".to_owned());
|
||||
let live = vec!["alice".to_owned(), "bob".to_owned(), "carol".to_owned()];
|
||||
let pending = vec!["dora".to_owned()];
|
||||
let (next, changed) = apply_reconcile(&roster, &live, &pending);
|
||||
assert!(!changed, "no change expected: {next:?}");
|
||||
assert!(next.contains("dora"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_reconcile_is_a_noop_when_already_in_sync() {
|
||||
let live = vec!["alice".to_owned(), "bob".to_owned(), "carol".to_owned()];
|
||||
let (next, changed) = apply_reconcile(&roster_three(), &live, &[]);
|
||||
let (next, changed) = apply_reconcile(&roster_three(), &live);
|
||||
assert!(!changed);
|
||||
assert_eq!(next, roster_three());
|
||||
}
|
||||
|
|
@ -255,8 +235,7 @@ mod tests {
|
|||
fn reconcile_leaves_a_corrupt_file_untouched() {
|
||||
let (_dir, path) = corrupt_file();
|
||||
let live = vec!["alice".to_owned(), "bob".to_owned()];
|
||||
let err =
|
||||
reconcile_at(&path, &live, &[]).expect_err("a corrupt file must not be rewritten");
|
||||
let err = reconcile_at(&path, &live).expect_err("a corrupt file must not be rewritten");
|
||||
assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
|
||||
assert_eq!(std::fs::read(&path).expect("read"), TRUNCATED.as_bytes());
|
||||
}
|
||||
|
|
@ -273,7 +252,7 @@ mod tests {
|
|||
let path = dir.path().join(TOPOLOGY_FILE);
|
||||
assert!(read_from(&path).expect("missing file").is_empty());
|
||||
let live = vec!["alice".to_owned(), "bob".to_owned(), "carol".to_owned()];
|
||||
assert!(reconcile_at(&path, &live, &[]).expect("reconcile"));
|
||||
assert!(reconcile_at(&path, &live).expect("reconcile"));
|
||||
assert_eq!(read_from(&path).expect("read"), roster_three());
|
||||
let entries: Vec<_> = std::fs::read_dir(dir.path())
|
||||
.expect("read_dir")
|
||||
|
|
|
|||
Loading…
Reference in a new issue