use crate::config::{docker::DockerConnectionConfig, mrproxy::MrproxyConnectionConfig}; use crate::database::exposer::MemStorage; use crate::database::instance::Instance; use crate::deploy::container::Container; use crate::deploy::container_options::Options; use crate::{deploy, mcproxy_client}; use bollard::errors::Error; use bollard::Docker; use log::error; use std::error::Error as GenericError; use std::sync::Mutex; pub struct Controller { driver: Docker, network: String, storage: Mutex, started: bool, docker_config: DockerConnectionConfig, mrproxy_config: MrproxyConnectionConfig, } impl Controller { pub async fn new( driver: Docker, network: String, range: String, docker_config: DockerConnectionConfig, mrproxy_config: MrproxyConnectionConfig, ) -> Result { deploy::network::Network::new(driver.clone(), network.clone(), range).await?; let cont = Self { driver: driver, network: network, storage: Mutex::new(MemStorage::new().unwrap()), started: false, docker_config, mrproxy_config, }; Ok(cont) } pub async fn create_container( &self, domain: String, ip: Option, image: String, ops: Options, ) -> String { let is_stored = self.storage.lock().unwrap().search_instance(domain.clone()); match is_stored { Some(c) => match c.docker_id { Some(id) => id, None => "Container without docker_id".to_string(), }, None => { match self .load_container_and_bind(None, domain.clone(), ip.clone(), image.clone(), ops) .await { Ok(c) => { self.storage .try_lock() .unwrap() .new_instance(c.clone()) .unwrap(); c.get_id() } Err(e) => format!("error creating container: {}", e.to_string()), } } } } async fn load_container_and_bind( &self, docker_id: Option, domain: String, ip: Option, image: String, ops: Options, ) -> Result> { match self .load_container(docker_id, domain.clone(), ip.clone(), image, ops) .await { Ok(c) => { match self .bind_container_in_proxy(domain.clone(), ip, c.clone()) .await { Ok(_) => Ok(c), Err(e) => { error!("failed in the bind process with the proxy, deleting the container"); self.delete_container(domain).await?; return Err(e); } } } Err(e) => return Err(Box::new(e)), } } async fn bind_container_in_proxy( &self, domain: String, ip: Option, container: Container, ) -> Result<(), Box> { let mut mrcp_controller = mcproxy_client::controller::Controller::new(&self.mrproxy_config)?; mrcp_controller.insert_new_domain( &domain, &ip.unwrap_or(container.get_ip(&self.driver).await?), )?; Ok(()) } async fn unbind_container_in_proxy(&self, domain: &str) -> Result<(), Box> { let mut mrcp_controller = mcproxy_client::controller::Controller::new(&self.mrproxy_config)?; mrcp_controller.remove_domain(&domain)?; Ok(()) } pub async fn start_container_from_instance(&self, instance: Instance) { let image = match self .storage .lock() .unwrap() .id_to_image(instance.image.clone()) { Ok(i) => i, Err(e) => { error!("image not found: {}", e); return; } }; match self .load_container_and_bind( Some(instance.docker_id.clone()), instance.domain.clone(), instance.ip.clone(), image, Options::new(None, None), ) .await { Ok(c) => { self.storage.lock().unwrap().loaded_instance(instance, c); } Err(e) => error!("{}", e), } } async fn load_container( &self, docker_id: Option, domain: String, ip: Option, image: String, ops: Options, ) -> Result { deploy::container::Container::new( self.driver.clone(), docker_id, domain, ip, image, self.network.clone(), ops, ) .await } pub async fn is_started(&self) -> bool { self.started } pub async fn load_all_instances(&self) -> bool { let data = match self.storage.lock().unwrap().get_instances_db() { Ok(d) => d, Err(e) => { error!("instances can't be loaded: {}", e); return false; } }; println!("instances {}", data.len()); for instance in data { self.start_container_from_instance(instance).await; } return true; } async fn stop_given_container(&self, container: Container) -> Result { match container.stop(&self.driver).await { Ok(_i) => Ok(container.get_id()), Err(e) => Err(e), } } async fn prune_given_container( &self, container: Container, ) -> Result> { match container.remove(&self.driver).await { Ok(_i) => Ok(container.get_id()), Err(e) => Err(Box::new(e)), } } pub async fn stop_container(&self, domain: String) -> Result { match self.storage.lock().unwrap().stop_instance(domain) { Some(c) => self.stop_given_container(c).await, None => Err(Error::DockerResponseServerError { status_code: 404, message: "container not found".to_string(), }), } } pub async fn delete_container(&self, domain: String) -> Result> { match self.storage.lock().unwrap().remove_instance(&domain) { Some(data) => match data.1 { Some(c) => { self.unbind_container_in_proxy(&domain).await?; self.prune_given_container(c).await } None => Ok(data.0.docker_id), }, None => Err(Box::new(Error::DockerResponseServerError { status_code: 404, message: "container not found".to_string(), })), } } pub async fn get_ip(&self, domain: String) -> Result { let container = self .storage .lock() .unwrap() .search_instance(domain.clone()) .unwrap(); container.get_ip(&self.driver).await } }