diff --git a/ecstore/src/metrics_realtime.rs b/ecstore/src/metrics_realtime.rs index 97b396970..5bfc189b0 100644 --- a/ecstore/src/metrics_realtime.rs +++ b/ecstore/src/metrics_realtime.rs @@ -97,19 +97,19 @@ pub async fn collect_local_metrics(types: MetricType, opts: &CollectMetricsOpts) real_time_metrics.aggregated.scanner = Some(metrics); } - if types.contains(&MetricType::OS) {} + // if types.contains(&MetricType::OS) {} - if types.contains(&MetricType::BATCH_JOBS) {} + // if types.contains(&MetricType::BATCH_JOBS) {} - if types.contains(&MetricType::SITE_RESYNC) {} + // if types.contains(&MetricType::SITE_RESYNC) {} - if types.contains(&MetricType::NET) {} + // if types.contains(&MetricType::NET) {} - if types.contains(&MetricType::MEM) {} + // if types.contains(&MetricType::MEM) {} - if types.contains(&MetricType::CPU) {} + // if types.contains(&MetricType::CPU) {} - if types.contains(&MetricType::RPC) {} + // if types.contains(&MetricType::RPC) {} real_time_metrics .by_host @@ -128,10 +128,8 @@ async fn collect_local_disks_metrics(disks: &HashSet) -> HashMap, #[serde(rename = "groupStatus")] pub status: GroupStatus, diff --git a/rustfs/src/admin/handlers/group.rs b/rustfs/src/admin/handlers/group.rs index 6fb0bdc93..70025d371 100644 --- a/rustfs/src/admin/handlers/group.rs +++ b/rustfs/src/admin/handlers/group.rs @@ -1,11 +1,22 @@ -use http::StatusCode; -use iam::{error::is_err_no_such_user, get_global_action_cred}; +use http::{HeaderMap, StatusCode}; +use iam::{ + error::{is_err_no_such_group, is_err_no_such_user}, + get_global_action_cred, +}; use madmin::GroupAddRemove; use matchit::Params; -use s3s::{s3_error, Body, S3Error, S3ErrorCode, S3Request, S3Response, S3Result}; +use s3s::{header::CONTENT_TYPE, s3_error, Body, S3Error, S3ErrorCode, S3Request, S3Response, S3Result}; +use serde::Deserialize; +use serde_urlencoded::from_bytes; use tracing::warn; -use crate::admin::router::Operation; +use crate::admin::{router::Operation, utils::has_space_be}; + +#[derive(Debug, Deserialize, Default)] +pub struct GroupQuery { + pub group: String, + pub status: Option, +} pub struct ListGroups {} #[async_trait::async_trait] @@ -13,17 +24,101 @@ impl Operation for ListGroups { async fn call(&self, _req: S3Request, _params: Params<'_, '_>) -> S3Result> { warn!("handle ListGroups"); - Err(s3_error!(NotImplemented)) + let Ok(iam_store) = iam::get() else { return Err(s3_error!(InternalError, "iam not init")) }; + + let groups = iam_store.list_groups().await.map_err(|e| { + warn!("list groups failed, e: {:?}", e); + S3Error::with_message(S3ErrorCode::InternalError, e.to_string()) + })?; + + let body = serde_json::to_vec(&groups).map_err(|e| s3_error!(InternalError, "marshal body failed, e: {:?}", e))?; + + let mut header = HeaderMap::new(); + header.insert(CONTENT_TYPE, "application/json".parse().unwrap()); + + Ok(S3Response::with_headers((StatusCode::OK, Body::from(body)), header)) } } -pub struct Group {} +pub struct GetGroup {} #[async_trait::async_trait] -impl Operation for Group { - async fn call(&self, _req: S3Request, _params: Params<'_, '_>) -> S3Result> { - warn!("handle Group"); +impl Operation for GetGroup { + async fn call(&self, req: S3Request, _params: Params<'_, '_>) -> S3Result> { + warn!("handle GetGroup"); - Err(s3_error!(NotImplemented)) + let query = { + if let Some(query) = req.uri.query() { + let input: GroupQuery = + from_bytes(query.as_bytes()).map_err(|_e| s3_error!(InvalidArgument, "get body failed1"))?; + input + } else { + GroupQuery::default() + } + }; + let Ok(iam_store) = iam::get() else { return Err(s3_error!(InternalError, "iam not init")) }; + + let g = iam_store.get_group_description(&query.group).await.map_err(|e| { + warn!("get group failed, e: {:?}", e); + S3Error::with_message(S3ErrorCode::InternalError, e.to_string()) + })?; + + let body = serde_json::to_vec(&g).map_err(|e| s3_error!(InternalError, "marshal body failed, e: {:?}", e))?; + + let mut header = HeaderMap::new(); + header.insert(CONTENT_TYPE, "application/json".parse().unwrap()); + + Ok(S3Response::with_headers((StatusCode::OK, Body::from(body)), header)) + } +} + +pub struct SetGroupStatus {} +#[async_trait::async_trait] +impl Operation for SetGroupStatus { + async fn call(&self, req: S3Request, _params: Params<'_, '_>) -> S3Result> { + warn!("handle SetGroupStatus"); + + let query = { + if let Some(query) = req.uri.query() { + let input: GroupQuery = + from_bytes(query.as_bytes()).map_err(|_e| s3_error!(InvalidArgument, "get body failed1"))?; + input + } else { + GroupQuery::default() + } + }; + + if query.group.is_empty() { + return Err(s3_error!(InvalidArgument, "group is required")); + } + + let Ok(iam_store) = iam::get() else { return Err(s3_error!(InternalError, "iam not init")) }; + + if let Some(status) = query.status { + match status.as_str() { + "enabled" => { + iam_store.set_group_status(&query.group, true).await.map_err(|e| { + warn!("enable group failed, e: {:?}", e); + S3Error::with_message(S3ErrorCode::InternalError, e.to_string()) + })?; + } + "disabled" => { + iam_store.set_group_status(&query.group, false).await.map_err(|e| { + warn!("enable group failed, e: {:?}", e); + S3Error::with_message(S3ErrorCode::InternalError, e.to_string()) + })?; + } + _ => { + return Err(s3_error!(InvalidArgument, "invalid status")); + } + } + } else { + return Err(s3_error!(InvalidArgument, "status is required")); + } + + let mut header = HeaderMap::new(); + header.insert(CONTENT_TYPE, "application/json".parse().unwrap()); + + Ok(S3Response::with_headers((StatusCode::OK, Body::empty()), header)) } } @@ -83,20 +178,31 @@ impl Operation for UpdateGroupMembers { if args.is_remove { warn!("remove group members"); + iam_store + .remove_users_from_group(&args.group, args.members) + .await + .map_err(|e| { + warn!("remove group members failed, e: {:?}", e); + S3Error::with_message(S3ErrorCode::InternalError, e.to_string()) + })?; } else { warn!("add group members"); + + if let Err(err) = iam_store.get_group_description(&args.group).await { + if is_err_no_such_group(&err) && has_space_be(&args.group) { + return Err(s3_error!(InvalidArgument, "not such group")); + } + } + + iam_store.add_users_to_group(&args.group, args.members).await.map_err(|e| { + warn!("add group members failed, e: {:?}", e); + S3Error::with_message(S3ErrorCode::InternalError, e.to_string()) + })?; } - Err(s3_error!(NotImplemented)) - } -} - -pub struct SetGroupStatus {} -#[async_trait::async_trait] -impl Operation for SetGroupStatus { - async fn call(&self, _req: S3Request, _params: Params<'_, '_>) -> S3Result> { - warn!("handle SetGroupStatus"); - - Err(s3_error!(NotImplemented)) + let mut header = HeaderMap::new(); + header.insert(CONTENT_TYPE, "application/json".parse().unwrap()); + + Ok(S3Response::with_headers((StatusCode::OK, Body::empty()), header)) } } diff --git a/rustfs/src/admin/handlers/user.rs b/rustfs/src/admin/handlers/user.rs index 3fc98f07b..e30b5f0f9 100644 --- a/rustfs/src/admin/handlers/user.rs +++ b/rustfs/src/admin/handlers/user.rs @@ -156,17 +156,42 @@ impl Operation for SetUserStatus { } } +#[derive(Debug, Deserialize, Default)] +pub struct BucketQuery { + #[serde(rename = "bucket")] + pub bucket: String, +} pub struct ListUsers {} #[async_trait::async_trait] impl Operation for ListUsers { - async fn call(&self, _req: S3Request, _params: Params<'_, '_>) -> S3Result> { + async fn call(&self, req: S3Request, _params: Params<'_, '_>) -> S3Result> { warn!("handle ListUsers"); + + 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() + } + }; + let Ok(iam_store) = iam::get() else { return Err(s3_error!(InvalidRequest, "iam not init")) }; - let users = iam_store - .list_users() - .await - .map_err(|e| S3Error::with_message(S3ErrorCode::InternalError, e.to_string()))?; + let users = { + if !query.bucket.is_empty() { + iam_store + .list_bucket_users(query.bucket.as_str()) + .await + .map_err(|e| S3Error::with_message(S3ErrorCode::InternalError, e.to_string()))? + } else { + iam_store + .list_users() + .await + .map_err(|e| S3Error::with_message(S3ErrorCode::InternalError, e.to_string()))? + } + }; let data = serde_json::to_vec(&users) .map_err(|e| S3Error::with_message(S3ErrorCode::InternalError, format!("marshal users err {}", e)))?; diff --git a/rustfs/src/admin/mod.rs b/rustfs/src/admin/mod.rs index 4f9796d7a..43079517e 100644 --- a/rustfs/src/admin/mod.rs +++ b/rustfs/src/admin/mod.rs @@ -171,7 +171,7 @@ fn regist_user_route(r: &mut S3Router) -> Result<()> { r.insert( Method::GET, format!("{}{}", ADMIN_PREFIX, "/v3/group").as_str(), - AdminOperation(&group::Group {}), + AdminOperation(&group::GetGroup {}), )?; r.insert( @@ -192,7 +192,7 @@ fn regist_user_route(r: &mut S3Router) -> Result<()> { format!("{}{}", ADMIN_PREFIX, "/v3/update-service-account").as_str(), AdminOperation(&UpdateServiceAccount {}), )?; - + // 1 r.insert( Method::GET, format!("{}{}", ADMIN_PREFIX, "/v3/info-service-account").as_str(), @@ -205,13 +205,13 @@ fn regist_user_route(r: &mut S3Router) -> Result<()> { format!("{}{}", ADMIN_PREFIX, "/v3/list-service-accounts").as_str(), AdminOperation(&ListServiceAccount {}), )?; - + // 1 r.insert( Method::DELETE, format!("{}{}", ADMIN_PREFIX, "/v3/delete-service-accounts").as_str(), AdminOperation(&DeleteServiceAccount {}), )?; - + // 1 r.insert( Method::PUT, format!("{}{}", ADMIN_PREFIX, "/v3/add-service-accounts").as_str(),