mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
rename appmgr
This commit is contained in:
committed by
Aiden McClelland
parent
9cf379f9ee
commit
edde478382
292
backend/src/install/cleanup.rs
Normal file
292
backend/src/install/cleanup.rs
Normal file
@@ -0,0 +1,292 @@
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
use bollard::image::ListImagesOptions;
|
||||
use color_eyre::eyre::eyre;
|
||||
use patch_db::{DbHandle, LockType, PatchDbHandle};
|
||||
use tracing::instrument;
|
||||
|
||||
use super::{PKG_ARCHIVE_DIR, PKG_DOCKER_DIR};
|
||||
use crate::context::RpcContext;
|
||||
use crate::db::model::{CurrentDependencyInfo, InstalledPackageDataEntry, PackageDataEntry};
|
||||
use crate::dependencies::reconfigure_dependents_with_live_pointers;
|
||||
use crate::error::ErrorCollection;
|
||||
use crate::s9pk::manifest::{Manifest, PackageId};
|
||||
use crate::util::{Apply, Version};
|
||||
use crate::Error;
|
||||
|
||||
#[instrument(skip(ctx, db, deps))]
|
||||
pub async fn update_dependency_errors_of_dependents<
|
||||
'a,
|
||||
Db: DbHandle,
|
||||
I: IntoIterator<Item = &'a PackageId>,
|
||||
>(
|
||||
ctx: &RpcContext,
|
||||
db: &mut Db,
|
||||
id: &PackageId,
|
||||
deps: I,
|
||||
) -> Result<(), Error> {
|
||||
for dep in deps {
|
||||
if let Some(man) = &*crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.idx_model(&dep)
|
||||
.and_then(|m| m.installed())
|
||||
.map::<_, Manifest>(|m| m.manifest())
|
||||
.get(db, true)
|
||||
.await?
|
||||
{
|
||||
if let Err(e) = if let Some(info) = man.dependencies.0.get(id) {
|
||||
info.satisfied(ctx, db, id, None, dep).await?
|
||||
} else {
|
||||
Ok(())
|
||||
} {
|
||||
let mut errs = crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.idx_model(&dep)
|
||||
.expect(db)
|
||||
.await?
|
||||
.installed()
|
||||
.expect(db)
|
||||
.await?
|
||||
.status()
|
||||
.dependency_errors()
|
||||
.get_mut(db)
|
||||
.await?;
|
||||
errs.0.insert(id.clone(), e);
|
||||
errs.save(db).await?;
|
||||
} else {
|
||||
let mut errs = crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.idx_model(&dep)
|
||||
.expect(db)
|
||||
.await?
|
||||
.installed()
|
||||
.expect(db)
|
||||
.await?
|
||||
.status()
|
||||
.dependency_errors()
|
||||
.get_mut(db)
|
||||
.await?;
|
||||
errs.0.remove(id);
|
||||
errs.save(db).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(ctx))]
|
||||
pub async fn cleanup(ctx: &RpcContext, id: &PackageId, version: &Version) -> Result<(), Error> {
|
||||
let mut errors = ErrorCollection::new();
|
||||
ctx.managers.remove(&(id.clone(), version.clone())).await;
|
||||
// docker images start9/$APP_ID/*:$VERSION -q | xargs docker rmi
|
||||
let images = ctx
|
||||
.docker
|
||||
.list_images(Some(ListImagesOptions {
|
||||
all: false,
|
||||
filters: {
|
||||
let mut f = HashMap::new();
|
||||
f.insert(
|
||||
"reference".to_owned(),
|
||||
vec![format!("start9/{}/*:{}", id, version)],
|
||||
);
|
||||
f
|
||||
},
|
||||
digests: false,
|
||||
}))
|
||||
.await
|
||||
.apply(|res| errors.handle(res));
|
||||
errors.extend(
|
||||
futures::future::join_all(images.into_iter().flatten().map(|image| async {
|
||||
let image = image; // move into future
|
||||
ctx.docker.remove_image(&image.id, None, None).await
|
||||
}))
|
||||
.await,
|
||||
);
|
||||
let pkg_archive_dir = ctx
|
||||
.datadir
|
||||
.join(PKG_ARCHIVE_DIR)
|
||||
.join(id)
|
||||
.join(version.as_str());
|
||||
if tokio::fs::metadata(&pkg_archive_dir).await.is_ok() {
|
||||
tokio::fs::remove_dir_all(&pkg_archive_dir)
|
||||
.await
|
||||
.apply(|res| errors.handle(res));
|
||||
}
|
||||
let docker_path = ctx
|
||||
.datadir
|
||||
.join(PKG_DOCKER_DIR)
|
||||
.join(id)
|
||||
.join(version.as_str());
|
||||
if tokio::fs::metadata(&docker_path).await.is_ok() {
|
||||
tokio::fs::remove_dir_all(&docker_path)
|
||||
.await
|
||||
.apply(|res| errors.handle(res));
|
||||
}
|
||||
|
||||
errors.into_result()
|
||||
}
|
||||
|
||||
#[instrument(skip(ctx, db))]
|
||||
pub async fn cleanup_failed<Db: DbHandle>(
|
||||
ctx: &RpcContext,
|
||||
db: &mut Db,
|
||||
id: &PackageId,
|
||||
) -> Result<(), Error> {
|
||||
crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.lock(db, LockType::Write)
|
||||
.await?;
|
||||
let pde = crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.idx_model(id)
|
||||
.expect(db)
|
||||
.await?
|
||||
.get(db, true)
|
||||
.await?
|
||||
.into_owned();
|
||||
if let Some(manifest) = match &pde {
|
||||
PackageDataEntry::Installing { manifest, .. }
|
||||
| PackageDataEntry::Restoring { manifest, .. } => Some(manifest),
|
||||
PackageDataEntry::Updating {
|
||||
manifest,
|
||||
installed:
|
||||
InstalledPackageDataEntry {
|
||||
manifest: installed_manifest,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
if &manifest.version != &installed_manifest.version {
|
||||
Some(manifest)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
tracing::warn!("{}: Nothing to clean up!", id);
|
||||
None
|
||||
}
|
||||
} {
|
||||
cleanup(ctx, id, &manifest.version).await?;
|
||||
}
|
||||
|
||||
match pde {
|
||||
PackageDataEntry::Installing { .. } | PackageDataEntry::Restoring { .. } => {
|
||||
crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.remove(db, id)
|
||||
.await?;
|
||||
}
|
||||
PackageDataEntry::Updating {
|
||||
installed,
|
||||
static_files,
|
||||
..
|
||||
} => {
|
||||
crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.idx_model(id)
|
||||
.put(
|
||||
db,
|
||||
&PackageDataEntry::Installed {
|
||||
manifest: installed.manifest.clone(),
|
||||
installed,
|
||||
static_files,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(db, current_dependencies))]
|
||||
pub async fn remove_from_current_dependents_lists<
|
||||
'a,
|
||||
Db: DbHandle,
|
||||
I: IntoIterator<Item = &'a PackageId>,
|
||||
>(
|
||||
db: &mut Db,
|
||||
id: &'a PackageId,
|
||||
current_dependencies: I,
|
||||
) -> Result<(), Error> {
|
||||
for dep in current_dependencies.into_iter().chain(std::iter::once(id)) {
|
||||
if let Some(current_dependents) = crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.idx_model(dep)
|
||||
.and_then(|m| m.installed())
|
||||
.map::<_, BTreeMap<PackageId, CurrentDependencyInfo>>(|m| m.current_dependents())
|
||||
.check(db)
|
||||
.await?
|
||||
{
|
||||
if current_dependents
|
||||
.clone()
|
||||
.idx_model(id)
|
||||
.exists(db, true)
|
||||
.await?
|
||||
{
|
||||
current_dependents.remove(db, id).await?
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(ctx, db))]
|
||||
pub async fn uninstall(
|
||||
ctx: &RpcContext,
|
||||
db: &mut PatchDbHandle,
|
||||
id: &PackageId,
|
||||
) -> Result<(), Error> {
|
||||
let mut tx = db.begin().await?;
|
||||
crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.lock(&mut tx, LockType::Write)
|
||||
.await?;
|
||||
let entry = crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.idx_model(id)
|
||||
.and_then(|pde| pde.removing())
|
||||
.get(&mut tx, true)
|
||||
.await?
|
||||
.into_owned()
|
||||
.ok_or_else(|| {
|
||||
Error::new(
|
||||
eyre!("Package not in removing state: {}", id),
|
||||
crate::ErrorKind::NotFound,
|
||||
)
|
||||
})?;
|
||||
cleanup(ctx, &entry.manifest.id, &entry.manifest.version).await?;
|
||||
|
||||
crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.remove(&mut tx, id)
|
||||
.await?;
|
||||
|
||||
// once we have removed the package entry, we can change all the dependent pointers to null
|
||||
reconfigure_dependents_with_live_pointers(ctx, &mut tx, &entry).await?;
|
||||
|
||||
remove_from_current_dependents_lists(
|
||||
&mut tx,
|
||||
&entry.manifest.id,
|
||||
entry.current_dependencies.keys(),
|
||||
)
|
||||
.await?;
|
||||
update_dependency_errors_of_dependents(
|
||||
ctx,
|
||||
&mut tx,
|
||||
&entry.manifest.id,
|
||||
entry.current_dependents.keys(),
|
||||
)
|
||||
.await?;
|
||||
let volumes = ctx
|
||||
.datadir
|
||||
.join(crate::volume::PKG_VOLUME_DIR)
|
||||
.join(&entry.manifest.id);
|
||||
if tokio::fs::metadata(&volumes).await.is_ok() {
|
||||
tokio::fs::remove_dir_all(&volumes).await?;
|
||||
}
|
||||
tx.commit(None).await?;
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user