more complete admin API #298

Merged
lx merged 48 commits from admin-api into main 2022-05-24 10:16:40 +00:00
4 changed files with 66 additions and 1 deletions
Showing only changes of commit fe399a3265 - Show all commits

View file

@ -1,7 +1,7 @@
.PHONY: doc all release shell
all:
clear; cargo build --features k2v
clear; cargo build --all-features
doc:
cd doc/book; mdbook build

View file

@ -454,3 +454,5 @@ or no alias at all.
### DeleteBucket `DELETE /bucket?id=<bucket id>`
Deletes a storage bucket. A bucket cannot be deleted if it is not empty.
Warning: this will delete all aliases associated with the bucket!

View file

@ -146,6 +146,7 @@ impl ApiHandler for AdminApiServer {
handle_get_bucket_info(&self.garage, id, global_alias).await
}
Endpoint::CreateBucket => handle_create_bucket(&self.garage, req).await,
Endpoint::DeleteBucket { id } => handle_delete_bucket(&self.garage, id).await,
_ => Err(Error::NotImplemented(format!(
"Admin endpoint {} not implemented yet",
endpoint.name()

View file

@ -4,6 +4,7 @@ use std::sync::Arc;
use hyper::{Body, Request, Response, StatusCode};
use serde::{Deserialize, Serialize};
use garage_util::crdt::*;
use garage_util::data::*;
use garage_util::error::Error as GarageError;
@ -13,6 +14,7 @@ use garage_model::bucket_alias_table::*;
use garage_model::bucket_table::*;
use garage_model::garage::Garage;
use garage_model::permission::*;
use garage_model::s3::object_table::ObjectFilter;
use crate::admin::key::KeyBucketPermResult;
use crate::error::*;
@ -306,3 +308,63 @@ struct CreateBucketLocalAlias {
#[serde(rename = "allPermissions", default)]
all_permissions: bool,
}
pub async fn handle_delete_bucket(
garage: &Arc<Garage>,
id: String,
) -> Result<Response<Body>, Error> {
let helper = garage.bucket_helper();
let id_hex = hex::decode(&id).ok_or_bad_request("Invalid bucket id")?;
let bucket_id = Uuid::try_from(&id_hex).ok_or_bad_request("Invalid bucket id")?;
let mut bucket = helper.get_existing_bucket(bucket_id).await?;
let state = bucket.state.as_option().unwrap();
// Check bucket is empty
let objects = garage
.object_table
.get_range(
&bucket_id,
None,
Some(ObjectFilter::IsData),
10,
EnumerationOrder::Forward,
)
.await?;
if !objects.is_empty() {
return Err(Error::BadRequest("Bucket is not empty".into()));
}
// --- done checking, now commit ---
// 1. delete authorization from keys that had access
for (key_id, perm) in bucket.authorized_keys() {
if perm.is_any() {
helper
.set_bucket_key_permissions(bucket.id, key_id, BucketKeyPerm::NO_PERMISSIONS)
.await?;
}
}
// 2. delete all local aliases
for ((key_id, alias), _, active) in state.local_aliases.items().iter() {
if *active {
helper
.unset_local_bucket_alias(bucket.id, &key_id, &alias)
.await?;
}
}
// 3. delete all global aliases
for (alias, _, active) in state.aliases.items().iter() {
if *active {
helper.purge_global_bucket_alias(bucket.id, &alias).await?;
}
}
// 4. delete bucket
bucket.state = Deletable::delete();
garage.bucket_table.insert(&bucket).await?;
Ok(Response::builder()
.status(StatusCode::NO_CONTENT)
.body(Body::empty())?)
}