mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-13 16:46:55 +00:00
ilm feature add
This commit is contained in:
@@ -65,6 +65,7 @@ pub mod service_account;
|
||||
pub mod sts;
|
||||
pub mod trace;
|
||||
pub mod user;
|
||||
pub mod tier;
|
||||
use urlencoding::decode;
|
||||
|
||||
#[derive(Debug, Serialize, Default)]
|
||||
|
||||
@@ -0,0 +1,364 @@
|
||||
use std::str::from_utf8;
|
||||
|
||||
use http::{HeaderMap, StatusCode};
|
||||
use iam::get_global_action_cred;
|
||||
use matchit::Params;
|
||||
use s3s::{header::CONTENT_TYPE, s3_error, Body, S3Error, S3ErrorCode, S3Request, S3Response, S3Result};
|
||||
use serde::Deserialize;
|
||||
use serde_urlencoded::from_bytes;
|
||||
use tracing::{warn, debug, info};
|
||||
|
||||
use crypto::{encrypt_data, decrypt_data};
|
||||
use crate::{
|
||||
admin::{router::Operation, utils::has_space_be},
|
||||
auth::{check_key_valid, get_session_token},
|
||||
};
|
||||
use ecstore::{
|
||||
client::admin_handler_utils::AdminError,
|
||||
config::storageclass,
|
||||
global::GLOBAL_TierConfigMgr,
|
||||
tier::{
|
||||
tier_admin::TierCreds,
|
||||
tier_config::{TierConfig, TierType},
|
||||
tier_handlers::{
|
||||
ERR_TIER_NAME_NOT_UPPERCASE, ERR_TIER_ALREADY_EXISTS, ERR_TIER_NOT_FOUND, ERR_TIER_CONNECT_ERR,
|
||||
ERR_TIER_INVALID_CREDENTIALS,
|
||||
},
|
||||
tier::{ERR_TIER_MISSING_CREDENTIALS, ERR_TIER_BACKEND_NOT_EMPTY, ERR_TIER_BACKEND_IN_USE},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Deserialize, Default)]
|
||||
pub struct AddTierQuery {
|
||||
#[serde(rename = "accessKey")]
|
||||
pub access_key: Option<String>,
|
||||
pub status: Option<String>,
|
||||
pub tier: Option<String>,
|
||||
pub force: String,
|
||||
}
|
||||
|
||||
pub struct AddTier {}
|
||||
#[async_trait::async_trait]
|
||||
impl Operation for AddTier {
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
async fn call(&self, req: S3Request<Body>, _params: Params<'_, '_>) -> S3Result<S3Response<(StatusCode, Body)>> {
|
||||
let query = {
|
||||
if let Some(query) = req.uri.query() {
|
||||
let input: AddTierQuery =
|
||||
from_bytes(query.as_bytes()).map_err(|_e| s3_error!(InvalidArgument, "get body failed1"))?;
|
||||
input
|
||||
} else {
|
||||
AddTierQuery::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 args: TierConfig = serde_json::from_slice(&body)
|
||||
.map_err(|e| S3Error::with_message(S3ErrorCode::InternalError, format!("unmarshal body err {}", e)))?;
|
||||
|
||||
match args.tier_type {
|
||||
TierType::S3 => {
|
||||
args.name = args.s3.clone().unwrap().name;
|
||||
}
|
||||
TierType::RustFS => {
|
||||
args.name = args.rustfs.clone().unwrap().name;
|
||||
}
|
||||
TierType::MinIO => {
|
||||
args.name = args.minio.clone().unwrap().name;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
debug!("add tier args {:?}", args);
|
||||
|
||||
let mut force: bool = false;
|
||||
let force_str = query.force;
|
||||
if force_str != "" {
|
||||
force = force_str.parse().unwrap();
|
||||
}
|
||||
match args.name.as_str() {
|
||||
storageclass::STANDARD | storageclass::RRS => {
|
||||
warn!("tier reserved name, args.name: {}", args.name);
|
||||
return Err(s3_error!(InvalidRequest, "Cannot use reserved tier name"));
|
||||
}
|
||||
&_ => ()
|
||||
}
|
||||
|
||||
let mut tier_config_mgr = GLOBAL_TierConfigMgr.write().await;
|
||||
//tier_config_mgr.reload(api);
|
||||
match tier_config_mgr.add(args, force).await {
|
||||
Err(ERR_TIER_ALREADY_EXISTS) => {
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("TierNameAlreadyExist".into()), "tier name already exists!"));
|
||||
}
|
||||
Err(ERR_TIER_NAME_NOT_UPPERCASE) => {
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("TierNameNotUppercase".into()), "tier name not uppercase!"));
|
||||
}
|
||||
Err(ERR_TIER_BACKEND_IN_USE) => {
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("TierNameBackendInUse!".into()), "tier name backend in use!"));
|
||||
}
|
||||
Err(ERR_TIER_CONNECT_ERR) => {
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("TierConnectError".into()), "tier connect error!"));
|
||||
}
|
||||
Err(ERR_TIER_INVALID_CREDENTIALS) => {
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom(ERR_TIER_INVALID_CREDENTIALS.code.into()), ERR_TIER_INVALID_CREDENTIALS.message));
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("tier_config_mgr add failed, e: {:?}", e);
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("TierAddFailed".into()), "tier add failed"));
|
||||
}
|
||||
Ok(_) => (),
|
||||
}
|
||||
if let Err(e) = tier_config_mgr.save().await {
|
||||
warn!("tier_config_mgr save failed, e: {:?}", e);
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("TierAddFailed".into()), "tier save failed"));
|
||||
}
|
||||
//globalNotificationSys.LoadTransitionTierConfig(ctx);
|
||||
|
||||
let mut header = HeaderMap::new();
|
||||
header.insert(CONTENT_TYPE, "application/json".parse().unwrap());
|
||||
|
||||
Ok(S3Response::with_headers((StatusCode::OK, Body::empty()), header))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EditTier {}
|
||||
#[async_trait::async_trait]
|
||||
impl Operation for EditTier {
|
||||
async fn call(&self, req: S3Request<Body>, params: Params<'_, '_>) -> S3Result<S3Response<(StatusCode, Body)>> {
|
||||
let query = {
|
||||
if let Some(query) = req.uri.query() {
|
||||
let input: AddTierQuery =
|
||||
from_bytes(query.as_bytes()).map_err(|_e| s3_error!(InvalidArgument, "get body failed1"))?;
|
||||
input
|
||||
} else {
|
||||
AddTierQuery::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?;
|
||||
|
||||
//{"accesskey":"gggggg","secretkey":"jjjjjjj"}
|
||||
//{"detailedMessage":"failed to perform PUT: The Access Key Id you provided does not exist in our records.","message":"an error occurred, please try again"}
|
||||
//200 OK
|
||||
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 creds: TierCreds = serde_json::from_slice(&body)
|
||||
.map_err(|e| S3Error::with_message(S3ErrorCode::InternalError, format!("unmarshal body err {}", e)))?;
|
||||
|
||||
debug!("edit tier args {:?}", creds);
|
||||
|
||||
let tier_name = params.get("tiername").map(|s| s.to_string()).unwrap_or_default();
|
||||
|
||||
let mut tier_config_mgr = GLOBAL_TierConfigMgr.write().await;
|
||||
//tier_config_mgr.reload(api);
|
||||
match tier_config_mgr.edit(&tier_name, creds).await {
|
||||
Err(ERR_TIER_NOT_FOUND) => {
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("TierNotFound".into()), "tier not found!"));
|
||||
}
|
||||
Err(ERR_TIER_MISSING_CREDENTIALS) => {
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("TierMissingCredentials".into()), "tier missing credentials!"));
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("tier_config_mgr edit failed, e: {:?}", e);
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("TierEditFailed".into()), "tier edit failed"));
|
||||
}
|
||||
Ok(_) => (),
|
||||
}
|
||||
if let Err(e) = tier_config_mgr.save().await {
|
||||
warn!("tier_config_mgr save failed, e: {:?}", e);
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("TierEditFailed".into()), "tier save failed"));
|
||||
}
|
||||
//globalNotificationSys.LoadTransitionTierConfig(ctx);
|
||||
|
||||
let mut header = HeaderMap::new();
|
||||
header.insert(CONTENT_TYPE, "application/json".parse().unwrap());
|
||||
|
||||
Ok(S3Response::with_headers((StatusCode::OK, Body::empty()), header))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Default)]
|
||||
pub struct BucketQuery {
|
||||
#[serde(rename = "bucket")]
|
||||
pub bucket: String,
|
||||
}
|
||||
pub struct ListTiers {}
|
||||
#[async_trait::async_trait]
|
||||
impl Operation for ListTiers {
|
||||
async fn call(&self, req: S3Request<Body>, _params: Params<'_, '_>) -> S3Result<S3Response<(StatusCode, Body)>> {
|
||||
let query = {
|
||||
if let Some(query) = req.uri.query() {
|
||||
let input: BucketQuery =
|
||||
from_bytes(query.as_bytes()).map_err(|_e| s3_error!(InvalidArgument, "get body failed"))?;
|
||||
input
|
||||
} else {
|
||||
BucketQuery::default()
|
||||
}
|
||||
};
|
||||
|
||||
//{"items":[{"minio":{"accesskey":"minioadmin","bucket":"mblock2","endpoint":"http://192.168.1.11:9020","name":"COLDTIER","objects":"0","prefix":"mypre/","secretkey":"REDACTED","usage":"0 B","versions":"0"},"status":true,"type":"minio"}]}
|
||||
let mut tier_config_mgr = GLOBAL_TierConfigMgr.read().await;
|
||||
let tiers = tier_config_mgr.list_tiers();
|
||||
|
||||
let data = serde_json::to_vec(&tiers)
|
||||
.map_err(|e| S3Error::with_message(S3ErrorCode::InternalError, format!("marshal tiers err {}", e)))?;
|
||||
|
||||
let mut header = HeaderMap::new();
|
||||
header.insert(CONTENT_TYPE, "application/json".parse().unwrap());
|
||||
|
||||
Ok(S3Response::with_headers((StatusCode::OK, Body::from(data)), header))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RemoveTier {}
|
||||
#[async_trait::async_trait]
|
||||
impl Operation for RemoveTier {
|
||||
async fn call(&self, req: S3Request<Body>, params: Params<'_, '_>) -> S3Result<S3Response<(StatusCode, Body)>> {
|
||||
warn!("handle RemoveTier");
|
||||
|
||||
let query = {
|
||||
if let Some(query) = req.uri.query() {
|
||||
let input: AddTierQuery =
|
||||
from_bytes(query.as_bytes()).map_err(|_e| s3_error!(InvalidArgument, "get body failed"))?;
|
||||
input
|
||||
} else {
|
||||
AddTierQuery::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 sys_cred = get_global_action_cred()
|
||||
.ok_or_else(|| S3Error::with_message(S3ErrorCode::InternalError, "get_global_action_cred failed"))?;
|
||||
|
||||
let mut force: bool = false;
|
||||
let force_str = query.force;
|
||||
if force_str != "" {
|
||||
force = force_str.parse().unwrap();
|
||||
}
|
||||
|
||||
let tier_name = params.get("tiername").map(|s| s.to_string()).unwrap_or_default();
|
||||
|
||||
let mut tier_config_mgr = GLOBAL_TierConfigMgr.write().await;
|
||||
//tier_config_mgr.reload(api);
|
||||
match tier_config_mgr.remove(&tier_name, force).await {
|
||||
Err(ERR_TIER_NOT_FOUND) => {
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("TierNotFound".into()), "tier not found."));
|
||||
}
|
||||
Err(ERR_TIER_BACKEND_NOT_EMPTY) => {
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("TierNameBackendInUse".into()), "tier is used."));
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("tier_config_mgr remove failed, e: {:?}", e);
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("TierRemoveFailed".into()), "tier remove failed"));
|
||||
}
|
||||
Ok(_) => (),
|
||||
}
|
||||
if let Err(e) = tier_config_mgr.save().await {
|
||||
warn!("tier_config_mgr save failed, e: {:?}", e);
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("TierRemoveFailed".into()), "tier save failed"));
|
||||
}
|
||||
//globalNotificationSys.LoadTransitionTierConfig(ctx);
|
||||
|
||||
let mut header = HeaderMap::new();
|
||||
header.insert(CONTENT_TYPE, "application/json".parse().unwrap());
|
||||
|
||||
Ok(S3Response::with_headers((StatusCode::OK, Body::empty()), header))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VerifyTier {}
|
||||
#[async_trait::async_trait]
|
||||
impl Operation for VerifyTier {
|
||||
async fn call(&self, req: S3Request<Body>, _params: Params<'_, '_>) -> S3Result<S3Response<(StatusCode, Body)>> {
|
||||
warn!("handle RemoveTier");
|
||||
|
||||
let query = {
|
||||
if let Some(query) = req.uri.query() {
|
||||
let input: AddTierQuery =
|
||||
from_bytes(query.as_bytes()).map_err(|_e| s3_error!(InvalidArgument, "get body failed"))?;
|
||||
input
|
||||
} else {
|
||||
AddTierQuery::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 sys_cred = get_global_action_cred()
|
||||
.ok_or_else(|| S3Error::with_message(S3ErrorCode::InternalError, "get_global_action_cred failed"))?;
|
||||
|
||||
let mut tier_config_mgr = GLOBAL_TierConfigMgr.write().await;
|
||||
tier_config_mgr.verify(&query.tier.unwrap());
|
||||
|
||||
let mut header = HeaderMap::new();
|
||||
header.insert(CONTENT_TYPE, "application/json".parse().unwrap());
|
||||
|
||||
Ok(S3Response::with_headers((StatusCode::OK, Body::empty()), header))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GetTierInfo {}
|
||||
#[async_trait::async_trait]
|
||||
impl Operation for GetTierInfo {
|
||||
async fn call(&self, req: S3Request<Body>, _params: Params<'_, '_>) -> S3Result<S3Response<(StatusCode, Body)>> {
|
||||
warn!("handle GetTierInfo");
|
||||
|
||||
let query = {
|
||||
if let Some(query) = req.uri.query() {
|
||||
let input: AddTierQuery =
|
||||
from_bytes(query.as_bytes()).map_err(|_e| s3_error!(InvalidArgument, "get body failed"))?;
|
||||
input
|
||||
} else {
|
||||
AddTierQuery::default()
|
||||
}
|
||||
};
|
||||
|
||||
let mut tier_config_mgr = GLOBAL_TierConfigMgr.read().await;
|
||||
let info = tier_config_mgr.get(&query.tier.unwrap());
|
||||
|
||||
let data = serde_json::to_vec(&info)
|
||||
.map_err(|e| S3Error::with_message(S3ErrorCode::InternalError, format!("marshal tier err {}", e)))?;
|
||||
|
||||
let mut header = HeaderMap::new();
|
||||
header.insert(CONTENT_TYPE, "application/json".parse().unwrap());
|
||||
|
||||
Ok(S3Response::with_headers((StatusCode::OK, Body::from(data)), header))
|
||||
}
|
||||
}
|
||||
+34
-1
@@ -7,7 +7,7 @@ pub mod utils;
|
||||
use handlers::{
|
||||
group, policys, pools, rebalance,
|
||||
service_account::{AddServiceAccount, DeleteServiceAccount, InfoServiceAccount, ListServiceAccount, UpdateServiceAccount},
|
||||
sts, user,
|
||||
sts, user, tier,
|
||||
};
|
||||
|
||||
use handlers::{GetReplicationMetricsHandler, ListRemoteTargetHandler, RemoveRemoteTargetHandler, SetRemoteTargetHandler};
|
||||
@@ -311,5 +311,38 @@ fn register_user_route(r: &mut S3Router<AdminOperation>) -> std::io::Result<()>
|
||||
AdminOperation(&policys::SetPolicyForUserOrGroup {}),
|
||||
)?;
|
||||
|
||||
// ?
|
||||
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 {}),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ use chrono::Utc;
|
||||
use datafusion::arrow::csv::WriterBuilder as CsvWriterBuilder;
|
||||
use datafusion::arrow::json::WriterBuilder as JsonWriterBuilder;
|
||||
use datafusion::arrow::json::writer::JsonArray;
|
||||
use ecstore::bucket::error::BucketMetadataError;
|
||||
use ecstore::bucket::metadata::BUCKET_LIFECYCLE_CONFIG;
|
||||
use ecstore::bucket::metadata::BUCKET_NOTIFICATION_CONFIG;
|
||||
use ecstore::bucket::metadata::BUCKET_POLICY_CONFIG;
|
||||
@@ -52,6 +53,7 @@ use ecstore::bucket::utils::serialize;
|
||||
use ecstore::cmd::bucket_replication::ReplicationStatusType;
|
||||
use ecstore::cmd::bucket_replication::ReplicationType;
|
||||
use ecstore::store_api::RESERVED_METADATA_PREFIX_LOWER;
|
||||
use ecstore::bucket::lifecycle::bucket_lifecycle_ops::validate_transition_tier;
|
||||
use futures::pin_mut;
|
||||
use futures::{Stream, StreamExt};
|
||||
use http::HeaderMap;
|
||||
@@ -93,6 +95,14 @@ use tracing::warn;
|
||||
use transform_stream::AsyncTryStream;
|
||||
use uuid::Uuid;
|
||||
|
||||
use ecstore::bucket::{
|
||||
lifecycle::{
|
||||
lifecycle::Lifecycle,
|
||||
bucket_lifecycle_ops::ERR_INVALID_STORAGECLASS
|
||||
},
|
||||
object_lock::objectlock_sys::BucketObjectLockSys,
|
||||
};
|
||||
|
||||
macro_rules! try_ {
|
||||
($result:expr) => {
|
||||
match $result {
|
||||
@@ -1590,12 +1600,26 @@ impl S3 for FS {
|
||||
..
|
||||
} = req.input;
|
||||
|
||||
// warn!("lifecycle_configuration {:?}", &lifecycle_configuration);
|
||||
let rcfg = metadata_sys::get_object_lock_config(&bucket).await;
|
||||
if rcfg.is_err() {
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("BucketLockIsNotExist".into()), "bucket lock is not exist."));
|
||||
}
|
||||
let rcfg = rcfg.expect("get_lifecycle_config err!").0;
|
||||
|
||||
// TODO: objcetLock
|
||||
//info!("lifecycle_configuration: {:?}", &lifecycle_configuration);
|
||||
|
||||
let Some(input_cfg) = lifecycle_configuration else { return Err(s3_error!(InvalidArgument)) };
|
||||
|
||||
if let Err(err) = input_cfg.validate(&rcfg).await {
|
||||
//return Err(S3Error::with_message(S3ErrorCode::Custom("BucketLockValidateFailed".into()), "bucket lock validate failed."));
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("ValidateFailed".into()), format!("{}", err.to_string())));
|
||||
}
|
||||
|
||||
if let Err(err) = validate_transition_tier(&input_cfg).await {
|
||||
//warn!("lifecycle_configuration add failed, err: {:?}", err);
|
||||
return Err(S3Error::with_message(S3ErrorCode::Custom("CustomError".into()), format!("{}", err.to_string())));
|
||||
}
|
||||
|
||||
let data = try_!(serialize(&input_cfg));
|
||||
metadata_sys::update(&bucket, BUCKET_LIFECYCLE_CONFIG, data)
|
||||
.await
|
||||
@@ -2036,6 +2060,27 @@ impl S3 for FS {
|
||||
}))
|
||||
}
|
||||
|
||||
async fn get_object_attributes(
|
||||
&self,
|
||||
req: S3Request<GetObjectAttributesInput>,
|
||||
) -> S3Result<S3Response<GetObjectAttributesOutput>> {
|
||||
let GetObjectAttributesInput { bucket, key, .. } = req.input;
|
||||
|
||||
let Some(store) = new_object_layer_fn() else {
|
||||
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
|
||||
};
|
||||
|
||||
if let Err(e) = store.get_object_reader(&bucket, &key, None, HeaderMap::new(), &ObjectOptions::default()).await {
|
||||
return Err(S3Error::with_message(S3ErrorCode::InternalError, format!("{}", e)));
|
||||
}
|
||||
|
||||
Ok(S3Response::new(GetObjectAttributesOutput {
|
||||
delete_marker: None,
|
||||
object_parts: None,
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
|
||||
async fn put_object_acl(&self, req: S3Request<PutObjectAclInput>) -> S3Result<S3Response<PutObjectAclOutput>> {
|
||||
let PutObjectAclInput {
|
||||
bucket,
|
||||
|
||||
Reference in New Issue
Block a user