mirror of
https://codeberg.org/icewind/haze.git
synced 2026-06-03 17:14:08 +02:00
split services into seperate files
This commit is contained in:
parent
b9bb8190cd
commit
3cac4e4679
9 changed files with 434 additions and 463 deletions
25
Cargo.lock
generated
25
Cargo.lock
generated
|
|
@ -32,6 +32,17 @@ version = "1.0.40"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
|
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-trait"
|
||||||
|
version = "0.1.51"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
|
@ -289,6 +300,18 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enum_dispatch"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd53b3fde38a39a06b2e66dc282f3e86191e53bd04cc499929c15742beae3df8"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "eyre"
|
name = "eyre"
|
||||||
version = "0.6.5"
|
version = "0.6.5"
|
||||||
|
|
@ -440,10 +463,12 @@ checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
||||||
name = "haze"
|
name = "haze"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
"bollard",
|
"bollard",
|
||||||
"camino",
|
"camino",
|
||||||
"color-eyre",
|
"color-eyre",
|
||||||
"directories-next",
|
"directories-next",
|
||||||
|
"enum_dispatch",
|
||||||
"flate2",
|
"flate2",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"maplit",
|
"maplit",
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ petname = "1"
|
||||||
reqwest = { version = "0.11", default-features = false }
|
reqwest = { version = "0.11", default-features = false }
|
||||||
tar = "0.4"
|
tar = "0.4"
|
||||||
flate2 = "1"
|
flate2 = "1"
|
||||||
|
async-trait = "0.1"
|
||||||
|
enum_dispatch = "0.3"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|
@ -4,6 +4,7 @@ use crate::exec::{exec, exec_tty, ExitCode};
|
||||||
use crate::mapping::{default_mappings, Mapping};
|
use crate::mapping::{default_mappings, Mapping};
|
||||||
use crate::php::PhpVersion;
|
use crate::php::PhpVersion;
|
||||||
use crate::service::Service;
|
use crate::service::Service;
|
||||||
|
use crate::service::ServiceTrait;
|
||||||
use bollard::container::{ListContainersOptions, RemoveContainerOptions};
|
use bollard::container::{ListContainersOptions, RemoveContainerOptions};
|
||||||
use bollard::models::ContainerState;
|
use bollard::models::ContainerState;
|
||||||
use bollard::network::CreateNetworkOptions;
|
use bollard::network::CreateNetworkOptions;
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,7 @@ pub async fn pull_image(docker: &Docker, image: &str) -> Result<()> {
|
||||||
|
|
||||||
let mut bars: HashMap<String, u16> = HashMap::new();
|
let mut bars: HashMap<String, u16> = HashMap::new();
|
||||||
|
|
||||||
let stdout = stdout();
|
let mut stdout = stdout();
|
||||||
let mut stdout = stdout.lock();
|
|
||||||
while let Some(info) = info_stream.next().await {
|
while let Some(info) = info_stream.next().await {
|
||||||
let info: CreateImageInfo = info?;
|
let info: CreateImageInfo = info?;
|
||||||
// dbg!(&info);
|
// dbg!(&info);
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use crate::cloud::{Cloud, CloudOptions};
|
||||||
use crate::config::HazeConfig;
|
use crate::config::HazeConfig;
|
||||||
use crate::exec::container_logs;
|
use crate::exec::container_logs;
|
||||||
use crate::service::Service;
|
use crate::service::Service;
|
||||||
|
use crate::service::ServiceTrait;
|
||||||
use bollard::Docker;
|
use bollard::Docker;
|
||||||
use color_eyre::{eyre::WrapErr, Result};
|
use color_eyre::{eyre::WrapErr, Result};
|
||||||
|
|
||||||
|
|
|
||||||
510
src/service.rs
510
src/service.rs
|
|
@ -1,61 +1,62 @@
|
||||||
use crate::exec::exec;
|
mod ldap;
|
||||||
use crate::image::pull_image;
|
mod objectstore;
|
||||||
use bollard::container::{Config, CreateContainerOptions, NetworkingConfig};
|
mod onlyoffice;
|
||||||
use bollard::models::{ContainerState, EndpointSettings, HostConfig};
|
|
||||||
|
use crate::service::ldap::{LDAPAdmin, LDAP};
|
||||||
|
use crate::service::objectstore::ObjectStore;
|
||||||
|
use crate::service::onlyoffice::OnlyOffice;
|
||||||
|
use bollard::models::ContainerState;
|
||||||
use bollard::Docker;
|
use bollard::Docker;
|
||||||
use color_eyre::{eyre::WrapErr, Report, Result};
|
use color_eyre::{eyre::WrapErr, Result};
|
||||||
use maplit::hashmap;
|
use enum_dispatch::enum_dispatch;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::time::{sleep, timeout};
|
use tokio::time::{sleep, timeout};
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
#[enum_dispatch(Service)]
|
||||||
|
pub trait ServiceTrait {
|
||||||
|
fn name(&self) -> &str;
|
||||||
|
|
||||||
|
fn env(&self) -> &[&str];
|
||||||
|
|
||||||
|
async fn spawn(&self, docker: &Docker, cloud_id: &str, network: &str) -> Result<String>;
|
||||||
|
|
||||||
|
async fn is_healthy(&self, docker: &Docker, cloud_id: &str) -> Result<bool> {
|
||||||
|
let info = docker
|
||||||
|
.inspect_container(&self.container_name(cloud_id), None)
|
||||||
|
.await?;
|
||||||
|
Ok(matches!(
|
||||||
|
info.state,
|
||||||
|
Some(ContainerState {
|
||||||
|
running: Some(true),
|
||||||
|
..
|
||||||
|
})
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn container_name(&self, cloud_id: &str) -> String;
|
||||||
|
|
||||||
|
async fn start_message(&self, docker: &Docker, cloud_id: &str) -> Result<Option<String>>;
|
||||||
|
|
||||||
|
fn apps(&self) -> &'static [&'static str];
|
||||||
|
|
||||||
|
async fn post_setup(&self, docker: &Docker, cloud_id: &str) -> Result<Vec<String>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[enum_dispatch]
|
||||||
|
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||||
pub enum Service {
|
pub enum Service {
|
||||||
ObjectStore(ObjectStore),
|
ObjectStore(ObjectStore),
|
||||||
Ldap(LDAP),
|
LDAP(LDAP),
|
||||||
LdapAdmin(LDAPAdmin),
|
LDAPAdmin(LDAPAdmin),
|
||||||
OnlyOffice(OnlyOffice),
|
OnlyOffice(OnlyOffice),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Service {
|
impl Service {
|
||||||
pub fn name(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Service::ObjectStore(store) => store.name(),
|
|
||||||
Service::Ldap(ldap) => ldap.name(),
|
|
||||||
Service::LdapAdmin(ldap_admin) => ldap_admin.name(),
|
|
||||||
Service::OnlyOffice(office) => office.name(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn env(&self) -> &[&str] {
|
|
||||||
match self {
|
|
||||||
Service::ObjectStore(store) => store.env(),
|
|
||||||
Service::Ldap(ldap) => ldap.env(),
|
|
||||||
Service::LdapAdmin(ldap_admin) => ldap_admin.env(),
|
|
||||||
Service::OnlyOffice(office) => office.env(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn spawn(&self, docker: &Docker, cloud_id: &str, network: &str) -> Result<String> {
|
|
||||||
match self {
|
|
||||||
Service::ObjectStore(store) => store.spawn(docker, cloud_id, network).await,
|
|
||||||
Service::Ldap(ldap) => ldap.spawn(docker, cloud_id, network).await,
|
|
||||||
Service::LdapAdmin(ldap_admin) => ldap_admin.spawn(docker, cloud_id, network).await,
|
|
||||||
Service::OnlyOffice(office) => office.spawn(docker, cloud_id, network).await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn is_healthy(&self, docker: &Docker, cloud_id: &str) -> Result<bool> {
|
|
||||||
match self {
|
|
||||||
Service::ObjectStore(store) => store.is_healthy(docker, cloud_id).await,
|
|
||||||
Service::Ldap(ldap) => ldap.is_healthy(docker, cloud_id).await,
|
|
||||||
Service::LdapAdmin(ldap_admin) => ldap_admin.is_healthy(docker, cloud_id).await,
|
|
||||||
Service::OnlyOffice(office) => office.is_healthy(docker, cloud_id).await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_type(ty: &str) -> Option<&'static [Self]> {
|
pub fn from_type(ty: &str) -> Option<&'static [Self]> {
|
||||||
match ty {
|
match ty {
|
||||||
"s3" => Some(&[Service::ObjectStore(ObjectStore::S3)]),
|
"s3" => Some(&[Service::ObjectStore(ObjectStore::S3)]),
|
||||||
"ldap" => Some(&[Service::Ldap(LDAP), Service::LdapAdmin(LDAPAdmin)]),
|
"ldap" => Some(&[Service::LDAP(LDAP), Service::LDAPAdmin(LDAPAdmin)]),
|
||||||
"onlyoffice" => Some(&[Service::OnlyOffice(OnlyOffice)]),
|
"onlyoffice" => Some(&[Service::OnlyOffice(OnlyOffice)]),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
@ -71,421 +72,4 @@ impl Service {
|
||||||
.await
|
.await
|
||||||
.wrap_err("Timeout after 30 seconds")?
|
.wrap_err("Timeout after 30 seconds")?
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn container_name(&self, cloud_id: &str) -> String {
|
|
||||||
match self {
|
|
||||||
Service::ObjectStore(store) => store.container_name(cloud_id),
|
|
||||||
Service::Ldap(ldap) => ldap.container_name(cloud_id),
|
|
||||||
Service::LdapAdmin(ldap_admin) => ldap_admin.container_name(cloud_id),
|
|
||||||
Service::OnlyOffice(office) => office.container_name(cloud_id),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn start_message(&self, docker: &Docker, cloud_id: &str) -> Result<Option<String>> {
|
|
||||||
match self {
|
|
||||||
Service::ObjectStore(store) => store.start_message(docker, cloud_id).await,
|
|
||||||
Service::Ldap(ldap) => ldap.start_message(docker, cloud_id).await,
|
|
||||||
Service::LdapAdmin(ldap_admin) => ldap_admin.start_message(docker, cloud_id).await,
|
|
||||||
Service::OnlyOffice(office) => office.start_message(docker, cloud_id).await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn apps(&self) -> &'static [&'static str] {
|
|
||||||
match self {
|
|
||||||
Service::ObjectStore(store) => store.apps(),
|
|
||||||
Service::Ldap(ldap) => ldap.apps(),
|
|
||||||
Service::LdapAdmin(ldap_admin) => ldap_admin.apps(),
|
|
||||||
Service::OnlyOffice(office) => office.apps(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn post_setup(&self, docker: &Docker, cloud_id: &str) -> Result<Vec<String>> {
|
|
||||||
match self {
|
|
||||||
Service::ObjectStore(store) => store.post_setup(docker, cloud_id).await,
|
|
||||||
Service::Ldap(ldap) => ldap.post_setup(docker, cloud_id).await,
|
|
||||||
Service::LdapAdmin(ldap_admin) => ldap_admin.post_setup(docker, cloud_id).await,
|
|
||||||
Service::OnlyOffice(office) => office.post_setup(docker, cloud_id).await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub enum ObjectStore {
|
|
||||||
S3,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ObjectStore {
|
|
||||||
fn image(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
ObjectStore::S3 => "localstack/localstack:0.12.7",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
ObjectStore::S3 => "s3",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn self_env(&self) -> Vec<&str> {
|
|
||||||
match self {
|
|
||||||
ObjectStore::S3 => vec!["DEBUG=1", "SERVICES=s3"],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn env(&self) -> &[&str] {
|
|
||||||
match self {
|
|
||||||
ObjectStore::S3 => &["S3=1"],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn spawn(&self, docker: &Docker, cloud_id: &str, network: &str) -> Result<String> {
|
|
||||||
pull_image(docker, self.image()).await?;
|
|
||||||
let options = Some(CreateContainerOptions {
|
|
||||||
name: format!("{}-object", cloud_id),
|
|
||||||
});
|
|
||||||
let config = Config {
|
|
||||||
image: Some(self.image()),
|
|
||||||
env: Some(self.self_env()),
|
|
||||||
host_config: Some(HostConfig {
|
|
||||||
network_mode: Some(network.to_string()),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
labels: Some(hashmap! {
|
|
||||||
"haze-type" => self.name(),
|
|
||||||
"haze-cloud-id" => cloud_id
|
|
||||||
}),
|
|
||||||
networking_config: Some(NetworkingConfig {
|
|
||||||
endpoints_config: hashmap! {
|
|
||||||
network => EndpointSettings {
|
|
||||||
aliases: Some(vec![self.name().to_string()]),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let id = docker.create_container(options, config).await?.id;
|
|
||||||
docker.start_container::<String>(&id, None).await?;
|
|
||||||
Ok(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn is_healthy(&self, docker: &Docker, cloud_id: &str) -> Result<bool> {
|
|
||||||
let mut output = Vec::new();
|
|
||||||
exec(
|
|
||||||
docker,
|
|
||||||
format!("{}-object", cloud_id),
|
|
||||||
"root",
|
|
||||||
vec!["curl", "localhost:4566/health"],
|
|
||||||
vec![],
|
|
||||||
Some(&mut output),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
let output = String::from_utf8(output)?;
|
|
||||||
Ok(output.contains(r#""s3": "running""#))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn container_name(&self, cloud_id: &str) -> String {
|
|
||||||
format!("{}-object", cloud_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn start_message(&self, _docker: &Docker, _cloud_id: &str) -> Result<Option<String>> {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apps(&self) -> &'static [&'static str] {
|
|
||||||
&["files_external"]
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn post_setup(&self, _docker: &Docker, _cloud_id: &str) -> Result<Vec<String>> {
|
|
||||||
Ok(Vec::new())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub struct LDAP;
|
|
||||||
|
|
||||||
impl LDAP {
|
|
||||||
fn image(&self) -> &str {
|
|
||||||
"icewind1991/haze-ldap"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"ldap"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn self_env(&self) -> Vec<&str> {
|
|
||||||
vec!["LDAP_ADMIN_PASSWORD=haze"]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn env(&self) -> &[&str] {
|
|
||||||
&["LDAP=1"]
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn spawn(&self, docker: &Docker, cloud_id: &str, network: &str) -> Result<String> {
|
|
||||||
pull_image(docker, self.image()).await?;
|
|
||||||
let options = Some(CreateContainerOptions {
|
|
||||||
name: self.container_name(cloud_id),
|
|
||||||
});
|
|
||||||
let config = Config {
|
|
||||||
image: Some(self.image()),
|
|
||||||
env: Some(self.self_env()),
|
|
||||||
host_config: Some(HostConfig {
|
|
||||||
network_mode: Some(network.to_string()),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
labels: Some(hashmap! {
|
|
||||||
"haze-type" => self.name(),
|
|
||||||
"haze-cloud-id" => cloud_id
|
|
||||||
}),
|
|
||||||
networking_config: Some(NetworkingConfig {
|
|
||||||
endpoints_config: hashmap! {
|
|
||||||
network => EndpointSettings {
|
|
||||||
aliases: Some(vec![self.name().to_string()]),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
cmd: Some(vec!["--copy-service"]),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let id = docker.create_container(options, config).await?.id;
|
|
||||||
docker.start_container::<String>(&id, None).await?;
|
|
||||||
Ok(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn is_healthy(&self, _docker: &Docker, _cloud_id: &str) -> Result<bool> {
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn container_name(&self, cloud_id: &str) -> String {
|
|
||||||
format!("{}-ldap", cloud_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn start_message(&self, _docker: &Docker, _cloud_id: &str) -> Result<Option<String>> {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apps(&self) -> &'static [&'static str] {
|
|
||||||
&["user_ldap"]
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn post_setup(&self, _docker: &Docker, _cloud_id: &str) -> Result<Vec<String>> {
|
|
||||||
Ok(Vec::new())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub struct LDAPAdmin;
|
|
||||||
|
|
||||||
impl LDAPAdmin {
|
|
||||||
fn image(&self) -> &str {
|
|
||||||
"osixia/phpldapadmin"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"ldap-admin"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn self_env(&self) -> Vec<&str> {
|
|
||||||
vec!["PHPLDAPADMIN_LDAP_HOSTS=ldap"]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn env(&self) -> &[&str] {
|
|
||||||
&[]
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn spawn(&self, docker: &Docker, cloud_id: &str, network: &str) -> Result<String> {
|
|
||||||
pull_image(docker, self.image()).await?;
|
|
||||||
let options = Some(CreateContainerOptions {
|
|
||||||
name: self.container_name(cloud_id),
|
|
||||||
});
|
|
||||||
let config = Config {
|
|
||||||
image: Some(self.image()),
|
|
||||||
env: Some(self.self_env()),
|
|
||||||
host_config: Some(HostConfig {
|
|
||||||
network_mode: Some(network.to_string()),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
labels: Some(hashmap! {
|
|
||||||
"haze-type" => self.name(),
|
|
||||||
"haze-cloud-id" => cloud_id
|
|
||||||
}),
|
|
||||||
networking_config: Some(NetworkingConfig {
|
|
||||||
endpoints_config: hashmap! {
|
|
||||||
network => EndpointSettings {
|
|
||||||
aliases: Some(vec![self.name().to_string()]),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
cmd: Some(vec!["--copy-service"]),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let id = docker.create_container(options, config).await?.id;
|
|
||||||
docker.start_container::<String>(&id, None).await?;
|
|
||||||
Ok(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn is_healthy(&self, docker: &Docker, cloud_id: &str) -> Result<bool> {
|
|
||||||
let info = docker
|
|
||||||
.inspect_container(&self.container_name(cloud_id), None)
|
|
||||||
.await?;
|
|
||||||
Ok(matches!(
|
|
||||||
info.state,
|
|
||||||
Some(ContainerState {
|
|
||||||
running: Some(true),
|
|
||||||
..
|
|
||||||
})
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn container_name(&self, cloud_id: &str) -> String {
|
|
||||||
format!("{}-ldap-admin", cloud_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn start_message(&self, docker: &Docker, cloud_id: &str) -> Result<Option<String>> {
|
|
||||||
let info = docker
|
|
||||||
.inspect_container(&self.container_name(cloud_id), None)
|
|
||||||
.await?;
|
|
||||||
let ip = if matches!(
|
|
||||||
info.state,
|
|
||||||
Some(ContainerState {
|
|
||||||
running: Some(true),
|
|
||||||
..
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
info.network_settings
|
|
||||||
.unwrap()
|
|
||||||
.networks
|
|
||||||
.unwrap()
|
|
||||||
.values()
|
|
||||||
.next()
|
|
||||||
.unwrap()
|
|
||||||
.ip_address
|
|
||||||
.clone()
|
|
||||||
.unwrap()
|
|
||||||
} else {
|
|
||||||
return Err(Report::msg("ldap admin not started"));
|
|
||||||
};
|
|
||||||
Ok(Some(format!(
|
|
||||||
"Ldap admin running at: https://{} with 'cn=admin,dc=example,dc=org' and password 'haze'",
|
|
||||||
ip
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn post_setup(&self, _docker: &Docker, _cloud_id: &str) -> Result<Vec<String>> {
|
|
||||||
Ok(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apps(&self) -> &'static [&'static str] {
|
|
||||||
&[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub struct OnlyOffice;
|
|
||||||
|
|
||||||
impl OnlyOffice {
|
|
||||||
fn image(&self) -> &str {
|
|
||||||
"onlyoffice/documentserver"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"onlyoffice"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn self_env(&self) -> Vec<&str> {
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn env(&self) -> &[&str] {
|
|
||||||
&[]
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn spawn(&self, docker: &Docker, cloud_id: &str, network: &str) -> Result<String> {
|
|
||||||
pull_image(docker, self.image()).await?;
|
|
||||||
let options = Some(CreateContainerOptions {
|
|
||||||
name: self.container_name(cloud_id),
|
|
||||||
});
|
|
||||||
let config = Config {
|
|
||||||
image: Some(self.image()),
|
|
||||||
env: Some(self.self_env()),
|
|
||||||
host_config: Some(HostConfig {
|
|
||||||
network_mode: Some(network.to_string()),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
labels: Some(hashmap! {
|
|
||||||
"haze-type" => self.name(),
|
|
||||||
"haze-cloud-id" => cloud_id
|
|
||||||
}),
|
|
||||||
networking_config: Some(NetworkingConfig {
|
|
||||||
endpoints_config: hashmap! {
|
|
||||||
network => EndpointSettings {
|
|
||||||
aliases: Some(vec![self.name().to_string()]),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let id = docker.create_container(options, config).await?.id;
|
|
||||||
docker.start_container::<String>(&id, None).await?;
|
|
||||||
Ok(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn is_healthy(&self, docker: &Docker, cloud_id: &str) -> Result<bool> {
|
|
||||||
let info = docker
|
|
||||||
.inspect_container(&self.container_name(cloud_id), None)
|
|
||||||
.await?;
|
|
||||||
Ok(matches!(
|
|
||||||
info.state,
|
|
||||||
Some(ContainerState {
|
|
||||||
running: Some(true),
|
|
||||||
..
|
|
||||||
})
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn container_name(&self, cloud_id: &str) -> String {
|
|
||||||
format!("{}-onlyoffice", cloud_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn start_message(&self, _docker: &Docker, _cloud_id: &str) -> Result<Option<String>> {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apps(&self) -> &'static [&'static str] {
|
|
||||||
&["onlyoffice"]
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn post_setup(&self, docker: &Docker, cloud_id: &str) -> Result<Vec<String>> {
|
|
||||||
let info = docker
|
|
||||||
.inspect_container(&self.container_name(cloud_id), None)
|
|
||||||
.await?;
|
|
||||||
let ip = if matches!(
|
|
||||||
info.state,
|
|
||||||
Some(ContainerState {
|
|
||||||
running: Some(true),
|
|
||||||
..
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
info.network_settings
|
|
||||||
.unwrap()
|
|
||||||
.networks
|
|
||||||
.unwrap()
|
|
||||||
.values()
|
|
||||||
.next()
|
|
||||||
.unwrap()
|
|
||||||
.ip_address
|
|
||||||
.clone()
|
|
||||||
.unwrap()
|
|
||||||
} else {
|
|
||||||
return Err(Report::msg("onlyoffice not started"));
|
|
||||||
};
|
|
||||||
Ok(vec![format!(
|
|
||||||
"occ config:app:set onlyoffice DocumentServerUrl --value http://{}/",
|
|
||||||
ip
|
|
||||||
)])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
160
src/service/ldap.rs
Normal file
160
src/service/ldap.rs
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
use crate::image::pull_image;
|
||||||
|
use crate::service::ServiceTrait;
|
||||||
|
use crate::Result;
|
||||||
|
use bollard::container::{Config, CreateContainerOptions, NetworkingConfig};
|
||||||
|
use bollard::models::{ContainerState, EndpointSettings, HostConfig};
|
||||||
|
use bollard::Docker;
|
||||||
|
use color_eyre::Report;
|
||||||
|
use maplit::hashmap;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct LDAP;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl ServiceTrait for LDAP {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"ldap"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn env(&self) -> &[&str] {
|
||||||
|
&["LDAP=1"]
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn spawn(&self, docker: &Docker, cloud_id: &str, network: &str) -> Result<String> {
|
||||||
|
let image = "icewind1991/haze-ldap";
|
||||||
|
pull_image(docker, image).await?;
|
||||||
|
let options = Some(CreateContainerOptions {
|
||||||
|
name: self.container_name(cloud_id),
|
||||||
|
});
|
||||||
|
let config = Config {
|
||||||
|
image: Some(image),
|
||||||
|
env: Some(vec!["LDAP_ADMIN_PASSWORD=haze"]),
|
||||||
|
host_config: Some(HostConfig {
|
||||||
|
network_mode: Some(network.to_string()),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
labels: Some(hashmap! {
|
||||||
|
"haze-type" => self.name(),
|
||||||
|
"haze-cloud-id" => cloud_id
|
||||||
|
}),
|
||||||
|
networking_config: Some(NetworkingConfig {
|
||||||
|
endpoints_config: hashmap! {
|
||||||
|
network => EndpointSettings {
|
||||||
|
aliases: Some(vec![self.name().to_string()]),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
cmd: Some(vec!["--copy-service"]),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let id = docker.create_container(options, config).await?.id;
|
||||||
|
docker.start_container::<String>(&id, None).await?;
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn container_name(&self, cloud_id: &str) -> String {
|
||||||
|
format!("{}-ldap", cloud_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn start_message(&self, _docker: &Docker, _cloud_id: &str) -> Result<Option<String>> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apps(&self) -> &'static [&'static str] {
|
||||||
|
&["user_ldap"]
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn post_setup(&self, _docker: &Docker, _cloud_id: &str) -> Result<Vec<String>> {
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct LDAPAdmin;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl ServiceTrait for LDAPAdmin {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"ldap-admin"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn env(&self) -> &[&str] {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn spawn(&self, docker: &Docker, cloud_id: &str, network: &str) -> Result<String> {
|
||||||
|
let image = "osixia/phpldapadmin";
|
||||||
|
pull_image(docker, image).await?;
|
||||||
|
let options = Some(CreateContainerOptions {
|
||||||
|
name: self.container_name(cloud_id),
|
||||||
|
});
|
||||||
|
let config = Config {
|
||||||
|
image: Some(image),
|
||||||
|
env: Some(vec!["PHPLDAPADMIN_LDAP_HOSTS=ldap"]),
|
||||||
|
host_config: Some(HostConfig {
|
||||||
|
network_mode: Some(network.to_string()),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
labels: Some(hashmap! {
|
||||||
|
"haze-type" => self.name(),
|
||||||
|
"haze-cloud-id" => cloud_id
|
||||||
|
}),
|
||||||
|
networking_config: Some(NetworkingConfig {
|
||||||
|
endpoints_config: hashmap! {
|
||||||
|
network => EndpointSettings {
|
||||||
|
aliases: Some(vec![self.name().to_string()]),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
cmd: Some(vec!["--copy-service"]),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let id = docker.create_container(options, config).await?.id;
|
||||||
|
docker.start_container::<String>(&id, None).await?;
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn container_name(&self, cloud_id: &str) -> String {
|
||||||
|
format!("{}-ldap-admin", cloud_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn start_message(&self, docker: &Docker, cloud_id: &str) -> Result<Option<String>> {
|
||||||
|
let info = docker
|
||||||
|
.inspect_container(&self.container_name(cloud_id), None)
|
||||||
|
.await?;
|
||||||
|
let ip = if matches!(
|
||||||
|
info.state,
|
||||||
|
Some(ContainerState {
|
||||||
|
running: Some(true),
|
||||||
|
..
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
info.network_settings
|
||||||
|
.unwrap()
|
||||||
|
.networks
|
||||||
|
.unwrap()
|
||||||
|
.values()
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.ip_address
|
||||||
|
.clone()
|
||||||
|
.unwrap()
|
||||||
|
} else {
|
||||||
|
return Err(Report::msg("ldap admin not started"));
|
||||||
|
};
|
||||||
|
Ok(Some(format!(
|
||||||
|
"Ldap admin running at: https://{} with 'cn=admin,dc=example,dc=org' and password 'haze'",
|
||||||
|
ip
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn post_setup(&self, _docker: &Docker, _cloud_id: &str) -> Result<Vec<String>> {
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apps(&self) -> &'static [&'static str] {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
}
|
||||||
104
src/service/objectstore.rs
Normal file
104
src/service/objectstore.rs
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
use crate::exec::exec;
|
||||||
|
use crate::image::pull_image;
|
||||||
|
use crate::service::ServiceTrait;
|
||||||
|
use crate::Result;
|
||||||
|
use bollard::container::{Config, CreateContainerOptions, NetworkingConfig};
|
||||||
|
use bollard::models::{EndpointSettings, HostConfig};
|
||||||
|
use bollard::Docker;
|
||||||
|
use maplit::hashmap;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub enum ObjectStore {
|
||||||
|
S3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectStore {
|
||||||
|
fn image(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
ObjectStore::S3 => "localstack/localstack:0.12.7",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn self_env(&self) -> Vec<&str> {
|
||||||
|
match self {
|
||||||
|
ObjectStore::S3 => vec!["DEBUG=1", "SERVICES=s3"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl ServiceTrait for ObjectStore {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
ObjectStore::S3 => "s3",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn env(&self) -> &[&str] {
|
||||||
|
match self {
|
||||||
|
ObjectStore::S3 => &["S3=1"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn spawn(&self, docker: &Docker, cloud_id: &str, network: &str) -> Result<String> {
|
||||||
|
pull_image(docker, self.image()).await?;
|
||||||
|
let options = Some(CreateContainerOptions {
|
||||||
|
name: format!("{}-object", cloud_id),
|
||||||
|
});
|
||||||
|
let config = Config {
|
||||||
|
image: Some(self.image()),
|
||||||
|
env: Some(self.self_env()),
|
||||||
|
host_config: Some(HostConfig {
|
||||||
|
network_mode: Some(network.to_string()),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
labels: Some(hashmap! {
|
||||||
|
"haze-type" => self.name(),
|
||||||
|
"haze-cloud-id" => cloud_id
|
||||||
|
}),
|
||||||
|
networking_config: Some(NetworkingConfig {
|
||||||
|
endpoints_config: hashmap! {
|
||||||
|
network => EndpointSettings {
|
||||||
|
aliases: Some(vec![self.name().to_string()]),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let id = docker.create_container(options, config).await?.id;
|
||||||
|
docker.start_container::<String>(&id, None).await?;
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_healthy(&self, docker: &Docker, cloud_id: &str) -> Result<bool> {
|
||||||
|
let mut output = Vec::new();
|
||||||
|
exec(
|
||||||
|
docker,
|
||||||
|
format!("{}-object", cloud_id),
|
||||||
|
"root",
|
||||||
|
vec!["curl", "localhost:4566/health"],
|
||||||
|
vec![],
|
||||||
|
Some(&mut output),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let output = String::from_utf8(output)?;
|
||||||
|
Ok(output.contains(r#""s3": "running""#))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn container_name(&self, cloud_id: &str) -> String {
|
||||||
|
format!("{}-object", cloud_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn start_message(&self, _docker: &Docker, _cloud_id: &str) -> Result<Option<String>> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apps(&self) -> &'static [&'static str] {
|
||||||
|
&["files_external"]
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn post_setup(&self, _docker: &Docker, _cloud_id: &str) -> Result<Vec<String>> {
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/service/onlyoffice.rs
Normal file
95
src/service/onlyoffice.rs
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
use crate::image::pull_image;
|
||||||
|
use crate::service::ServiceTrait;
|
||||||
|
use crate::Result;
|
||||||
|
use bollard::container::{Config, CreateContainerOptions, NetworkingConfig};
|
||||||
|
use bollard::models::{ContainerState, EndpointSettings, HostConfig};
|
||||||
|
use bollard::Docker;
|
||||||
|
use color_eyre::Report;
|
||||||
|
use maplit::hashmap;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct OnlyOffice;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl ServiceTrait for OnlyOffice {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"onlyoffice"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn env(&self) -> &[&str] {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn spawn(&self, docker: &Docker, cloud_id: &str, network: &str) -> Result<String> {
|
||||||
|
let image = "onlyoffice/documentserver";
|
||||||
|
pull_image(docker, image).await?;
|
||||||
|
let options = Some(CreateContainerOptions {
|
||||||
|
name: self.container_name(cloud_id),
|
||||||
|
});
|
||||||
|
let config = Config {
|
||||||
|
image: Some(image),
|
||||||
|
host_config: Some(HostConfig {
|
||||||
|
network_mode: Some(network.to_string()),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
labels: Some(hashmap! {
|
||||||
|
"haze-type" => self.name(),
|
||||||
|
"haze-cloud-id" => cloud_id
|
||||||
|
}),
|
||||||
|
networking_config: Some(NetworkingConfig {
|
||||||
|
endpoints_config: hashmap! {
|
||||||
|
network => EndpointSettings {
|
||||||
|
aliases: Some(vec![self.name().to_string()]),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let id = docker.create_container(options, config).await?.id;
|
||||||
|
docker.start_container::<String>(&id, None).await?;
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn container_name(&self, cloud_id: &str) -> String {
|
||||||
|
format!("{}-onlyoffice", cloud_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn start_message(&self, _docker: &Docker, _cloud_id: &str) -> Result<Option<String>> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apps(&self) -> &'static [&'static str] {
|
||||||
|
&["onlyoffice"]
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn post_setup(&self, docker: &Docker, cloud_id: &str) -> Result<Vec<String>> {
|
||||||
|
let info = docker
|
||||||
|
.inspect_container(&self.container_name(cloud_id), None)
|
||||||
|
.await?;
|
||||||
|
let ip = if matches!(
|
||||||
|
info.state,
|
||||||
|
Some(ContainerState {
|
||||||
|
running: Some(true),
|
||||||
|
..
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
info.network_settings
|
||||||
|
.unwrap()
|
||||||
|
.networks
|
||||||
|
.unwrap()
|
||||||
|
.values()
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.ip_address
|
||||||
|
.clone()
|
||||||
|
.unwrap()
|
||||||
|
} else {
|
||||||
|
return Err(Report::msg("onlyoffice not started"));
|
||||||
|
};
|
||||||
|
Ok(vec![format!(
|
||||||
|
"occ config:app:set onlyoffice DocumentServerUrl --value http://{}/",
|
||||||
|
ip
|
||||||
|
)])
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue