Merge pull request 'CLI: allow manipulating buckets by prefixes of their full IDs' (#783) from bucket-id-prefix into main

Reviewed-on: Deuxfleurs/garage#783
This commit is contained in:
Alex 2024-03-19 16:17:16 +00:00
commit 26310f3242
2 changed files with 59 additions and 24 deletions

View file

@ -54,9 +54,8 @@ impl AdminRpcHandler {
let bucket_id = self
.garage
.bucket_helper()
.resolve_global_bucket_name(&query.name)
.await?
.ok_or_bad_request("Bucket not found")?;
.admin_get_existing_matching_bucket(&query.name)
.await?;
let bucket = self
.garage
@ -157,9 +156,8 @@ impl AdminRpcHandler {
let bucket_id = helper
.bucket()
.resolve_global_bucket_name(&query.name)
.await?
.ok_or_bad_request("Bucket not found")?;
.admin_get_existing_matching_bucket(&query.name)
.await?;
// Get the alias, but keep in minde here the bucket name
// given in parameter can also be directly the bucket's ID.
@ -235,9 +233,8 @@ impl AdminRpcHandler {
let bucket_id = helper
.bucket()
.resolve_global_bucket_name(&query.existing_bucket)
.await?
.ok_or_bad_request("Bucket not found")?;
.admin_get_existing_matching_bucket(&query.existing_bucket)
.await?;
if let Some(key_pattern) = &query.local {
let key = helper.key().get_existing_matching_key(key_pattern).await?;
@ -307,9 +304,8 @@ impl AdminRpcHandler {
let bucket_id = helper
.bucket()
.resolve_global_bucket_name(&query.bucket)
.await?
.ok_or_bad_request("Bucket not found")?;
.admin_get_existing_matching_bucket(&query.bucket)
.await?;
let key = helper
.key()
.get_existing_matching_key(&query.key_pattern)
@ -343,9 +339,8 @@ impl AdminRpcHandler {
let bucket_id = helper
.bucket()
.resolve_global_bucket_name(&query.bucket)
.await?
.ok_or_bad_request("Bucket not found")?;
.admin_get_existing_matching_bucket(&query.bucket)
.await?;
let key = helper
.key()
.get_existing_matching_key(&query.key_pattern)
@ -378,9 +373,8 @@ impl AdminRpcHandler {
let bucket_id = self
.garage
.bucket_helper()
.resolve_global_bucket_name(&query.bucket)
.await?
.ok_or_bad_request("Bucket not found")?;
.admin_get_existing_matching_bucket(&query.bucket)
.await?;
let mut bucket = self
.garage
@ -420,9 +414,8 @@ impl AdminRpcHandler {
let bucket_id = self
.garage
.bucket_helper()
.resolve_global_bucket_name(&query.bucket)
.await?
.ok_or_bad_request("Bucket not found")?;
.admin_get_existing_matching_bucket(&query.bucket)
.await?;
let mut bucket = self
.garage
@ -479,9 +472,8 @@ impl AdminRpcHandler {
bucket_ids.push(
self.garage
.bucket_helper()
.resolve_global_bucket_name(b)
.await?
.ok_or_bad_request(format!("Bucket not found: {}", b))?,
.admin_get_existing_matching_bucket(b)
.await?,
);
}

View file

@ -67,6 +67,49 @@ impl<'a> BucketHelper<'a> {
}
}
/// Find a bucket by its global alias or a prefix of its uuid
pub async fn admin_get_existing_matching_bucket(
&self,
pattern: &String,
) -> Result<Uuid, Error> {
if let Some(uuid) = self.resolve_global_bucket_name(pattern).await? {
return Ok(uuid);
} else if pattern.len() >= 2 {
let hexdec = pattern
.get(..pattern.len() & !1)
.and_then(|x| hex::decode(x).ok());
if let Some(hex) = hexdec {
let mut start = [0u8; 32];
start
.as_mut_slice()
.get_mut(..hex.len())
.ok_or_bad_request("invalid length")?
.copy_from_slice(&hex);
let mut candidates = self
.0
.bucket_table
.get_range(
&EmptyKey,
Some(start.into()),
Some(DeletedFilter::NotDeleted),
10,
EnumerationOrder::Forward,
)
.await?
.into_iter()
.collect::<Vec<_>>();
candidates.retain(|x| hex::encode(x.id).starts_with(pattern));
if candidates.len() == 1 {
return Ok(candidates.into_iter().next().unwrap().id);
}
}
}
Err(Error::BadRequest(format!(
"Bucket not found / several matching buckets: {}",
pattern
)))
}
/// Returns a Bucket if it is present in bucket table,
/// even if it is in deleted state. Querying a non-existing
/// bucket ID returns an internal error.