247 lines
7.5 KiB
Rust
247 lines
7.5 KiB
Rust
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<MemStorage>,
|
|
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<Self, bollard::errors::Error> {
|
|
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<String>,
|
|
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<String>,
|
|
domain: String,
|
|
ip: Option<String>,
|
|
image: String,
|
|
ops: Options,
|
|
) -> Result<deploy::container::Container, Box<dyn GenericError>> {
|
|
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<String>,
|
|
container: Container,
|
|
) -> Result<(), Box<dyn GenericError>> {
|
|
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<dyn GenericError>> {
|
|
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<String>,
|
|
domain: String,
|
|
ip: Option<String>,
|
|
image: String,
|
|
ops: Options,
|
|
) -> Result<deploy::container::Container, bollard::errors::Error> {
|
|
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<String, Error> {
|
|
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<String, Box<dyn GenericError>> {
|
|
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<String, Error> {
|
|
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<String, Box<dyn GenericError>> {
|
|
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<String, Error> {
|
|
let container = self
|
|
.storage
|
|
.lock()
|
|
.unwrap()
|
|
.search_instance(domain.clone())
|
|
.unwrap();
|
|
container.get_ip(&self.driver).await
|
|
}
|
|
}
|