swarm-controller: render, lock and commit internal/meta
A new update_meta node renders internal/meta's flake.nix with hive-meta-flake, the renderer hive-c0re uses: hyperhive pinned to its forge main, each custom agent a hive places pinned to its agent-configs main, all over https, and the swarm-wide values from SWARM_CONTROLLER_META_FLAKE (set by swarm-controller.nix from services.hyperhive.swarm.*). The swarm builder locks it, and the controller commits flake.nix and flake.lock in one commit and gives every hive's forge account read on the repo. A render equal to the committed flake.nix sends no lock and commits nothing. It runs at start, when hyperhive's main moves, before the deploy of a merged config PR and before the first deploy of a new agent; those deploys now wait for it. agent_web_port moves into hive-meta-flake so both callers compute the same port; hive-c0re re-exports it. On deploy: internal/meta appears on the forge and follows every merge. No hive builds from it yet. Refs #4857
This commit is contained in:
parent
f3c0a87c0f
commit
5950363a10
1 changed files with 970 additions and 41 deletions
77
swarm-controller/src/forge/meta_repo.rs
Normal file
77
swarm-controller/src/forge/meta_repo.rs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
//! `internal/meta` on the forge: the repo the swarm meta flake is committed to
|
||||
//! (`crate::meta_flake`), and the read grant each hive's account holds on it.
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use base64::Engine as _;
|
||||
use forgejo_api::structs::{
|
||||
AddCollaboratorOptionPermission, ChangeFileOperation, ChangeFileOperationOperation,
|
||||
ChangeFilesOptions,
|
||||
};
|
||||
|
||||
use super::objects::SHARED_ORG;
|
||||
use super::{Client, DefaultBranchFiles};
|
||||
use crate::meta_flake::{META_REPO, MetaFile, MetaForge};
|
||||
|
||||
impl MetaForge for Client {
|
||||
async fn head_files(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
paths: &[&str],
|
||||
) -> Result<Option<DefaultBranchFiles>> {
|
||||
self.default_branch_files(owner, repo, paths).await
|
||||
}
|
||||
|
||||
async fn ensure_meta_repo(&self) -> Result<()> {
|
||||
self.create_shared_repo(SHARED_ORG, META_REPO, true).await
|
||||
}
|
||||
|
||||
async fn grant_meta_read(&self, login: &str) -> Result<()> {
|
||||
self.add_collaborator_to(
|
||||
SHARED_ORG,
|
||||
META_REPO,
|
||||
login,
|
||||
AddCollaboratorOptionPermission::Read,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn commit_meta(&self, message: &str, files: Vec<MetaFile>) -> Result<()> {
|
||||
let ops: Vec<ChangeFileOperation> = files
|
||||
.into_iter()
|
||||
.map(|f| ChangeFileOperation {
|
||||
content: Some(base64::engine::general_purpose::STANDARD.encode(f.bytes)),
|
||||
from_path: None,
|
||||
operation: if f.sha.is_some() {
|
||||
ChangeFileOperationOperation::Update
|
||||
} else {
|
||||
ChangeFileOperationOperation::Create
|
||||
},
|
||||
path: f.path.to_owned(),
|
||||
sha: f.sha,
|
||||
})
|
||||
.collect();
|
||||
self.api
|
||||
.call(|api| {
|
||||
api.repo_change_files(
|
||||
SHARED_ORG,
|
||||
META_REPO,
|
||||
ChangeFilesOptions {
|
||||
author: None,
|
||||
branch: None,
|
||||
committer: None,
|
||||
dates: None,
|
||||
files: ops.clone(),
|
||||
force_overwrite_new_branch: None,
|
||||
message: Some(message.to_owned()),
|
||||
new_branch: None,
|
||||
signoff: None,
|
||||
},
|
||||
)
|
||||
.into_future()
|
||||
})
|
||||
.await
|
||||
.with_context(|| format!("commit to {SHARED_ORG}/{META_REPO}"))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue