mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-08 06:13:14 +00:00
feat: add ImportBucketMetadata handler
This commit is contained in:
@@ -56,6 +56,7 @@ use tokio_stream::wrappers::ReceiverStream;
|
||||
use tracing::{error, info, warn};
|
||||
// use url::UrlQuery;
|
||||
|
||||
pub mod bucket_meta;
|
||||
pub mod event;
|
||||
pub mod group;
|
||||
pub mod policys;
|
||||
|
||||
@@ -0,0 +1,486 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io::{Cursor, Read as _, Write as _},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
admin::router::Operation,
|
||||
auth::{check_key_valid, get_session_token},
|
||||
};
|
||||
|
||||
use ecstore::{
|
||||
StorageAPI,
|
||||
bucket::{
|
||||
metadata::{
|
||||
BUCKET_LIFECYCLE_CONFIG, BUCKET_NOTIFICATION_CONFIG, BUCKET_POLICY_CONFIG, BUCKET_QUOTA_CONFIG_FILE,
|
||||
BUCKET_REPLICATION_CONFIG, BUCKET_SSECONFIG, BUCKET_TAGGING_CONFIG, BUCKET_TARGETS_FILE, BUCKET_VERSIONING_CONFIG,
|
||||
OBJECT_LOCK_CONFIG,
|
||||
},
|
||||
metadata_sys,
|
||||
},
|
||||
error::StorageError,
|
||||
new_object_layer_fn,
|
||||
store_api::BucketOptions,
|
||||
};
|
||||
use ecstore::{
|
||||
bucket::utils::{deserialize, serialize},
|
||||
store_api::MakeBucketOptions,
|
||||
};
|
||||
use http::{HeaderMap, StatusCode};
|
||||
use matchit::Params;
|
||||
use rustfs_utils::path::{SLASH_SEPARATOR, path_join_buf};
|
||||
use s3s::{
|
||||
Body, S3Request, S3Response, S3Result,
|
||||
header::{CONTENT_DISPOSITION, CONTENT_LENGTH, CONTENT_TYPE},
|
||||
s3_error,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use serde_urlencoded::from_bytes;
|
||||
use time::OffsetDateTime;
|
||||
use tracing::warn;
|
||||
use zip::{ZipArchive, ZipWriter, write::SimpleFileOptions};
|
||||
|
||||
#[derive(Debug, Default, serde::Deserialize)]
|
||||
pub struct ExportBucketMetadataQuery {
|
||||
pub bucket: String,
|
||||
}
|
||||
|
||||
pub struct ExportBucketMetadata {}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Operation for ExportBucketMetadata {
|
||||
async fn call(&self, req: S3Request<Body>, _params: Params<'_, '_>) -> S3Result<S3Response<(StatusCode, Body)>> {
|
||||
let query = {
|
||||
if let Some(query) = req.uri.query() {
|
||||
let input: ExportBucketMetadataQuery =
|
||||
from_bytes(query.as_bytes()).map_err(|_e| s3_error!(InvalidArgument, "get query failed"))?;
|
||||
input
|
||||
} else {
|
||||
ExportBucketMetadataQuery::default()
|
||||
}
|
||||
};
|
||||
|
||||
let Some(input_cred) = req.credentials else {
|
||||
return Err(s3_error!(InvalidRequest, "get cred failed"));
|
||||
};
|
||||
|
||||
let (_cred, _owner) =
|
||||
check_key_valid(get_session_token(&req.uri, &req.headers).unwrap_or_default(), &input_cred.access_key).await?;
|
||||
|
||||
let Some(store) = new_object_layer_fn() else {
|
||||
return Err(s3_error!(InvalidRequest, "object store not init"));
|
||||
};
|
||||
|
||||
let buckets = if query.bucket.is_empty() {
|
||||
store
|
||||
.list_bucket(&BucketOptions::default())
|
||||
.await
|
||||
.map_err(|e| s3_error!(InternalError, "list buckets failed: {e}"))?
|
||||
} else {
|
||||
let bucket = store
|
||||
.get_bucket_info(&query.bucket, &BucketOptions::default())
|
||||
.await
|
||||
.map_err(|e| s3_error!(InternalError, "get bucket failed: {e}"))?;
|
||||
vec![bucket]
|
||||
};
|
||||
|
||||
let mut zip_writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
|
||||
let confs = [
|
||||
BUCKET_POLICY_CONFIG,
|
||||
BUCKET_NOTIFICATION_CONFIG,
|
||||
BUCKET_LIFECYCLE_CONFIG,
|
||||
BUCKET_SSECONFIG,
|
||||
BUCKET_TAGGING_CONFIG,
|
||||
BUCKET_QUOTA_CONFIG_FILE,
|
||||
OBJECT_LOCK_CONFIG,
|
||||
BUCKET_VERSIONING_CONFIG,
|
||||
BUCKET_REPLICATION_CONFIG,
|
||||
BUCKET_TARGETS_FILE,
|
||||
];
|
||||
|
||||
for bucket in buckets {
|
||||
for &conf in confs.iter() {
|
||||
let conf_path = path_join_buf(&[bucket.name.as_str(), conf]);
|
||||
match conf {
|
||||
BUCKET_POLICY_CONFIG => {
|
||||
let config: policy::policy::BucketPolicy = match metadata_sys::get_bucket_policy(&bucket.name).await {
|
||||
Ok((res, _)) => res,
|
||||
Err(e) => {
|
||||
if e == StorageError::ConfigNotFound {
|
||||
continue;
|
||||
}
|
||||
return Err(s3_error!(InternalError, "get bucket metadata failed: {e}"));
|
||||
}
|
||||
};
|
||||
let config_json =
|
||||
serde_json::to_vec(&config).map_err(|e| s3_error!(InternalError, "serialize config failed: {e}"))?;
|
||||
zip_writer
|
||||
.start_file(conf_path, SimpleFileOptions::default())
|
||||
.map_err(|e| s3_error!(InternalError, "start file failed: {e}"))?;
|
||||
zip_writer
|
||||
.write_all(&config_json)
|
||||
.map_err(|e| s3_error!(InternalError, "write file failed: {e}"))?;
|
||||
}
|
||||
BUCKET_NOTIFICATION_CONFIG => {
|
||||
let config: s3s::dto::NotificationConfiguration =
|
||||
match metadata_sys::get_notification_config(&bucket.name).await {
|
||||
Ok(Some(res)) => res,
|
||||
Err(e) => {
|
||||
if e == StorageError::ConfigNotFound {
|
||||
continue;
|
||||
}
|
||||
return Err(s3_error!(InternalError, "get bucket metadata failed: {e}"));
|
||||
}
|
||||
Ok(None) => continue,
|
||||
};
|
||||
|
||||
let config_xml =
|
||||
serialize(&config).map_err(|e| s3_error!(InternalError, "serialize config failed: {e}"))?;
|
||||
|
||||
zip_writer
|
||||
.start_file(conf_path, SimpleFileOptions::default())
|
||||
.map_err(|e| s3_error!(InternalError, "start file failed: {e}"))?;
|
||||
zip_writer
|
||||
.write_all(&config_xml)
|
||||
.map_err(|e| s3_error!(InternalError, "write file failed: {e}"))?;
|
||||
}
|
||||
BUCKET_LIFECYCLE_CONFIG => {
|
||||
let config = match metadata_sys::get_lifecycle_config(&bucket.name).await {
|
||||
Ok((res, _)) => res,
|
||||
Err(e) => {
|
||||
if e == StorageError::ConfigNotFound {
|
||||
continue;
|
||||
}
|
||||
return Err(s3_error!(InternalError, "get bucket metadata failed: {e}"));
|
||||
}
|
||||
};
|
||||
let config_xml =
|
||||
serialize(&config).map_err(|e| s3_error!(InternalError, "serialize config failed: {e}"))?;
|
||||
|
||||
zip_writer
|
||||
.start_file(conf_path, SimpleFileOptions::default())
|
||||
.map_err(|e| s3_error!(InternalError, "start file failed: {e}"))?;
|
||||
zip_writer
|
||||
.write_all(&config_xml)
|
||||
.map_err(|e| s3_error!(InternalError, "write file failed: {e}"))?;
|
||||
}
|
||||
BUCKET_TAGGING_CONFIG => {
|
||||
let config = match metadata_sys::get_tagging_config(&bucket.name).await {
|
||||
Ok((res, _)) => res,
|
||||
Err(e) => {
|
||||
if e == StorageError::ConfigNotFound {
|
||||
continue;
|
||||
}
|
||||
return Err(s3_error!(InternalError, "get bucket metadata failed: {e}"));
|
||||
}
|
||||
};
|
||||
let config_xml =
|
||||
serialize(&config).map_err(|e| s3_error!(InternalError, "serialize config failed: {e}"))?;
|
||||
|
||||
zip_writer
|
||||
.start_file(conf_path, SimpleFileOptions::default())
|
||||
.map_err(|e| s3_error!(InternalError, "start file failed: {e}"))?;
|
||||
zip_writer
|
||||
.write_all(&config_xml)
|
||||
.map_err(|e| s3_error!(InternalError, "write file failed: {e}"))?;
|
||||
}
|
||||
BUCKET_QUOTA_CONFIG_FILE => {
|
||||
let config = match metadata_sys::get_quota_config(&bucket.name).await {
|
||||
Ok((res, _)) => res,
|
||||
Err(e) => {
|
||||
if e == StorageError::ConfigNotFound {
|
||||
continue;
|
||||
}
|
||||
return Err(s3_error!(InternalError, "get bucket metadata failed: {e}"));
|
||||
}
|
||||
};
|
||||
let config_json =
|
||||
serde_json::to_vec(&config).map_err(|e| s3_error!(InternalError, "serialize config failed: {e}"))?;
|
||||
|
||||
zip_writer
|
||||
.start_file(conf_path, SimpleFileOptions::default())
|
||||
.map_err(|e| s3_error!(InternalError, "start file failed: {e}"))?;
|
||||
zip_writer
|
||||
.write_all(&config_json)
|
||||
.map_err(|e| s3_error!(InternalError, "write file failed: {e}"))?;
|
||||
}
|
||||
OBJECT_LOCK_CONFIG => {
|
||||
let config = match metadata_sys::get_object_lock_config(&bucket.name).await {
|
||||
Ok((res, _)) => res,
|
||||
Err(e) => {
|
||||
if e == StorageError::ConfigNotFound {
|
||||
continue;
|
||||
}
|
||||
return Err(s3_error!(InternalError, "get bucket metadata failed: {e}"));
|
||||
}
|
||||
};
|
||||
let config_xml =
|
||||
serialize(&config).map_err(|e| s3_error!(InternalError, "serialize config failed: {e}"))?;
|
||||
|
||||
zip_writer
|
||||
.start_file(conf_path, SimpleFileOptions::default())
|
||||
.map_err(|e| s3_error!(InternalError, "start file failed: {e}"))?;
|
||||
zip_writer
|
||||
.write_all(&config_xml)
|
||||
.map_err(|e| s3_error!(InternalError, "write file failed: {e}"))?;
|
||||
}
|
||||
BUCKET_SSECONFIG => {
|
||||
let config = match metadata_sys::get_sse_config(&bucket.name).await {
|
||||
Ok((res, _)) => res,
|
||||
Err(e) => {
|
||||
if e == StorageError::ConfigNotFound {
|
||||
continue;
|
||||
}
|
||||
return Err(s3_error!(InternalError, "get bucket metadata failed: {e}"));
|
||||
}
|
||||
};
|
||||
let config_xml =
|
||||
serialize(&config).map_err(|e| s3_error!(InternalError, "serialize config failed: {e}"))?;
|
||||
|
||||
zip_writer
|
||||
.start_file(conf_path, SimpleFileOptions::default())
|
||||
.map_err(|e| s3_error!(InternalError, "start file failed: {e}"))?;
|
||||
zip_writer
|
||||
.write_all(&config_xml)
|
||||
.map_err(|e| s3_error!(InternalError, "write file failed: {e}"))?;
|
||||
}
|
||||
BUCKET_VERSIONING_CONFIG => {
|
||||
let config = match metadata_sys::get_versioning_config(&bucket.name).await {
|
||||
Ok((res, _)) => res,
|
||||
Err(e) => {
|
||||
if e == StorageError::ConfigNotFound {
|
||||
continue;
|
||||
}
|
||||
return Err(s3_error!(InternalError, "get bucket metadata failed: {e}"));
|
||||
}
|
||||
};
|
||||
let config_xml =
|
||||
serialize(&config).map_err(|e| s3_error!(InternalError, "serialize config failed: {e}"))?;
|
||||
|
||||
zip_writer
|
||||
.start_file(conf_path, SimpleFileOptions::default())
|
||||
.map_err(|e| s3_error!(InternalError, "start file failed: {e}"))?;
|
||||
zip_writer
|
||||
.write_all(&config_xml)
|
||||
.map_err(|e| s3_error!(InternalError, "write file failed: {e}"))?;
|
||||
}
|
||||
BUCKET_REPLICATION_CONFIG => {
|
||||
let config = match metadata_sys::get_replication_config(&bucket.name).await {
|
||||
Ok((res, _)) => res,
|
||||
Err(e) => {
|
||||
if e == StorageError::ConfigNotFound {
|
||||
continue;
|
||||
}
|
||||
return Err(s3_error!(InternalError, "get bucket metadata failed: {e}"));
|
||||
}
|
||||
};
|
||||
let config_xml =
|
||||
serialize(&config).map_err(|e| s3_error!(InternalError, "serialize config failed: {e}"))?;
|
||||
|
||||
zip_writer
|
||||
.start_file(conf_path, SimpleFileOptions::default())
|
||||
.map_err(|e| s3_error!(InternalError, "start file failed: {e}"))?;
|
||||
zip_writer
|
||||
.write_all(&config_xml)
|
||||
.map_err(|e| s3_error!(InternalError, "write file failed: {e}"))?;
|
||||
}
|
||||
BUCKET_TARGETS_FILE => {
|
||||
let config = match metadata_sys::get_bucket_targets_config(&bucket.name).await {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
if e == StorageError::ConfigNotFound {
|
||||
continue;
|
||||
}
|
||||
return Err(s3_error!(InternalError, "get bucket metadata failed: {e}"));
|
||||
}
|
||||
};
|
||||
|
||||
let config_json =
|
||||
serde_json::to_vec(&config).map_err(|e| s3_error!(InternalError, "serialize config failed: {e}"))?;
|
||||
|
||||
zip_writer
|
||||
.start_file(conf_path, SimpleFileOptions::default())
|
||||
.map_err(|e| s3_error!(InternalError, "start file failed: {e}"))?;
|
||||
zip_writer
|
||||
.write_all(&config_json)
|
||||
.map_err(|e| s3_error!(InternalError, "write file failed: {e}"))?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let zip_bytes = zip_writer
|
||||
.finish()
|
||||
.map_err(|e| s3_error!(InternalError, "finish zip failed: {e}"))?;
|
||||
let mut header = HeaderMap::new();
|
||||
header.insert(CONTENT_TYPE, "application/zip".parse().unwrap());
|
||||
header.insert(CONTENT_DISPOSITION, "attachment; filename=bucket-meta.zip".parse().unwrap());
|
||||
header.insert(CONTENT_LENGTH, zip_bytes.get_ref().len().to_string().parse().unwrap());
|
||||
Ok(S3Response::with_headers((StatusCode::OK, Body::from(zip_bytes.into_inner())), header))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct ImportBucketMetadataQuery {
|
||||
#[allow(dead_code)]
|
||||
pub bucket: String,
|
||||
}
|
||||
|
||||
pub struct ImportBucketMetadata {}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Operation for ImportBucketMetadata {
|
||||
async fn call(&self, req: S3Request<Body>, _params: Params<'_, '_>) -> S3Result<S3Response<(StatusCode, Body)>> {
|
||||
let _query = {
|
||||
if let Some(query) = req.uri.query() {
|
||||
let input: ImportBucketMetadataQuery =
|
||||
from_bytes(query.as_bytes()).map_err(|_e| s3_error!(InvalidArgument, "get query failed"))?;
|
||||
input
|
||||
} else {
|
||||
ImportBucketMetadataQuery::default()
|
||||
}
|
||||
};
|
||||
|
||||
let Some(input_cred) = req.credentials else {
|
||||
return Err(s3_error!(InvalidRequest, "get cred failed"));
|
||||
};
|
||||
|
||||
let (_cred, _owner) =
|
||||
check_key_valid(get_session_token(&req.uri, &req.headers).unwrap_or_default(), &input_cred.access_key).await?;
|
||||
|
||||
let mut input = req.input;
|
||||
let body = match input.store_all_unlimited().await {
|
||||
Ok(b) => b,
|
||||
Err(e) => {
|
||||
warn!("get body failed, e: {:?}", e);
|
||||
return Err(s3_error!(InvalidRequest, "get body failed"));
|
||||
}
|
||||
};
|
||||
|
||||
let mut zip_reader = ZipArchive::new(Cursor::new(body)).map_err(|e| s3_error!(InternalError, "get body failed: {e}"))?;
|
||||
|
||||
// First pass: read all file contents into memory
|
||||
let mut file_contents = Vec::new();
|
||||
for i in 0..zip_reader.len() {
|
||||
let mut file = zip_reader
|
||||
.by_index(i)
|
||||
.map_err(|e| s3_error!(InternalError, "get file failed: {e}"))?;
|
||||
let file_path = file.name().to_string();
|
||||
|
||||
let mut content = Vec::new();
|
||||
file.read_to_end(&mut content)
|
||||
.map_err(|e| s3_error!(InternalError, "read file failed: {e}"))?;
|
||||
|
||||
file_contents.push((file_path, content));
|
||||
}
|
||||
|
||||
// Extract bucket names
|
||||
let mut bucket_names = Vec::new();
|
||||
for (file_path, _) in &file_contents {
|
||||
let file_path_split = file_path.split(SLASH_SEPARATOR).collect::<Vec<&str>>();
|
||||
|
||||
if file_path_split.len() < 2 {
|
||||
warn!("file path is invalid: {}", file_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
let bucket_name = file_path_split[0].to_string();
|
||||
if !bucket_names.contains(&bucket_name) {
|
||||
bucket_names.push(bucket_name);
|
||||
}
|
||||
}
|
||||
|
||||
// Get existing bucket metadata
|
||||
let mut bucket_metadatas = HashMap::new();
|
||||
for bucket_name in bucket_names {
|
||||
match metadata_sys::get_config_from_disk(&bucket_name).await {
|
||||
Ok(res) => bucket_metadatas.insert(bucket_name, Arc::new(res)),
|
||||
Err(e) => {
|
||||
if e == StorageError::ConfigNotFound {
|
||||
warn!("bucket metadata not found: {e}");
|
||||
continue;
|
||||
}
|
||||
warn!("get bucket metadata failed: {e}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let Some(store) = new_object_layer_fn() else {
|
||||
return Err(s3_error!(InvalidRequest, "object store not init"));
|
||||
};
|
||||
|
||||
let update_at = OffsetDateTime::now_utc();
|
||||
|
||||
// Second pass: process file contents
|
||||
for (file_path, content) in file_contents {
|
||||
let file_path_split = file_path.split(SLASH_SEPARATOR).collect::<Vec<&str>>();
|
||||
|
||||
if file_path_split.len() < 2 {
|
||||
warn!("file path is invalid: {}", file_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
let bucket_name = file_path_split[0];
|
||||
let conf_name = file_path_split[1];
|
||||
|
||||
// create bucket if not exists
|
||||
if !bucket_metadatas.contains_key(bucket_name) {
|
||||
if let Err(e) = store
|
||||
.make_bucket(
|
||||
bucket_name,
|
||||
&MakeBucketOptions {
|
||||
force_create: true,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
warn!("create bucket failed: {e}");
|
||||
continue;
|
||||
}
|
||||
|
||||
let metadata = metadata_sys::get(bucket_name).await.unwrap_or_default();
|
||||
bucket_metadatas.insert(bucket_name.to_string(), metadata.clone());
|
||||
}
|
||||
|
||||
match conf_name {
|
||||
BUCKET_POLICY_CONFIG => {
|
||||
let config: policy::policy::BucketPolicy = match serde_json::from_slice(&content) {
|
||||
Ok(config) => config,
|
||||
Err(e) => {
|
||||
warn!("deserialize config failed: {e}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if config.version.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// let mut metadata = bucket_metadatas.get_mut(bucket_name).unwrap().clone();
|
||||
// metadata.policy_config_json = content;
|
||||
// metadata.policy_config_updated_at = update_at;
|
||||
}
|
||||
BUCKET_NOTIFICATION_CONFIG => {
|
||||
if let Err(e) = deserialize::<s3s::dto::NotificationConfiguration>(&content) {
|
||||
warn!("deserialize config failed: {e}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// let mut metadata = bucket_metadatas.get_mut(bucket_name).unwrap().clone();
|
||||
// metadata.notification_config_xml = content;
|
||||
// metadata.notification_config_updated_at = update_at;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let mut header = HeaderMap::new();
|
||||
header.insert(CONTENT_TYPE, "application/json".parse().unwrap());
|
||||
Ok(S3Response::with_headers((StatusCode::OK, Body::empty()), header))
|
||||
}
|
||||
}
|
||||
+76
-45
@@ -5,8 +5,7 @@ pub mod utils;
|
||||
|
||||
// use ecstore::global::{is_dist_erasure, is_erasure};
|
||||
use handlers::{
|
||||
event::{ListNotificationTargets, RemoveNotificationTarget, SetNotificationTarget},
|
||||
group, policys, pools, rebalance,
|
||||
bucket_meta, group, policys, pools, rebalance,
|
||||
service_account::{AddServiceAccount, DeleteServiceAccount, InfoServiceAccount, ListServiceAccount, UpdateServiceAccount},
|
||||
sts, tier, user,
|
||||
};
|
||||
@@ -120,11 +119,85 @@ pub fn make_admin_route() -> std::io::Result<impl S3Route> {
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/background-heal/status").as_str(),
|
||||
AdminOperation(&handlers::BackgroundHealStatusHandler {}),
|
||||
)?;
|
||||
// }
|
||||
|
||||
// ?
|
||||
r.insert(
|
||||
Method::GET,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/tier").as_str(),
|
||||
AdminOperation(&tier::ListTiers {}),
|
||||
)?;
|
||||
// ?
|
||||
r.insert(
|
||||
Method::GET,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/tier-stats").as_str(),
|
||||
AdminOperation(&tier::GetTierInfo {}),
|
||||
)?;
|
||||
// ?force=xxx
|
||||
r.insert(
|
||||
Method::DELETE,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/tier/{tiername}").as_str(),
|
||||
AdminOperation(&tier::RemoveTier {}),
|
||||
)?;
|
||||
// ?force=xxx
|
||||
// body: AddOrUpdateTierReq
|
||||
r.insert(
|
||||
Method::PUT,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/tier").as_str(),
|
||||
AdminOperation(&tier::AddTier {}),
|
||||
)?;
|
||||
// ?
|
||||
// body: AddOrUpdateTierReq
|
||||
r.insert(
|
||||
Method::POST,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/tier/{tiername}").as_str(),
|
||||
AdminOperation(&tier::EditTier {}),
|
||||
)?;
|
||||
r.insert(
|
||||
Method::POST,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/tier/clear").as_str(),
|
||||
AdminOperation(&tier::ClearTier {}),
|
||||
)?;
|
||||
|
||||
r.insert(
|
||||
Method::GET,
|
||||
format!("{}{}", ADMIN_PREFIX, "/export-bucket-metadata").as_str(),
|
||||
AdminOperation(&bucket_meta::ExportBucketMetadata {}),
|
||||
)?;
|
||||
|
||||
r.insert(
|
||||
Method::PUT,
|
||||
format!("{}{}", ADMIN_PREFIX, "/import-bucket-metadata").as_str(),
|
||||
AdminOperation(&bucket_meta::ImportBucketMetadata {}),
|
||||
)?;
|
||||
|
||||
r.insert(
|
||||
Method::GET,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/list-remote-targets").as_str(),
|
||||
AdminOperation(&ListRemoteTargetHandler {}),
|
||||
)?;
|
||||
|
||||
r.insert(
|
||||
Method::GET,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/replicationmetrics").as_str(),
|
||||
AdminOperation(&GetReplicationMetricsHandler {}),
|
||||
)?;
|
||||
|
||||
r.insert(
|
||||
Method::PUT,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/set-remote-target").as_str(),
|
||||
AdminOperation(&SetRemoteTargetHandler {}),
|
||||
)?;
|
||||
|
||||
r.insert(
|
||||
Method::DELETE,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/remove-remote-target").as_str(),
|
||||
AdminOperation(&RemoveRemoteTargetHandler {}),
|
||||
)?;
|
||||
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
/// user router
|
||||
fn register_user_route(r: &mut S3Router<AdminOperation>) -> std::io::Result<()> {
|
||||
// 1
|
||||
r.insert(
|
||||
@@ -241,30 +314,6 @@ fn register_user_route(r: &mut S3Router<AdminOperation>) -> std::io::Result<()>
|
||||
AdminOperation(&user::ImportIam {}),
|
||||
)?;
|
||||
|
||||
r.insert(
|
||||
Method::GET,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/list-remote-targets").as_str(),
|
||||
AdminOperation(&ListRemoteTargetHandler {}),
|
||||
)?;
|
||||
|
||||
r.insert(
|
||||
Method::GET,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/replicationmetrics").as_str(),
|
||||
AdminOperation(&GetReplicationMetricsHandler {}),
|
||||
)?;
|
||||
|
||||
r.insert(
|
||||
Method::PUT,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/set-remote-target").as_str(),
|
||||
AdminOperation(&SetRemoteTargetHandler {}),
|
||||
)?;
|
||||
|
||||
r.insert(
|
||||
Method::DELETE,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/remove-remote-target").as_str(),
|
||||
AdminOperation(&RemoveRemoteTargetHandler {}),
|
||||
)?;
|
||||
|
||||
// list-canned-policies?bucket=xxx
|
||||
r.insert(
|
||||
Method::GET,
|
||||
@@ -338,23 +387,5 @@ fn register_user_route(r: &mut S3Router<AdminOperation>) -> std::io::Result<()>
|
||||
AdminOperation(&tier::ClearTier {}),
|
||||
)?;
|
||||
|
||||
r.insert(
|
||||
Method::GET,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/target-list").as_str(),
|
||||
AdminOperation(&ListNotificationTargets {}),
|
||||
)?;
|
||||
|
||||
r.insert(
|
||||
Method::POST,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/target-set").as_str(),
|
||||
AdminOperation(&SetNotificationTarget {}),
|
||||
)?;
|
||||
|
||||
r.insert(
|
||||
Method::DELETE,
|
||||
format!("{}{}", ADMIN_PREFIX, "/v3/target-remove").as_str(),
|
||||
AdminOperation(&RemoveNotificationTarget {}),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user