use serde::{Deserialize, Serialize, Deserializer};
use std::collections::HashMap;
use crate::container::health_check::HealthCheck;
#[derive(Debug, Deserialize, Serialize, Clone)]
struct EmptyObject;
#[derive(Debug, Default)]
pub struct ConfigBuilder {
name: Option<String>,
hostname: Option<String>,
domain_name: Option<String>,
user: Option<String>,
attach_stdin: Option<bool>,
attach_stdout: Option<bool>,
attach_stderr: Option<bool>,
exposed_ports: HashMap<String, EmptyObject>,
tty: Option<bool>,
open_stdin: Option<bool>,
stdin_once: Option<bool>,
env: Vec<String>,
cmd: Vec<String>,
health_check: Option<HealthCheck>,
args_escaped: Option<bool>,
image: Option<String>,
volumes: HashMap<String, EmptyObject>,
work_dir: Option<String>,
entry_point: Vec<String>,
network_disabled: Option<bool>,
mac_address: Option<String>,
on_build: Vec<String>,
labels: HashMap<String, String>,
stop_signal: Option<String>,
stop_timeout: Option<i32>,
shell: Vec<String>,
}
impl ConfigBuilder {
pub fn new() -> Self {
ConfigBuilder::default()
}
pub fn with_image<T>(image: T) -> Self
where T: Into<String>
{
let mut builder = ConfigBuilder::new();
builder.image = Some(image.into());
builder
}
pub fn name<T>(&mut self, name: T) -> &mut Self
where T: Into<String>
{
self.name = Some(name.into());
self
}
pub fn hostname<T>(&mut self, name: T) -> &mut Self
where T: Into<String>
{
self.hostname = Some(name.into());
self
}
pub fn domain_name<T>(&mut self, name: T) -> &mut Self
where T: Into<String>
{
self.domain_name = Some(name.into());
self
}
pub fn user<T>(&mut self, name: T) -> &mut Self
where T: Into<String>
{
self.user = Some(name.into());
self
}
pub fn attach_stdin(&mut self, b: bool) -> &mut Self {
self.attach_stdin = Some(b);
self
}
pub fn attach_stdout(&mut self, b: bool) -> &mut Self {
self.attach_stdout = Some(b);
self
}
pub fn attach_stderr(&mut self, b: bool) -> &mut Self {
self.attach_stderr = Some(b);
self
}
pub fn expose_port<T>(&mut self, port: T) -> &mut Self
where T: Into<String>
{
self.exposed_ports.insert(port.into(), EmptyObject{});
self
}
pub fn tty(&mut self, b: bool) -> &mut Self {
self.tty = Some(b);
self
}
pub fn open_stdin(&mut self, b: bool) -> &mut Self {
self.open_stdin = Some(b);
self
}
pub fn stdin_once(&mut self, b: bool) -> &mut Self {
self.stdin_once = Some(b);
self
}
pub fn env<T>(&mut self, env: T) -> &mut Self
where T: Into<String>
{
self.env.push(env.into());
self
}
pub fn cmd<T>(&mut self, cmd: T) -> &mut Self
where T: Into<String>
{
self.cmd.push(cmd.into());
self
}
pub fn health_check(&mut self, health_check: Option<HealthCheck>) -> &mut Self {
self.health_check = health_check;
self
}
pub fn args_escaped(&mut self, b: bool) -> &mut Self {
self.args_escaped = Some(b);
self
}
pub fn image<T>(&mut self, image: T) -> &mut Self
where T: Into<String>
{
self.image = Some(image.into());
self
}
pub fn volume<T>(&mut self, volume: T) -> &mut Self
where T: Into<String>
{
self.volumes.insert(volume.into(), EmptyObject{});
self
}
pub fn work_dir<T>(&mut self, work_dir: T) -> &mut Self
where T: Into<String>
{
self.work_dir = Some(work_dir.into());
self
}
pub fn entry_point<T>(&mut self, entry_point: T) -> &mut Self
where T: Into<String>
{
self.entry_point.push(entry_point.into());
self
}
pub fn network_disabled(&mut self, b: bool) -> &mut Self {
self.network_disabled = Some(b);
self
}
pub fn mac_address<T>(&mut self, mac_address: T) -> &mut Self
where T: Into<String>
{
self.mac_address = Some(mac_address.into());
self
}
pub fn on_build<T>(&mut self, cmd: T) -> &mut Self
where T: Into<String>
{
self.on_build.push(cmd.into());
self
}
pub fn label<T, U>(&mut self, k: T, v: U) -> &mut Self
where
T: Into<String>,
U: Into<String>
{
self.labels.insert(k.into(), v.into());
self
}
pub fn stop_signal<T>(&mut self, stop_signal: T) -> &mut Self
where T: Into<String>
{
self.stop_signal = Some(stop_signal.into());
self
}
pub fn stop_timeout(&mut self, time: Option<i32>) -> &mut Self {
self.stop_timeout = time;
self
}
pub fn shell<T>(&mut self, cmd: T) -> &mut Self
where T: Into<String>
{
self.shell.push(cmd.into());
self
}
pub fn build(&self) -> Config {
Config {
name: self.name.clone(),
hostname: self.hostname.clone(),
domain_name: self.domain_name.clone(),
user: self.user.clone(),
attach_stdin: self.attach_stdin.clone(),
attach_stdout: self.attach_stdout.clone(),
attach_stderr: self.attach_stderr.clone(),
tty: self.tty.clone(),
open_stdin: self.open_stdin.clone(),
stdin_once: self.stdin_once.clone(),
env: self.env.clone(),
labels: self.labels.clone(),
cmd: self.cmd.clone(),
entry_point: self.entry_point.clone(),
image: self.image.clone(),
volumes: self.volumes.clone(),
health_check: self.health_check.clone(),
work_dir: self.work_dir.clone(),
network_disabled: self.network_disabled.clone()
}
}
}
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
pub struct Config {
#[serde(skip_serializing, skip_deserializing)]
name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "Hostname")]
hostname: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "Domainname")]
domain_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "User")]
user: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "AttachStdin")]
attach_stdin: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", rename = "AttachStdout")]
attach_stdout: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", rename = "AttachStderr")]
attach_stderr: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", rename = "Tty")]
tty: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", rename = "OpenStdin")]
open_stdin: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", rename = "StdinOnce")]
stdin_once: Option<bool>,
#[serde(skip_serializing_if = "Vec::is_empty", rename = "Env", deserialize_with = "nullable_priority_vec")]
env: Vec<String>,
#[serde(skip_serializing_if = "HashMap::is_empty", rename = "Labels")]
labels: HashMap<String, String>,
#[serde(skip_serializing_if = "Vec::is_empty", rename = "Cmd", deserialize_with = "nullable_priority_vec")]
cmd: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty", rename = "Entrypoint", deserialize_with = "nullable_priority_vec")]
entry_point: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "Image")]
image: Option<String>,
#[serde(skip_serializing_if = "HashMap::is_empty", rename = "Volumes", deserialize_with = "nullable_priority_hash")]
volumes: HashMap<String, EmptyObject>,
#[serde(skip_serializing_if = "Option::is_none", rename = "Healthcheck")]
health_check: Option<HealthCheck>,
#[serde(skip_serializing_if = "Option::is_none", rename = "WorkingDir")]
work_dir: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "NetworkDisabled")]
network_disabled: Option<bool>,
}
impl Config {
pub fn new() -> ConfigBuilder {
ConfigBuilder::default()
}
pub fn with_image<T>(image: T) -> ConfigBuilder
where T: Into<String>
{
let mut builder = ConfigBuilder::default();
builder.image = Some(image.into());
builder
}
pub fn get_path(&self) -> String {
let mut path = format!("/containers/create?");
if self.name.is_some() {
path.push_str(format!("name={}&", self.name.clone().unwrap()).as_str());
}
path.pop();
path
}
}
#[derive(Deserialize, Debug)]
pub struct CreatedContainer {
#[serde(rename(deserialize = "Id"))]
id: String,
#[serde(rename(deserialize = "Warnings"))]
warnings: Vec<String>,
}
impl CreatedContainer {
pub fn id(&self) -> String {
self.id.clone()
}
pub fn warnings(&self) -> Vec<String> {
self.warnings.clone()
}
}
fn nullable_priority_hash<'de, D>(deserializer: D) -> Result<HashMap<String, EmptyObject>, D::Error>
where D: Deserializer<'de>
{
let opt = Option::deserialize(deserializer)?;
Ok(opt.unwrap_or(Default::default()))
}
fn nullable_priority_vec<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
where D: Deserializer<'de>
{
let opt = Option::deserialize(deserializer)?;
Ok(opt.unwrap_or(Vec::new()))
}