WP-11: package and OS updates from the UI
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
CI / ui (push) Has been cancelled

package_upgrade job streams apt-get output into the job log (streaming
CommandRunner, DebianUpdater with dist-upgrade or --only-upgrade), refreshes
the inventory afterwards and flags reboot-required. POST /api/system/upgrade
(admin), package name validation, selectable package table with confirm
dialog and live log on the Updates page. Fake updater for dev.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Dennis Nemec
2026-09-02 22:27:28 +02:00
parent 1f56f015a2
commit 684695e71a
9 changed files with 277 additions and 33 deletions

View File

@ -19,9 +19,36 @@ impl DebianUpdater {
#[async_trait]
impl HostUpdater for DebianUpdater {
async fn upgrade(&self, _packages: &[String], _out: &dyn LineSink) -> Result<(), DomainError> {
let _ = &self.runner;
todo!()
async fn upgrade(&self, packages: &[String], out: &dyn LineSink) -> Result<(), DomainError> {
out.line("$ apt-get update");
if !self
.runner
.run_streaming("apt-get", &["update", "-q"], out)
.await?
{
out.line("warning: apt-get update failed, continuing with the current package index");
}
let mut args: Vec<&str> = vec![
"-y",
"-q",
"-o",
"Dpkg::Options::=--force-confdef",
"-o",
"Dpkg::Options::=--force-confold",
];
if packages.is_empty() {
args.push("dist-upgrade");
} else {
args.extend(["install", "--only-upgrade"]);
args.extend(packages.iter().map(String::as_str));
}
out.line(&format!("$ apt-get {}", args.join(" ")));
if !self.runner.run_streaming("apt-get", &args, out).await? {
return Err(DomainError::Unavailable(
"apt-get exited with a non-zero status".into(),
));
}
Ok(())
}
}