55//! for a shutdown signal.
66
77use bollard:: Docker ;
8- use bollard:: container:: {
9- Config as ContainerConfig , CreateContainerOptions , RemoveContainerOptions ,
10- StartContainerOptions , StopContainerOptions ,
8+ use bollard:: models:: ContainerCreateBody ;
9+ use bollard:: query_parameters:: {
10+ CreateContainerOptionsBuilder , CreateImageOptionsBuilder , InspectContainerOptionsBuilder ,
11+ RemoveContainerOptionsBuilder , StartContainerOptions , StopContainerOptionsBuilder ,
1112} ;
12- use bollard:: image:: CreateImageOptions ;
1313use bollard:: secret:: ContainerCreateResponse ;
1414use serde:: { Deserialize , Serialize } ;
1515use std:: collections:: { HashMap , VecDeque } ;
@@ -178,7 +178,8 @@ impl Container {
178178 // Check that containers are still running every 10 seconds
179179 _ = liveness_interval. tick( ) => {
180180 for container in & containers {
181- if let Some ( state) = docker. inspect_container( & container. id, None ) . await ?. state {
181+ let inspect_options = InspectContainerOptionsBuilder :: default ( ) . build( ) ;
182+ if let Some ( state) = docker. inspect_container( & container. id, Some ( inspect_options) ) . await ?. state {
182183 if !state. running. unwrap_or( false ) {
183184 return Err ( Error :: Generic ( format!(
184185 "Container {id} is not running anymore" ,
@@ -212,14 +213,11 @@ impl Container {
212213}
213214
214215async fn pull_image ( docker : & Docker , full_image : & str ) -> Result < ( ) , Error > {
215- let mut pull_stream = docker. create_image (
216- Some ( CreateImageOptions :: < & str > {
217- from_image : full_image,
218- ..Default :: default ( )
219- } ) ,
220- None ,
221- None ,
222- ) ;
216+ let create_image_options = CreateImageOptionsBuilder :: default ( )
217+ . from_image ( full_image)
218+ . build ( ) ;
219+
220+ let mut pull_stream = docker. create_image ( Some ( create_image_options) , None , None ) ;
223221
224222 while let Some ( item) = pull_stream. next ( ) . await {
225223 match item {
@@ -241,32 +239,35 @@ async fn pull_image(docker: &Docker, full_image: &str) -> Result<(), Error> {
241239impl Config {
242240 /// Convert the `Container` instance to a `ContainerConfig` for the Docker API.
243241 #[ must_use]
244- fn to_container_config < ' a > ( & ' a self , full_image : & ' a str ) -> ContainerConfig < & ' a str > {
245- ContainerConfig {
246- image : Some ( full_image) ,
242+ fn to_container_config ( & self , full_image : & str ) -> ContainerCreateBody {
243+ // The Docker API requires exposed ports in the format {"<port>/<protocol>": {}}.
244+ // For example: {"80/tcp": {}, "443/tcp": {}}
245+ // The port specification is in the key, and the value must be an empty object.
246+ // Bollard represents the empty object as HashMap<(), ()>, which is required by their API.
247+ #[ allow( clippy:: zero_sized_map_values) ]
248+ let exposed_ports = self . exposed_ports . as_ref ( ) . map ( |ports| {
249+ ports
250+ . iter ( )
251+ . map ( |port| {
252+ // Ensure port includes protocol (default to tcp if not specified)
253+ let port_with_protocol = if port. contains ( '/' ) {
254+ port. clone ( )
255+ } else {
256+ format ! ( "{port}/tcp" )
257+ } ;
258+ ( port_with_protocol, HashMap :: < ( ) , ( ) > :: new ( ) )
259+ } )
260+ . collect ( )
261+ } ) ;
262+
263+ ContainerCreateBody {
264+ image : Some ( full_image. to_string ( ) ) ,
247265 tty : Some ( true ) ,
248- cmd : self
249- . args
250- . as_ref ( )
251- . map ( |args| args. iter ( ) . map ( String :: as_str) . collect ( ) ) ,
252- env : self
253- . env
254- . as_ref ( )
255- . map ( |env| env. iter ( ) . map ( String :: as_str) . collect ( ) ) ,
256- labels : self . labels . as_ref ( ) . map ( |labels| {
257- labels
258- . iter ( )
259- . map ( |( key, value) | ( key. as_str ( ) , value. as_str ( ) ) )
260- . collect ( )
261- } ) ,
266+ cmd : self . args . clone ( ) ,
267+ env : self . env . clone ( ) ,
268+ labels : self . labels . clone ( ) ,
262269 network_disabled : self . network_disabled ,
263- #[ allow( clippy:: zero_sized_map_values) ]
264- exposed_ports : self . exposed_ports . as_ref ( ) . map ( |ports| {
265- ports
266- . iter ( )
267- . map ( |port| ( port. as_str ( ) , HashMap :: new ( ) ) )
268- . collect ( )
269- } ) ,
270+ exposed_ports,
270271 ..Default :: default ( )
271272 }
272273 }
@@ -279,14 +280,12 @@ impl Config {
279280 let container_name = format ! ( "lading_container_{}" , Uuid :: new_v4( ) ) ;
280281 debug ! ( "Creating container: {container_name}" ) ;
281282
283+ let create_options = CreateContainerOptionsBuilder :: default ( )
284+ . name ( & container_name)
285+ . build ( ) ;
286+
282287 let container = docker
283- . create_container (
284- Some ( CreateContainerOptions {
285- name : & container_name,
286- platform : None ,
287- } ) ,
288- self . to_container_config ( full_image) ,
289- )
288+ . create_container ( Some ( create_options) , self . to_container_config ( full_image) )
290289 . await ?;
291290
292291 debug ! ( "Created container with id: {id}" , id = container. id) ;
@@ -295,7 +294,7 @@ impl Config {
295294 }
296295
297296 docker
298- . start_container ( & container. id , None :: < StartContainerOptions < String > > )
297+ . start_container ( & container. id , None :: < StartContainerOptions > )
299298 . await ?;
300299
301300 debug ! ( "Started container: {id}" , id = container. id) ;
@@ -309,22 +308,18 @@ async fn stop_and_remove_container(
309308 container : & ContainerCreateResponse ,
310309) -> Result < ( ) , Error > {
311310 info ! ( "Stopping container: {id}" , id = container. id) ;
311+ let stop_options = StopContainerOptionsBuilder :: default ( ) . t ( 5 ) . build ( ) ;
312312 if let Err ( e) = docker
313- . stop_container ( & container. id , Some ( StopContainerOptions { t : 5 } ) )
313+ . stop_container ( & container. id , Some ( stop_options ) )
314314 . await
315315 {
316316 warn ! ( "Error stopping container {id}: {e}" , id = container. id) ;
317317 }
318318
319319 debug ! ( "Removing container: {id}" , id = container. id) ;
320+ let remove_options = RemoveContainerOptionsBuilder :: default ( ) . force ( true ) . build ( ) ;
320321 docker
321- . remove_container (
322- & container. id ,
323- Some ( RemoveContainerOptions {
324- force : true ,
325- ..Default :: default ( )
326- } ) ,
327- )
322+ . remove_container ( & container. id , Some ( remove_options) )
328323 . await ?;
329324
330325 debug ! ( "Removed container: {id}" , id = container. id) ;
0 commit comments