aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2024-03-19 17:17:46 +0100
committerAlex Auvolat <alex@adnab.me>2024-03-19 17:17:46 +0100
commitce69dc302c6eaad4fe5268cca3511620fcca12f8 (patch)
treea0a406a26ca15721a3a9d52caecc90a15512f1ab
parent65853a48634d662809eee5dafbe48535d400f4a0 (diff)
parent26310f3242319c9ad093f5121cff0fe0c0108542 (diff)
downloadgarage-ce69dc302c6eaad4fe5268cca3511620fcca12f8.tar.gz
garage-ce69dc302c6eaad4fe5268cca3511620fcca12f8.zip
Merge branch 'main' into next-0.10
-rw-r--r--doc/book/connect/cli.md2
-rw-r--r--src/garage/admin/bucket.rs40
-rw-r--r--src/model/helper/bucket.rs43
3 files changed, 60 insertions, 25 deletions
diff --git a/doc/book/connect/cli.md b/doc/book/connect/cli.md
index c9ffd4f4..6529e4b2 100644
--- a/doc/book/connect/cli.md
+++ b/doc/book/connect/cli.md
@@ -259,7 +259,7 @@ duck --delete garage:/my-files/an-object.txt
## WinSCP (libs3) {#winscp}
-*You can find instructions on how to use the GUI in french [in our wiki](https://wiki.deuxfleurs.fr/fr/Guide/Garage/WinSCP).*
+*You can find instructions on how to use the GUI in french [in our wiki](https://guide.deuxfleurs.fr/prise_en_main/winscp/).*
How to use `winscp.com`, the CLI interface of WinSCP:
diff --git a/src/garage/admin/bucket.rs b/src/garage/admin/bucket.rs
index 6b1190f8..1bdc6086 100644
--- a/src/garage/admin/bucket.rs
+++ b/src/garage/admin/bucket.rs
@@ -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?,
);
}
diff --git a/src/model/helper/bucket.rs b/src/model/helper/bucket.rs
index a712d683..e5506d7e 100644
--- a/src/model/helper/bucket.rs
+++ b/src/model/helper/bucket.rs
@@ -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.