mirror of
https://codeberg.org/icewind/haze.git
synced 2026-06-04 01:24:09 +02:00
284 lines
9.4 KiB
Rust
284 lines
9.4 KiB
Rust
use crate::cloud::CloudOptions;
|
|
use crate::config::HazeConfig;
|
|
use crate::exec::exec;
|
|
use crate::image::pull_image;
|
|
use crate::service::{split_cmnd, ServiceTrait};
|
|
use crate::Result;
|
|
use bollard::models::{
|
|
ContainerCreateBody, ContainerState, EndpointSettings, HostConfig, NetworkingConfig,
|
|
};
|
|
use bollard::query_parameters::CreateContainerOptions;
|
|
use bollard::Docker;
|
|
use maplit::hashmap;
|
|
use miette::{IntoDiagnostic, WrapErr};
|
|
use serde_json::Value;
|
|
use std::collections::HashMap;
|
|
use std::fs::{create_dir_all, write};
|
|
|
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
pub enum ObjectStore {
|
|
S3,
|
|
S3s,
|
|
S3m,
|
|
S3mb,
|
|
Azure,
|
|
}
|
|
|
|
impl ObjectStore {
|
|
fn image(&self) -> &str {
|
|
match self {
|
|
ObjectStore::S3 | ObjectStore::S3m | ObjectStore::S3mb | ObjectStore::S3s => {
|
|
"minio/minio:RELEASE.2024-07-16T23-46-41Z"
|
|
}
|
|
ObjectStore::Azure => "arafato/azurite:2.6.5",
|
|
}
|
|
}
|
|
|
|
fn self_env(&self) -> Vec<&str> {
|
|
match self {
|
|
ObjectStore::S3 | ObjectStore::S3m | ObjectStore::S3mb | ObjectStore::S3s => {
|
|
vec!["MINIO_ACCESS_KEY=minio", "MINIO_SECRET_KEY=minio123"]
|
|
}
|
|
ObjectStore::Azure => vec![],
|
|
}
|
|
}
|
|
|
|
fn host_name(&self) -> &str {
|
|
match self {
|
|
ObjectStore::S3 | ObjectStore::S3m | ObjectStore::S3mb | ObjectStore::S3s => "s3",
|
|
ObjectStore::Azure => "azure",
|
|
}
|
|
}
|
|
|
|
fn args(&self) -> &[&str] {
|
|
match self {
|
|
ObjectStore::S3 | ObjectStore::S3m | ObjectStore::S3mb | ObjectStore::S3s => {
|
|
&["server", "/data"]
|
|
}
|
|
_ => &[],
|
|
}
|
|
}
|
|
|
|
fn volumes(&self, config: &HazeConfig) -> Option<Vec<String>> {
|
|
match self {
|
|
ObjectStore::S3s => {
|
|
let cert_dir = config.work_dir.join("certificates/s3");
|
|
create_dir_all(&cert_dir)
|
|
.into_diagnostic()
|
|
.wrap_err("Failed to create redis certificate directory")
|
|
.unwrap();
|
|
let s3_cert_path = config.work_dir.join("certificates/s3/public.crt");
|
|
let s3_key_path = config.work_dir.join("certificates/s3/private.key");
|
|
if !s3_cert_path.exists() {
|
|
write(
|
|
&s3_cert_path,
|
|
include_bytes!("../../certificates/s3/public.crt"),
|
|
)
|
|
.into_diagnostic()
|
|
.wrap_err("Failed to write s3 certificate")
|
|
.unwrap();
|
|
}
|
|
if !s3_key_path.exists() {
|
|
write(
|
|
&s3_key_path,
|
|
include_bytes!("../../certificates/s3/private.key"),
|
|
)
|
|
.into_diagnostic()
|
|
.wrap_err("Failed to write s3 key")
|
|
.unwrap();
|
|
}
|
|
|
|
Some(vec![format!("{cert_dir}:/root/.minio/certs:ro")])
|
|
}
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl ServiceTrait for ObjectStore {
|
|
fn name(&self) -> &str {
|
|
match self {
|
|
ObjectStore::S3 => "s3",
|
|
ObjectStore::S3s => "s3s",
|
|
ObjectStore::S3m => "s3m",
|
|
ObjectStore::S3mb => "s3mb",
|
|
ObjectStore::Azure => "azure",
|
|
}
|
|
}
|
|
|
|
fn env(&self) -> &[&str] {
|
|
match self {
|
|
ObjectStore::S3 => &["S3=1"],
|
|
ObjectStore::S3s => &["S3S=1"],
|
|
ObjectStore::S3m => &["S3M=1"],
|
|
ObjectStore::S3mb => &["S3MB =1"],
|
|
ObjectStore::Azure => &["AZURE=1"],
|
|
}
|
|
}
|
|
|
|
async fn spawn(
|
|
&self,
|
|
docker: &Docker,
|
|
cloud_id: &str,
|
|
network: &str,
|
|
config: &HazeConfig,
|
|
_options: &CloudOptions,
|
|
) -> Result<Vec<String>> {
|
|
pull_image(docker, self.image()).await?;
|
|
let options = Some(CreateContainerOptions {
|
|
name: Some(format!("{}-object", cloud_id)),
|
|
..CreateContainerOptions::default()
|
|
});
|
|
let config = ContainerCreateBody {
|
|
image: Some(self.image().into()),
|
|
env: Some(self.self_env().into_iter().map(String::from).collect()),
|
|
host_config: Some(HostConfig {
|
|
network_mode: Some(network.to_string()),
|
|
binds: self.volumes(config),
|
|
..Default::default()
|
|
}),
|
|
labels: Some(hashmap! {
|
|
"haze-type".into() => self.name().into(),
|
|
"haze-cloud-id".into() => cloud_id.into(),
|
|
}),
|
|
cmd: Some(self.args().iter().copied().map(String::from).collect()),
|
|
networking_config: Some(NetworkingConfig {
|
|
endpoints_config: Some(hashmap! {
|
|
network.into() => EndpointSettings {
|
|
aliases: Some(vec![self.host_name().to_string()]),
|
|
..Default::default()
|
|
}
|
|
}),
|
|
}),
|
|
..Default::default()
|
|
};
|
|
let id = docker
|
|
.create_container(options, config)
|
|
.await
|
|
.into_diagnostic()?
|
|
.id;
|
|
docker.start_container(&id, None).await.into_diagnostic()?;
|
|
Ok(vec![id])
|
|
}
|
|
|
|
async fn is_healthy(
|
|
&self,
|
|
docker: &Docker,
|
|
cloud_id: &str,
|
|
_options: &CloudOptions,
|
|
) -> Result<bool> {
|
|
if !self.is_running(docker, cloud_id).await? {
|
|
return Ok(false);
|
|
}
|
|
match self {
|
|
ObjectStore::S3 | ObjectStore::S3mb => {
|
|
let mut output = Vec::new();
|
|
let exit = exec(
|
|
docker,
|
|
format!("{}-object", cloud_id),
|
|
"root",
|
|
vec!["curl", "localhost:9000/minio/health/ready"],
|
|
Vec::<String>::default(),
|
|
Some(&mut output),
|
|
)
|
|
.await?;
|
|
Ok(exit.is_ok())
|
|
}
|
|
_ => {
|
|
let info = docker
|
|
.inspect_container(&self.container_name(cloud_id).unwrap(), None)
|
|
.await
|
|
.into_diagnostic()?;
|
|
Ok(matches!(
|
|
info.state,
|
|
Some(ContainerState {
|
|
running: Some(true),
|
|
..
|
|
})
|
|
))
|
|
}
|
|
}
|
|
}
|
|
|
|
fn container_name(&self, cloud_id: &str) -> Option<String> {
|
|
Some(format!("{}-object", cloud_id))
|
|
}
|
|
|
|
fn apps(&self) -> &'static [&'static str] {
|
|
&["files_external"]
|
|
}
|
|
|
|
fn config(
|
|
&self,
|
|
_docker: &Docker,
|
|
_cloud_id: &str,
|
|
_config: &HazeConfig,
|
|
) -> Result<HashMap<String, Value>> {
|
|
match self {
|
|
ObjectStore::S3s => Ok(hashmap![
|
|
"default_certificates_bundle_path".into() => Value::String("/var/www/html/data/ca-bundle.crt".into()),
|
|
]),
|
|
_ => Ok(HashMap::default()),
|
|
}
|
|
}
|
|
|
|
fn pre_setup(
|
|
&self,
|
|
_docker: &Docker,
|
|
_cloud_id: &str,
|
|
_config: &HazeConfig,
|
|
) -> Result<Vec<Vec<String>>> {
|
|
match self {
|
|
ObjectStore::S3s => Ok(vec![
|
|
vec!["mkdir".into(), "-p".into(), "/var/www/html/data".into()],
|
|
vec![
|
|
"sh".into(),
|
|
"-c".into(),
|
|
"cat /var/www/html/resources/config/ca-bundle.crt /certificates/s3/public.crt > /var/www/html/data/ca-bundle.crt".into(),
|
|
],
|
|
]),
|
|
_ => Ok(Vec::new()),
|
|
}
|
|
}
|
|
|
|
async fn post_setup(
|
|
&self,
|
|
_docker: &Docker,
|
|
_cloud_id: &str,
|
|
_config: &HazeConfig,
|
|
) -> Result<Vec<Vec<String>>> {
|
|
match self {
|
|
ObjectStore::S3 => Ok(vec![
|
|
split_cmnd("occ files_external:create s3 amazons3 amazons3::accesskey"),
|
|
split_cmnd("occ files_external:config 1 bucket ext"),
|
|
split_cmnd("occ files_external:config 1 hostname s3"),
|
|
split_cmnd("occ files_external:config 1 port 9000"),
|
|
split_cmnd("occ files_external:config 1 use_ssl false"),
|
|
split_cmnd("occ files_external:config 1 use_path_style true"),
|
|
split_cmnd("occ files_external:config 1 key minio"),
|
|
split_cmnd("occ files_external:config 1 secret minio123"),
|
|
split_cmnd("mc alias set s3 http://s3:9000 minio minio123"),
|
|
]),
|
|
// ObjectStore::S3s => Ok(vec![
|
|
// "occ files_external:create s3 amazons3 amazons3::accesskey".into(),
|
|
// "occ files_external:config 1 bucket ext".into(),
|
|
// "occ files_external:config 1 hostname s3".into(),
|
|
// "occ files_external:config 1 port 9000".into(),
|
|
// "occ files_external:config 1 use_ssl true".into(),
|
|
// "occ files_external:config 1 use_path_style true".into(),
|
|
// "occ files_external:config 1 key minio".into(),
|
|
// "occ files_external:config 1 secret minio123".into(),
|
|
// "mc alias set s3 https://s3:9000 minio minio123".into(),
|
|
// ]),
|
|
_ => Ok(Vec::new()),
|
|
}
|
|
}
|
|
|
|
fn proxy_port(&self) -> u16 {
|
|
match self {
|
|
ObjectStore::S3 | ObjectStore::S3m | ObjectStore::S3mb | ObjectStore::S3s => 9000,
|
|
ObjectStore::Azure => 10000,
|
|
}
|
|
}
|
|
}
|