use std::collections::HashMap;
use bollard::{
Docker,
network::CreateNetworkOptions,
query_parameters::{
CreateContainerOptions, CreateContainerOptionsBuilder, StartContainerOptions,
},
secret::{ContainerCreateBody, EndpointIpamConfig, Ipam},
};
use clap::builder::Str;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct GameBoxMeta {
pub name: String,
pub author: String,
pub category: String,
pub description: String,
pub gamebox: GameBoxConfig,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct GameBoxConfig {
pub username: String,
pub image_tag: String,
pub break_point: f32,
pub fix_point: f32,
pub down_point: f32,
pub first_bouns: f32,
}
impl GameBoxMeta {
pub fn from_toml_str(toml: &str) -> Result<Self, toml::de::Error> {
toml::from_str(toml)
}
pub async fn create_and_start(
&self,
docker: &Docker,
identifier: &str,
net_bridge: Option<String>,
container_ip: Option<String>,
ctf_password: String,
) -> Result<(), Box<dyn std::error::Error>> {
let container_name = format!("{}", identifier);
let options = CreateContainerOptionsBuilder::new()
.name(&container_name)
.build();
let network_name = net_bridge.unwrap_or_else(|| "bridge".to_string());
let config = ContainerCreateBody {
image: Some(self.gamebox.image_tag.clone()),
env: Some(vec![
format!("{}={}", "CTF_USER", self.gamebox.username),
format!("{}={}", "CTF_PASSWORD", ctf_password),
]),
host_config: Some(bollard::models::HostConfig {
network_mode: network_name.clone().into(),
..Default::default()
}),
networking_config: Some(bollard::models::NetworkingConfig {
endpoints_config: Some(std::collections::HashMap::from([(
network_name,
bollard::models::EndpointSettings {
ipam_config: Some(EndpointIpamConfig {
ipv4_address: container_ip,
..Default::default()
}),
..Default::default()
},
)])),
..Default::default()
}),
..Default::default()
};
let container = docker.create_container(Some(options), config).await?;
docker
.start_container(&container.id, None::<StartContainerOptions>)
.await?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_create_and_start() {
let docker = Docker::connect_with_local_defaults().unwrap();
let meta = GameBoxMeta {
name: "hello-floatctf".to_string(),
author: "fb0sh@outlook.com".to_string(),
category: "Web".to_string(),
description: "hello floatctf".to_string(),
gamebox: GameBoxConfig {
username: "floatctf".to_string(),
image_tag: "floatctf/hello-floatctf:gamebox-web_v1.0.0".to_string(),
break_point: 100.0,
fix_point: 100.0,
down_point: 200.0,
first_bouns: 0.2,
},
};
crate::remove_and_create_bridge_net(
&docker,
"br-awd".to_string(),
"172.20.0.0/16".to_string(),
)
.await
.unwrap();
meta.create_and_start(
&docker,
"gamebox-hello-floatctf",
"br-awd".to_string().into(),
"172.20.1.100".to_string().into(),
"floatctf".to_string(),
)
.await
.unwrap();
tokio::time::sleep(tokio::time::Duration::from_secs(30)).await;
crate::stop_and_remove(&docker, "gamebox-hello-floatctf")
.await
.unwrap();
meta.create_and_start(
&docker,
"gamebox-hello-floatctf",
"br-awd".to_string().into(),
"172.20.1.100".to_string().into(),
"floatctf".to_string(),
)
.await
.unwrap();
}
}