Skip to content

Commit

Permalink
I am ready to go!/
Browse files Browse the repository at this point in the history
  • Loading branch information
namse committed Dec 2, 2023
1 parent 1dd7241 commit a5d17b7
Show file tree
Hide file tree
Showing 6 changed files with 260 additions and 179 deletions.
2 changes: 2 additions & 0 deletions oioi/agent/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions oioi/agent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ aws-sdk-ssm = "1.3.0"
bollard = "0.15.0"
futures-util = "0.3.29"
lazy_static = "1.4.0"
serde = { version = "1.0.193", features = ["derive"] }
serde_json = "1.0.108"
tokio = { version = "1.34.0", features = ["rt", "macros"] }
30 changes: 30 additions & 0 deletions oioi/agent/src/docker_cli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use anyhow::Result;

pub(crate) async fn pull_image(image: &str) -> Result<()> {
run_docker_command(&["pull", image]).await?;
Ok(())
}

async fn run_docker_command(args: &[&str]) -> Result<Vec<u8>> {
let output = tokio::process::Command::new("docker")
.args(args)
.output()
.await
.map_err(|e| {
anyhow::anyhow!(
"Failed to run docker {args}: {e}",
args = args.join(" "),
e = e
)
})?;

if !output.status.success() {
return Err(anyhow::anyhow!(
"Failed to run docker {args}: {stderr}",
args = args.join(" "),
stderr = String::from_utf8_lossy(&output.stderr),
));
}

Ok(output.stdout)
}
151 changes: 151 additions & 0 deletions oioi/agent/src/docker_engine.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use crate::envs::*;
use anyhow::Result;
use bollard::{container::ListContainersOptions, Docker};

pub(crate) struct DockerEngine {
docker: Docker,
}

impl DockerEngine {
pub(crate) fn new() -> Result<Self> {
Ok(Self {
docker: Docker::connect_with_local_defaults()?,
})
}

pub(crate) async fn get_local_image_digest(&self, image: &str) -> Result<String> {
let output = self.docker.inspect_image(image).await?;

Ok(output.id.unwrap())
}

pub(crate) async fn get_running_container_image_digest(
&self,
container_name: &str,
) -> Result<Option<String>> {
Ok(self
.docker
.list_containers(Some(ListContainersOptions::<String> {
all: true,
..Default::default()
}))
.await?
.into_iter()
.find_map(|container| {
container
.names
.unwrap_or_default()
.contains(&format!("/{container_name}"))
.then(|| container.image_id.unwrap())
}))
}

pub(crate) async fn stop_running_container(&self) -> Result<()> {
self.docker
.stop_container(
CONTAINER_NAME,
Some(bollard::container::StopContainerOptions {
t: GRACEFUL_SHUTDOWN_TIMEOUT_SECS,
}),
)
.await?;
Ok(())
}

pub(crate) async fn run_new_container(&self, image: &str) -> Result<()> {
println!("removing container {CONTAINER_NAME}");
let remove_container_result = self
.docker
.remove_container(
CONTAINER_NAME,
Some(bollard::container::RemoveContainerOptions {
force: true,
..Default::default()
}),
)
.await;

if let Err(err) = remove_container_result {
match err {
bollard::errors::Error::DockerResponseServerError {
status_code,
message,
} => if status_code == 404 && message.contains("No such container") {},
_ => return Err(err.into()),
}
};

println!("creating container {CONTAINER_NAME}");
self.docker
.create_container(
Some(bollard::container::CreateContainerOptions {
name: CONTAINER_NAME,
platform: None,
}),
bollard::container::Config {
image: Some(image.to_string()),
host_config: Some(bollard::models::HostConfig {
log_config: Some(bollard::models::HostConfigLogConfig {
typ: Some("awslogs".to_string()),
config: Some(std::collections::HashMap::from_iter([
("awslogs-group".to_string(), format!("oioi-{}", *GROUP_NAME)),
(
"awslogs-stream".to_string(),
format!("oioi-{}-{}", *GROUP_NAME, *EC2_INSTANCE_ID),
),
("awslogs-create-group".to_string(), "true".to_string()),
])),
}),
port_bindings: Some(std::collections::HashMap::from_iter(
PORT_MAPPINGS
.iter()
.map(|mapping| {
println!("mapping: {:?}", mapping);
(
format!("{}/{}", mapping.container_port, mapping.protocol),
Some(vec![bollard::models::PortBinding {
host_ip: None,
host_port: Some(mapping.host_port.to_string()),
}]),
)
})
.collect::<Vec<_>>(),
)),
..Default::default()
}),
..Default::default()
},
)
.await?;

println!("starting container {CONTAINER_NAME}");
self.docker
.start_container(
CONTAINER_NAME,
None::<bollard::container::StartContainerOptions<String>>,
)
.await?;

Ok(())
}

pub(crate) async fn docker_prune(&self) -> Result<()> {
self.docker
.prune_containers(None::<bollard::container::PruneContainersOptions<String>>)
.await?;

self.docker
.prune_images(None::<bollard::image::PruneImagesOptions<String>>)
.await?;

self.docker
.prune_networks(None::<bollard::network::PruneNetworksOptions<String>>)
.await?;

self.docker
.prune_volumes(None::<bollard::volume::PruneVolumesOptions<String>>)
.await?;

Ok(())
}
}
29 changes: 29 additions & 0 deletions oioi/agent/src/envs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
pub(crate) const INTERVAL: std::time::Duration = std::time::Duration::from_secs(5);
pub(crate) const CONTAINER_NAME: &str = "oioi";
pub(crate) const GRACEFUL_SHUTDOWN_TIMEOUT_SECS: i64 = 30;

lazy_static::lazy_static! {
pub(crate) static ref GROUP_NAME: String = std::env::var("GROUP_NAME").expect("GROUP_NAME env var not set");
pub(crate) static ref EC2_INSTANCE_ID: String = std::env::var("EC2_INSTANCE_ID").expect("EC2_INSTANCE_ID env var not set");
pub(crate) static ref PORT_MAPPINGS: Vec<PortMapping> = std::env::var("PORT_MAPPINGS").map(|env_string| {
env_string.split(',').map(|mapping| {
let mut parts = mapping.split(&[':', '/']);
let container_port = parts.next().expect("container port not found").parse::<u16>().expect("container port is not a number");
let host_port = parts.next().expect("host port not found").parse::<u16>().expect("host port is not a number");
let protocol = parts.next().expect("protocol not found").to_string();

PortMapping {
container_port,
host_port,
protocol,
}
}).collect()
}).expect("PORT_MAPPINGS env var not set");
}

#[derive(Debug)]
pub(crate) struct PortMapping {
pub(crate) container_port: u16,
pub(crate) host_port: u16,
pub(crate) protocol: String,
}
Loading

0 comments on commit a5d17b7

Please sign in to comment.