use crate::cloud::CloudOptions; use crate::config::{HazeConfig, ProxyConfig}; use crate::image::pull_image; use crate::service::ServiceTrait; use crate::Result; use bollard::config::NetworkingConfig; use bollard::models::{ContainerCreateBody, ContainerState, EndpointSettings, HostConfig}; use bollard::query_parameters::CreateContainerOptions; use bollard::Docker; use maplit::hashmap; use miette::{IntoDiagnostic, Report}; use std::net::IpAddr; use std::str::FromStr; #[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, _config: &HazeConfig, _options: &CloudOptions, ) -> Result> { let image = "icewind1991/haze-ldap"; pull_image(docker, image).await?; let options = Some(CreateContainerOptions { name: self.container_name(cloud_id), ..CreateContainerOptions::default() }); let config = ContainerCreateBody { image: Some(image.into()), env: Some(vec!["LDAP_ADMIN_PASSWORD=haze".into()]), host_config: Some(HostConfig { network_mode: Some(network.to_string()), ..Default::default() }), labels: Some(hashmap! { "haze-type".into() => self.name().into(), "haze-cloud-id".into() => cloud_id.into() }), networking_config: Some(NetworkingConfig { endpoints_config: Some(hashmap! { network.into() => EndpointSettings { aliases: Some(vec![self.name().to_string()]), ..Default::default() } }), }), cmd: Some(vec!["--copy-service".into()]), ..Default::default() }; let id = docker .create_container(options, config) .await .into_diagnostic()? .id; docker.start_container(&id, None).await.into_diagnostic()?; Ok(vec![id]) } fn container_name(&self, cloud_id: &str) -> Option { Some(format!("{}-ldap", cloud_id)) } fn apps(&self) -> &'static [&'static str] { &["user_ldap"] } async fn is_healthy( &self, docker: &Docker, cloud_id: &str, _options: &CloudOptions, ) -> Result { self.is_running(docker, cloud_id).await } } #[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, _config: &HazeConfig, _options: &CloudOptions, ) -> Result> { let image = "osixia/phpldapadmin"; pull_image(docker, image).await?; let options = Some(CreateContainerOptions { name: self.container_name(cloud_id), ..CreateContainerOptions::default() }); let config = ContainerCreateBody { image: Some(image.into()), env: Some(vec![ "PHPLDAPADMIN_LDAP_HOSTS=ldap".into(), "PHPLDAPADMIN_HTTPS=false".into(), ]), host_config: Some(HostConfig { network_mode: Some(network.to_string()), ..Default::default() }), labels: Some(hashmap! { "haze-type".into() => self.name().into(), "haze-cloud-id".into() => cloud_id.into(), }), networking_config: Some(NetworkingConfig { endpoints_config: Some(hashmap! { network.into() => EndpointSettings { aliases: Some(vec![self.name().to_string()]), ..Default::default() } }), }), cmd: Some(vec!["--copy-service".into()]), ..Default::default() }; let id = docker .create_container(options, config) .await .into_diagnostic()? .id; docker.start_container(&id, None).await.into_diagnostic()?; Ok(vec![id]) } fn container_name(&self, cloud_id: &str) -> Option { Some(format!("{}-ldap-admin", cloud_id)) } async fn start_message( &self, docker: &Docker, cloud_id: &str, proxy: &ProxyConfig, ) -> Result> { let id = self.container_name(cloud_id).unwrap(); let info = docker .inspect_container(&id, None) .await .into_diagnostic()?; 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")); }; let addr = proxy.addr(&id, IpAddr::from_str(&ip).unwrap()); Ok(Some(format!( "Ldap admin running at: {addr} with 'cn=admin,dc=example,dc=org' and password 'haze'" ))) } }