diff --git a/src/api/manifests.rs b/src/api/manifests.rs index e15e8aa..b4f337e 100644 --- a/src/api/manifests.rs +++ b/src/api/manifests.rs @@ -132,13 +132,27 @@ pub async fn delete_manifest(path: web::Path<(String, String)>, req: HttpRequest let _authorization = headers.get("Authorization").unwrap(); // TODO: let database = &state.database; + let digest = match Digest::is_digest(&reference) { + true => { + // Check if the manifest exists + if database.get_manifest(&name, &reference).await.unwrap().is_none() { + return HttpResponse::NotFound() + .finish(); + } - // If `reference` is a digest, then we're deleting a manifest, else a tag - if Digest::is_digest(&reference) { - database.delete_manifest(&name, &reference).await.unwrap(); - } else { - database.delete_tag(&name, &reference).await.unwrap(); - } + reference.clone() + }, + false => { + if let Some(tag) = database.get_tag(&name, &reference).await.unwrap() { + tag.manifest_digest + } else { + return HttpResponse::NotFound() + .finish(); + } + } + }; + + database.delete_manifest(&name, &digest).await.unwrap(); HttpResponse::Accepted() .append_header(("Content-Length", "None")) diff --git a/src/database/mod.rs b/src/database/mod.rs index cdd06e2..71c5f04 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -27,7 +27,7 @@ pub trait Database { /// Replace the uuid with a digest async fn replace_digest(&self, uuid: &str, new_digest: &str) -> sqlx::Result<()>; async fn link_manifest_layer(&self, manifest_digest: &str, layer_digest: &str) -> sqlx::Result<()>; - async fn unlink_manifest_layer(&self, repository: &str, layer_digest: &str) -> sqlx::Result<()>; + async fn unlink_manifest_layer(&self, manifest_digest: &str, layer_digest: &str) -> sqlx::Result<()>; // Tag related functions @@ -147,13 +147,13 @@ impl Database for Pool { Ok(()) } - async fn unlink_manifest_layer(&self, repository: &str, layer_digest: &str) -> sqlx::Result<()> { - sqlx::query("DELETE FROM manifest_layers WHERE layer_digest = ? AND manifest IN (SELECT digest FROM image_manifests WHERE repository = ?) RETURNING manifest, layer_digest") + async fn unlink_manifest_layer(&self, manifest_digest: &str, layer_digest: &str) -> sqlx::Result<()> { + sqlx::query("DELETE FROM manifest_layers WHERE manifest = ? AND layer_digest = ?") + .bind(manifest_digest) .bind(layer_digest) - .bind(repository) .execute(self).await?; - debug!("Removed link of layer {} from manifest in {} repository", layer_digest, repository); + debug!("Removed link between manifest {} and layer {}", manifest_digest, layer_digest); Ok(()) } @@ -275,6 +275,28 @@ impl Database for Pool { .bind(repository) .execute(self).await?; + debug!("Deleted manifest {} in repository {}", digest, repository); + + let rows: Vec<(String, )> = sqlx::query_as("DELETE FROM manifest_layers WHERE manifest = ? RETURNING layer_digest") + .bind(digest) + .fetch_all(self).await?; + + debug!("Unlinked manifest {} from all linked layers", digest); + + for row in rows.into_iter() { + let layer_digest = row.0; + + self.delete_digest(&layer_digest).await?; + } + + debug!("Deleted all digests for manifest {}", digest); + + sqlx::query("DELETE FROM image_tags where image_manifest = ?") + .bind(digest) + .execute(self).await?; + + debug!("Deleted all image tags for manifest {}", digest); + Ok(()) } diff --git a/src/main.rs b/src/main.rs index 62b343d..49ade06 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,7 +55,7 @@ async fn main() -> std::io::Result<()> { .service(api::manifests::upload_manifest) .service(api::manifests::pull_manifest) .service(api::manifests::manifest_exists) - .service(api::manifests::delete_manifest) + .service(api::manifests::delete_manifest) // delete image ) .service( web::scope("/blobs")