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
|
|
@ -1,5 +1,5 @@
|
|||
//! Startup convergence. Three phases, all idempotent and unguarded:
|
||||
//! harness files, applied + proposed repos, the agent-set files, plus the
|
||||
//! harness files, the applied repos, the agent-set files, plus the
|
||||
//! removal of the legacy meta repo's leftovers. They re-run every
|
||||
//! boot on purpose — each one is a no-op once its state is already
|
||||
//! correct.
|
||||
|
|
@ -80,10 +80,10 @@ pub async fn run() -> Result<()> {
|
|||
Err(e) => tracing::warn!(error = ?e, "migration: removing the legacy meta .git failed"),
|
||||
}
|
||||
|
||||
// Phase 1 + 2: per-agent applied + proposed.
|
||||
tracing::debug!("migration: phase 1+2 (applied + proposed repos)");
|
||||
// An archetype agent has neither repo, and seeding one here would hand it
|
||||
// a config it is not built from.
|
||||
// Phase 1 + 2: per-agent applied repo.
|
||||
tracing::debug!("migration: phase 1+2 (applied repo)");
|
||||
// An archetype agent has no applied repo, and seeding one here would hand
|
||||
// it a config it is not built from.
|
||||
let archetypes = crate::archetypes::read_at(&crate::archetypes::path()).unwrap_or_else(|e| {
|
||||
tracing::warn!(error = ?e, "migration: stored archetypes unreadable; treating every agent as custom");
|
||||
crate::archetypes::Stored::new()
|
||||
|
|
@ -92,26 +92,10 @@ pub async fn run() -> Result<()> {
|
|||
if archetypes.contains_key(name.as_str()) {
|
||||
continue;
|
||||
}
|
||||
tracing::debug!(%name, "migration: applied+proposed");
|
||||
tracing::debug!(%name, "migration: applied");
|
||||
if let Err(e) = migrate_applied_repo(name.as_str()).await {
|
||||
tracing::warn!(%name, error = ?e, "migration: applied repo rewrite failed");
|
||||
}
|
||||
let proposed_dir = Coordinator::agent_proposed_dir(name);
|
||||
match remove_meta_remote(&proposed_dir).await {
|
||||
Ok(true) => tracing::info!(%name, "migration: removed the legacy meta remote"),
|
||||
Ok(false) => {}
|
||||
Err(e) => {
|
||||
tracing::warn!(%name, error = ?e, "migration: removing the meta remote failed");
|
||||
}
|
||||
}
|
||||
let proposed = lifecycle::setup_proposed(&proposed_dir, name.as_str());
|
||||
match tokio::time::timeout(GIT_TIMEOUT, proposed).await {
|
||||
Ok(Err(e)) => tracing::warn!(%name, error = ?e, "migration: setup_proposed failed"),
|
||||
Err(_) => {
|
||||
tracing::warn!(%name, timeout = ?GIT_TIMEOUT, "migration: setup_proposed timed out — skipping");
|
||||
}
|
||||
Ok(Ok(())) => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 3: the files that follow the agent set.
|
||||
|
|
@ -190,19 +174,6 @@ fn remove_core_token(state: &Path) -> Result<bool> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Remove the `meta` remote from the proposed repo at `dir`. `true` when it
|
||||
/// was there; a missing remote, or a `dir` that is no repo, is `false`.
|
||||
async fn remove_meta_remote(dir: &Path) -> Result<bool> {
|
||||
let mut cmd = lifecycle::git_command();
|
||||
cmd.current_dir(dir).args(["remote", "get-url", "meta"]);
|
||||
let probe = output_with_timeout(cmd, GIT_TIMEOUT, "git remote get-url meta").await?;
|
||||
if !probe.status.success() {
|
||||
return Ok(false);
|
||||
}
|
||||
raw_git(dir, &["remote", "remove", "meta"]).await?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
async fn enumerate_agents() -> Result<Vec<hive_types::Ident>> {
|
||||
let containers = lifecycle::list().await?;
|
||||
Ok(containers
|
||||
|
|
@ -329,35 +300,6 @@ mod tests {
|
|||
assert!(dir.path().join("topology.json").exists());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn meta_remote_goes_and_the_others_stay() {
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
raw_git(dir.path(), &["init", "-q", "--initial-branch=main"])
|
||||
.await
|
||||
.expect("init");
|
||||
for (name, url) in [
|
||||
("meta", "http://forge/core/meta.git"),
|
||||
("applied", "/applied/x/.git"),
|
||||
] {
|
||||
raw_git(dir.path(), &["remote", "add", name, url])
|
||||
.await
|
||||
.expect("add remote");
|
||||
}
|
||||
|
||||
assert!(remove_meta_remote(dir.path()).await.expect("first"));
|
||||
let remotes = lifecycle::git_command()
|
||||
.current_dir(dir.path())
|
||||
.arg("remote")
|
||||
.output()
|
||||
.await
|
||||
.expect("list");
|
||||
assert_eq!(String::from_utf8_lossy(&remotes.stdout).trim(), "applied");
|
||||
assert!(
|
||||
!remove_meta_remote(dir.path()).await.expect("second"),
|
||||
"no-op"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn core_token_goes_once_and_its_neighbours_stay() {
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
|
|
@ -370,12 +312,6 @@ mod tests {
|
|||
assert!(!remove_core_token(dir.path()).expect("second"), "no-op");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn a_dir_that_is_no_repo_has_no_meta_remote() {
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
assert!(!remove_meta_remote(dir.path()).await.expect("probe"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn unreadable_flake_is_left_untouched() {
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
|
|
|
|||
Loading…
Reference in a new issue