Implement base operator #1
210
src/minio.rs
210
src/minio.rs
@ -1,9 +1,11 @@
|
|||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::constants::{MC_EXE, SECRET_MINIO_BUCKET_ACCESS_LEN, SECRET_MINIO_BUCKET_SECRET_LEN};
|
use crate::constants::{MC_EXE, SECRET_MINIO_BUCKET_ACCESS_LEN, SECRET_MINIO_BUCKET_SECRET_LEN};
|
||||||
use crate::crd::{MinioBucketSpec, RetentionType};
|
use crate::crd::{MinioBucketSpec, RetentionType};
|
||||||
use crate::utils::rand_str;
|
use crate::utils::rand_str;
|
||||||
use serde::de::DeserializeOwned;
|
|
||||||
use serde::Deserialize;
|
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
const MC_ALIAS_NAME: &str = "managedminioinst";
|
const MC_ALIAS_NAME: &str = "managedminioinst";
|
||||||
|
|
||||||
@ -62,6 +64,16 @@ struct BasicMinioResult {
|
|||||||
pub status: String,
|
pub status: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
struct MinioGetVersioningResult {
|
||||||
|
pub versioning: Option<MinioVersioning>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
struct MinioVersioning {
|
||||||
|
pub status: String,
|
||||||
|
}
|
||||||
|
|
||||||
impl BasicMinioResult {
|
impl BasicMinioResult {
|
||||||
pub fn success(&self) -> bool {
|
pub fn success(&self) -> bool {
|
||||||
self.status == "success"
|
self.status == "success"
|
||||||
@ -89,6 +101,11 @@ impl MinioService {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get bucket name prefixed by mc alias name
|
||||||
|
fn absolute_bucket_name(&self, name: &str) -> String {
|
||||||
|
format!("{}/{name}", MC_ALIAS_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
/// Execute a minio mc command
|
/// Execute a minio mc command
|
||||||
async fn exec_mc_cmd<A>(&self, args: &[&str]) -> anyhow::Result<Vec<A>>
|
async fn exec_mc_cmd<A>(&self, args: &[&str]) -> anyhow::Result<Vec<A>>
|
||||||
where
|
where
|
||||||
@ -179,10 +196,6 @@ impl MinioService {
|
|||||||
let bucket_name = format!("{}/{}", MC_ALIAS_NAME, b.name);
|
let bucket_name = format!("{}/{}", MC_ALIAS_NAME, b.name);
|
||||||
let mut args = ["mb", bucket_name.as_str()].to_vec();
|
let mut args = ["mb", bucket_name.as_str()].to_vec();
|
||||||
|
|
||||||
if b.versioning {
|
|
||||||
args.push("--with-versioning");
|
|
||||||
}
|
|
||||||
|
|
||||||
if b.lock || b.retention.is_some() {
|
if b.lock || b.retention.is_some() {
|
||||||
args.push("--with-lock");
|
args.push("--with-lock");
|
||||||
}
|
}
|
||||||
@ -192,6 +205,8 @@ impl MinioService {
|
|||||||
return Err(MinioError::MakeBucketFailed.into());
|
return Err(MinioError::MakeBucketFailed.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.bucket_set_versioning(&b.name, b.versioning).await?;
|
||||||
|
|
||||||
// Enable anonymous access, eg. public hosting
|
// Enable anonymous access, eg. public hosting
|
||||||
if b.anonymous_read_access {
|
if b.anonymous_read_access {
|
||||||
let target = format!("{}/*", bucket_name);
|
let target = format!("{}/*", bucket_name);
|
||||||
@ -249,6 +264,38 @@ impl MinioService {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set bucket versioning
|
||||||
|
pub async fn bucket_set_versioning(&self, bucket: &str, enable: bool) -> anyhow::Result<()> {
|
||||||
|
let bucket_name = self.absolute_bucket_name(bucket);
|
||||||
|
|
||||||
|
let res = self
|
||||||
|
.exec_mc_cmd::<BasicMinioResult>(&[
|
||||||
|
"version",
|
||||||
|
match enable {
|
||||||
|
true => "enable",
|
||||||
|
false => "suspend",
|
||||||
|
},
|
||||||
|
bucket_name.as_str(),
|
||||||
|
])
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if res.get(0).map(|r| r.success()) != Some(true) {
|
||||||
|
return Err(MinioError::SetQuotaFailed.into());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get current bucket versioning status
|
||||||
|
pub async fn bucket_get_versioning(&self, bucket_name: &str) -> anyhow::Result<bool> {
|
||||||
|
let bucket_name = self.absolute_bucket_name(bucket_name);
|
||||||
|
Ok(self.exec_mc_cmd::<MinioGetVersioningResult>(&["version", "info", bucket_name.as_str()])
|
||||||
|
.await?
|
||||||
|
.remove(0)
|
||||||
|
.versioning
|
||||||
|
.map(|v| v.status.to_lowercase().eq("enabled"))
|
||||||
|
.unwrap_or_default())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -256,6 +303,8 @@ mod test {
|
|||||||
use crate::crd::MinioBucketSpec;
|
use crate::crd::MinioBucketSpec;
|
||||||
use crate::minio_test_server::MinioTestServer;
|
use crate::minio_test_server::MinioTestServer;
|
||||||
|
|
||||||
|
const TEST_BUCKET_NAME: &str = "mybucket";
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn list_buckets_empty_instance() {
|
async fn list_buckets_empty_instance() {
|
||||||
let srv = MinioTestServer::start().await.unwrap();
|
let srv = MinioTestServer::start().await.unwrap();
|
||||||
@ -278,7 +327,7 @@ mod test {
|
|||||||
service
|
service
|
||||||
.create_bucket(&MinioBucketSpec {
|
.create_bucket(&MinioBucketSpec {
|
||||||
instance: "".to_string(),
|
instance: "".to_string(),
|
||||||
name: "mybucket".to_string(),
|
name: TEST_BUCKET_NAME.to_string(),
|
||||||
secret: "".to_string(),
|
secret: "".to_string(),
|
||||||
anonymous_read_access: false,
|
anonymous_read_access: false,
|
||||||
versioning: false,
|
versioning: false,
|
||||||
@ -288,13 +337,148 @@ mod test {
|
|||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(service.bucket_exists("mybucket").await.unwrap());
|
assert!(service.bucket_exists(TEST_BUCKET_NAME).await.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn bucket_creation_with_anonymous_access() {
|
||||||
|
let _ = env_logger::builder().is_test(true).try_init();
|
||||||
|
|
||||||
|
let srv = MinioTestServer::start().await.unwrap();
|
||||||
|
let service = srv.as_service();
|
||||||
|
service
|
||||||
|
.create_bucket(&MinioBucketSpec {
|
||||||
|
instance: "".to_string(),
|
||||||
|
name: TEST_BUCKET_NAME.to_string(),
|
||||||
|
secret: "".to_string(),
|
||||||
|
anonymous_read_access: true,
|
||||||
|
versioning: false,
|
||||||
|
quota: None,
|
||||||
|
lock: false,
|
||||||
|
retention: None,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(service.bucket_exists(TEST_BUCKET_NAME).await.unwrap());
|
||||||
|
assert_eq!(
|
||||||
|
reqwest::get(format!("{}/{}/test", service.hostname, TEST_BUCKET_NAME))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.status()
|
||||||
|
.as_u16(),
|
||||||
|
404
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn bucket_creation_without_anonymous_access() {
|
||||||
|
let _ = env_logger::builder().is_test(true).try_init();
|
||||||
|
|
||||||
|
let srv = MinioTestServer::start().await.unwrap();
|
||||||
|
let service = srv.as_service();
|
||||||
|
service
|
||||||
|
.create_bucket(&MinioBucketSpec {
|
||||||
|
instance: "".to_string(),
|
||||||
|
name: TEST_BUCKET_NAME.to_string(),
|
||||||
|
secret: "".to_string(),
|
||||||
|
anonymous_read_access: false,
|
||||||
|
versioning: false,
|
||||||
|
quota: None,
|
||||||
|
lock: false,
|
||||||
|
retention: None,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(service.bucket_exists(TEST_BUCKET_NAME).await.unwrap());
|
||||||
|
assert_eq!(
|
||||||
|
reqwest::get(format!("{}/{}/test", service.hostname, TEST_BUCKET_NAME))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.status()
|
||||||
|
.as_u16(),
|
||||||
|
403
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// With versioning
|
||||||
|
#[tokio::test]
|
||||||
|
async fn bucket_with_versioning() {
|
||||||
|
let _ = env_logger::builder().is_test(true).try_init();
|
||||||
|
|
||||||
|
let srv = MinioTestServer::start().await.unwrap();
|
||||||
|
let service = srv.as_service();
|
||||||
|
service
|
||||||
|
.create_bucket(&MinioBucketSpec {
|
||||||
|
instance: "".to_string(),
|
||||||
|
name: TEST_BUCKET_NAME.to_string(),
|
||||||
|
secret: "".to_string(),
|
||||||
|
anonymous_read_access: false,
|
||||||
|
versioning: true,
|
||||||
|
quota: None,
|
||||||
|
lock: false,
|
||||||
|
retention: None,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(service.bucket_exists(TEST_BUCKET_NAME).await.unwrap());
|
||||||
|
assert!(service.bucket_get_versioning(TEST_BUCKET_NAME).await.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn bucket_without_versioning() {
|
||||||
|
let _ = env_logger::builder().is_test(true).try_init();
|
||||||
|
|
||||||
|
let srv = MinioTestServer::start().await.unwrap();
|
||||||
|
let service = srv.as_service();
|
||||||
|
service
|
||||||
|
.create_bucket(&MinioBucketSpec {
|
||||||
|
instance: "".to_string(),
|
||||||
|
name: TEST_BUCKET_NAME.to_string(),
|
||||||
|
secret: "".to_string(),
|
||||||
|
anonymous_read_access: false,
|
||||||
|
versioning: false,
|
||||||
|
quota: None,
|
||||||
|
lock: false,
|
||||||
|
retention: None,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(service.bucket_exists(TEST_BUCKET_NAME).await.unwrap());
|
||||||
|
assert!(!service.bucket_get_versioning(TEST_BUCKET_NAME).await.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn change_versioning() {
|
||||||
|
let _ = env_logger::builder().is_test(true).try_init();
|
||||||
|
|
||||||
|
let srv = MinioTestServer::start().await.unwrap();
|
||||||
|
let service = srv.as_service();
|
||||||
|
service
|
||||||
|
.create_bucket(&MinioBucketSpec {
|
||||||
|
instance: "".to_string(),
|
||||||
|
name: TEST_BUCKET_NAME.to_string(),
|
||||||
|
secret: "".to_string(),
|
||||||
|
anonymous_read_access: false,
|
||||||
|
versioning: false,
|
||||||
|
quota: None,
|
||||||
|
lock: false,
|
||||||
|
retention: None,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(service.bucket_exists(TEST_BUCKET_NAME).await.unwrap());
|
||||||
|
assert!(!service.bucket_get_versioning(TEST_BUCKET_NAME).await.unwrap());
|
||||||
|
service.bucket_set_versioning(TEST_BUCKET_NAME, true).await.unwrap();
|
||||||
|
assert!(service.bucket_get_versioning(TEST_BUCKET_NAME).await.unwrap());
|
||||||
|
service.bucket_set_versioning(TEST_BUCKET_NAME, false).await.unwrap();
|
||||||
|
assert!(!service.bucket_get_versioning(TEST_BUCKET_NAME).await.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO : with anonymous access
|
|
||||||
// TODO : without anonymous access
|
|
||||||
// TODO : with versioning
|
|
||||||
// TODO : without versioning
|
|
||||||
// TODO : with quota
|
// TODO : with quota
|
||||||
// TODO : without quota
|
// TODO : without quota
|
||||||
// TODO : with lock
|
// TODO : with lock
|
||||||
|
Loading…
Reference in New Issue
Block a user