Skip to content

Commit

Permalink
fix: Fix port binding
Browse files Browse the repository at this point in the history
  • Loading branch information
IgorLaborieWefox committed Nov 16, 2023
1 parent de411d8 commit 372c7b6
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 84 deletions.
12 changes: 7 additions & 5 deletions rustainers/examples/custom_image.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::process::Command;
use std::sync::Arc;

use tracing::{info, Level};

use rustainers::runner::{RunOption, Runner};
use rustainers::{
ExposedPort, HealthCheck, ImageName, RunnableContainer, RunnableContainerBuilder,
ToRunnableContainer,
SharedExposedPort, ToRunnableContainer,
};

mod common;
Expand All @@ -26,7 +27,8 @@ async fn main() -> anyhow::Result<()> {
info!("Now I can use {container}");

// Making a dummy HTTP request
let port = container.port.host_port()?;
let container_port = container.port.lock().await;
let port = container_port.host_port()?;
let url = format!("http://localhost:{port}"); //DevSkim: ignore DS137138
Command::new("curl").args(["-v", &url]).status()?;

Expand All @@ -40,14 +42,14 @@ const PORT: u16 = 80;
#[derive(Debug, Clone)]
struct Nginx {
image: ImageName,
port: ExposedPort,
port: SharedExposedPort,
}

impl Default for Nginx {
fn default() -> Self {
Self {
image: NGINX_IMAGE.clone(),
port: ExposedPort::new(PORT),
port: ExposedPort::shared(PORT),
}
}
}
Expand All @@ -61,7 +63,7 @@ impl ToRunnableContainer for Nginx {
.with_command("curl -sf http://localhost") //DevSkim: ignore DS137138
.build(),
)
.with_port_mappings([self.port])
.with_port_mappings([Arc::clone(&self.port)])
.build()
}
}
2 changes: 1 addition & 1 deletion rustainers/examples/minio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ async fn main() -> anyhow::Result<()> {
}

async fn do_something_in_minio(minio: &Minio, bucket_name: &str) -> anyhow::Result<()> {
let endpoint = minio.endpoint()?;
let endpoint = minio.endpoint().await?;
info!("Using MinIO at {endpoint}");
let s3 = AmazonS3Builder::from_env()
.with_region(minio.region())
Expand Down
2 changes: 1 addition & 1 deletion rustainers/examples/postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ async fn main() -> anyhow::Result<()> {
}

async fn do_something_in_postgres(pg: &Postgres) -> anyhow::Result<()> {
let config = pg.config()?;
let config = pg.config().await?;

// Connect to the database.
let (client, connection) = tokio_postgres::connect(&config, NoTls).await?;
Expand Down
2 changes: 1 addition & 1 deletion rustainers/examples/redis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ async fn main() -> anyhow::Result<()> {
}

async fn do_something_in_redis(redis: &Redis) -> anyhow::Result<()> {
let endpoint = redis.endpoint()?;
let endpoint = redis.endpoint().await?;
info!("Using Redis at {endpoint}");
let client = Client::open(endpoint)?;
let mut con = client.get_connection()?;
Expand Down
8 changes: 4 additions & 4 deletions rustainers/src/container/runnable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ use std::fmt::{self, Display};
use indexmap::IndexMap;
use typed_builder::TypedBuilder;

use crate::{ExposedPort, ImageReference, WaitStrategy};
use crate::{ImageReference, SharedExposedPort, WaitStrategy};

/// Contains configuration require to create and run a container
#[derive(Debug, Clone, TypedBuilder)]
#[derive(Debug, TypedBuilder)]
#[builder(field_defaults(setter(prefix = "with_")))]
#[non_exhaustive]
pub struct RunnableContainer {
Expand All @@ -31,8 +31,8 @@ pub struct RunnableContainer {
pub(crate) wait_strategy: WaitStrategy,

/// The ports mapping
#[builder(default, setter(transform = |args: impl IntoIterator<Item = ExposedPort>| args.into_iter().collect()))]
pub(crate) port_mappings: Vec<ExposedPort>,
#[builder(default, setter(transform = |args: impl IntoIterator<Item = SharedExposedPort>| args.into_iter().collect()))]
pub(crate) port_mappings: Vec<SharedExposedPort>,
// TODO networks
// TODO volumes
// TODO entrypoint
Expand Down
35 changes: 21 additions & 14 deletions rustainers/src/images/minio.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::mem;
use std::sync::Arc;
use std::time::Duration;

use crate::runner::RunnerError;
use crate::{
Container, ExposedPort, HealthCheck, ImageName, Port, PortError, RunnableContainer,
RunnableContainerBuilder, ToRunnableContainer,
RunnableContainerBuilder, SharedExposedPort, ToRunnableContainer,
};

const DATA: &str = "/data";
Expand Down Expand Up @@ -35,11 +37,11 @@ const CONSOLE_PORT: Port = Port(9001);
/// # Ok(())
/// # }
///```
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone)]
pub struct Minio {
image: ImageName,
port: ExposedPort,
console_port: ExposedPort,
port: SharedExposedPort,
console_port: SharedExposedPort,
}

impl Minio {
Expand Down Expand Up @@ -100,8 +102,10 @@ impl Minio {
/// # Errors
///
/// Could fail if the port is not bind
pub fn endpoint(&self) -> Result<String, PortError> {
let port = self.port.host_port()?;
pub async fn endpoint(&self) -> Result<String, PortError> {
let p = self.port.lock().await;
let port = p.host_port()?;
mem::drop(p);
let url = format!("http://localhost:{port}");

Ok(url)
Expand All @@ -112,8 +116,10 @@ impl Minio {
/// # Errors
///
/// Could fail if the console port is not bind
pub fn console_endpoint(&self) -> Result<String, PortError> {
let port = self.console_port.host_port()?;
pub async fn console_endpoint(&self) -> Result<String, PortError> {
let p = self.console_port.lock().await;
let port = p.host_port()?;
mem::drop(p);
let url = format!("http://localhost:{port}");

Ok(url)
Expand Down Expand Up @@ -141,8 +147,8 @@ impl Default for Minio {
fn default() -> Self {
Minio {
image: MINIO_IMAGE.clone(),
port: ExposedPort::new(PORT),
console_port: ExposedPort::new(CONSOLE_PORT),
port: ExposedPort::shared(PORT),
console_port: ExposedPort::shared(CONSOLE_PORT),
}
}
}
Expand All @@ -158,24 +164,25 @@ impl ToRunnableContainer for Minio {
.build()
})
.with_command(["server", DATA])
.with_port_mappings([self.port, self.console_port])
.with_port_mappings([Arc::clone(&self.port), Arc::clone(&self.console_port)])
.build()
}
}

#[cfg(test)]
#[allow(clippy::ignored_unit_patterns)]
mod tests {

use super::*;
use assert2::{check, let_assert};

#[test]
fn should_create_endpoint() {
#[tokio::test]
async fn should_create_endpoint() {
let image = Minio {
port: ExposedPort::fixed(PORT, Port::new(9123)),
..Default::default()
};
let result = image.endpoint();
let result = image.endpoint().await;
let_assert!(Ok(endpoint) = result);
check!(endpoint == "http://localhost:9123");
}
Expand Down
35 changes: 21 additions & 14 deletions rustainers/src/images/postgres.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::mem;
use std::sync::Arc;
use std::time::Duration;

use crate::{
ExposedPort, HealthCheck, ImageName, Port, PortError, RunnableContainer,
RunnableContainerBuilder, ToRunnableContainer,
RunnableContainerBuilder, SharedExposedPort, ToRunnableContainer,
};

const POSTGRES_IMAGE: &ImageName = &ImageName::new("postgres");
Expand Down Expand Up @@ -46,7 +48,7 @@ pub struct Postgres {
user: String,
password: String,
db: String,
port: ExposedPort,
port: SharedExposedPort,
}

impl Postgres {
Expand Down Expand Up @@ -157,10 +159,12 @@ impl Postgres {
/// # Errors
///
/// Could fail if the port is not bind
pub fn url(&self) -> Result<String, PortError> {
pub async fn url(&self) -> Result<String, PortError> {
let user = &self.user;
let password = &self.password;
let port = self.port.host_port()?;
let p = self.port.lock().await;
let port = p.host_port()?;
mem::drop(p);
let database = &self.db;
let url = format!("postgresql://{user}:{password}@localhost:{port}/{database}");
Ok(url)
Expand All @@ -171,10 +175,12 @@ impl Postgres {
/// # Errors
///
/// Could fail if the port is not bind
pub fn config(&self) -> Result<String, PortError> {
pub async fn config(&self) -> Result<String, PortError> {
let user = &self.user;
let password = &self.password;
let port = self.port.host_port()?;
let p = self.port.lock().await;
let port = p.host_port()?;
mem::drop(p);
let database = &self.db;
let config =
format!("host=localhost user={user} password={password} port={port} dbname={database}");
Expand All @@ -189,7 +195,7 @@ impl Default for Postgres {
user: String::from(POSTGRES_USER),
password: String::from(POSTGRES_PASSWORD),
db: String::from(POSTGRES_DATABASE),
port: ExposedPort::new(PORT),
port: ExposedPort::shared(PORT),
}
}
}
Expand All @@ -211,35 +217,36 @@ impl ToRunnableContainer for Postgres {
("POSTGRES_PASSWORD", &self.password),
("POSTGRES_DB", &self.db),
])
.with_port_mappings([self.port])
.with_port_mappings([Arc::clone(&self.port)])
.build()
}
}

#[cfg(test)]
#[allow(clippy::ignored_unit_patterns)]
mod tests {

use assert2::check;

use super::*;

#[test]
fn should_build_config() {
#[tokio::test]
async fn should_build_config() {
let image = Postgres {
port: ExposedPort::fixed(PORT, Port::new(5432)),
..Default::default()
};
let result = image.config().unwrap();
let result = image.config().await.unwrap();
check!(result == "host=localhost user=postgres password=passwd port=5432 dbname=postgres");
}

#[test]
fn should_build_url() {
#[tokio::test]
async fn should_build_url() {
let image = Postgres {
port: ExposedPort::fixed(PORT, Port::new(5432)),
..Default::default()
};
let result = image.url().unwrap();
let result = image.url().await.unwrap();
check!(result == "postgresql://postgres:passwd@localhost:5432/postgres");
}
}
25 changes: 15 additions & 10 deletions rustainers/src/images/redis.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::mem;
use std::sync::Arc;
use std::time::Duration;

use crate::{
ExposedPort, HealthCheck, ImageName, Port, PortError, RunnableContainer,
RunnableContainerBuilder, ToRunnableContainer,
RunnableContainerBuilder, SharedExposedPort, ToRunnableContainer,
};

const REDIS_IMAGE: &ImageName = &ImageName::new("redis");
Expand All @@ -29,10 +31,10 @@ const PORT: Port = Port(6379);
/// // ...
/// # Ok(())
/// # }
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone)]
pub struct Redis {
image: ImageName,
port: ExposedPort,
port: SharedExposedPort,
}

impl Redis {
Expand All @@ -59,8 +61,10 @@ impl Redis {
/// # Errors
///
/// Could fail if the port is not bind
pub fn endpoint(&self) -> Result<String, PortError> {
let port = self.port.host_port()?;
pub async fn endpoint(&self) -> Result<String, PortError> {
let p = self.port.lock().await;
let port = p.host_port()?;
mem::drop(p);
let url = format!("redis://localhost:{port}");

Ok(url)
Expand All @@ -71,7 +75,7 @@ impl Default for Redis {
fn default() -> Self {
Self {
image: REDIS_IMAGE.clone(),
port: ExposedPort::new(PORT),
port: ExposedPort::shared(PORT),
}
}
}
Expand All @@ -87,24 +91,25 @@ impl ToRunnableContainer for Redis {
.with_interval(Duration::from_millis(96))
.build(),
)
.with_port_mappings([self.port])
.with_port_mappings([Arc::clone(&self.port)])
.build()
}
}

#[cfg(test)]
#[allow(clippy::ignored_unit_patterns)]
mod tests {

use super::*;
use assert2::{check, let_assert};

#[test]
fn should_create_endpoint() {
#[tokio::test]
async fn should_create_endpoint() {
let image = Redis {
port: ExposedPort::fixed(PORT, Port::new(9123)),
..Default::default()
};
let result = image.endpoint();
let result = image.endpoint().await;
let_assert!(Ok(endpoint) = result);
check!(endpoint == "redis://localhost:9123");
}
Expand Down
Loading

0 comments on commit 372c7b6

Please sign in to comment.