@@ -20,7 +20,7 @@ use crate::{
20
20
errors:: { Error , Result } ,
21
21
exec:: { Exec , ExecContainerOptions } ,
22
22
image:: Config ,
23
- network:: { NetworkInfo , NetworkSettings } ,
23
+ network:: NetworkSettings ,
24
24
transport:: Payload ,
25
25
tty:: { self , Multiplexer as TtyMultiPlexer } ,
26
26
} ;
@@ -31,6 +31,8 @@ use crate::datetime::datetime_from_unix_timestamp;
31
31
use chrono:: { DateTime , Utc } ;
32
32
33
33
/// Interface for accessing and manipulating a docker container
34
+ ///
35
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#tag/Container)
34
36
pub struct Container < ' docker > {
35
37
docker : & ' docker Docker ,
36
38
id : String ,
@@ -57,13 +59,17 @@ impl<'docker> Container<'docker> {
57
59
}
58
60
59
61
/// Inspects the current docker container instance's details
62
+ ///
63
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerInspect)
60
64
pub async fn inspect ( & self ) -> Result < ContainerDetails > {
61
65
self . docker
62
66
. get_json :: < ContainerDetails > ( & format ! ( "/containers/{}/json" , self . id) [ ..] )
63
67
. await
64
68
}
65
69
66
70
/// Returns a `top` view of information about the container process
71
+ ///
72
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerTop)
67
73
pub async fn top (
68
74
& self ,
69
75
psargs : Option < & str > ,
@@ -79,6 +85,8 @@ impl<'docker> Container<'docker> {
79
85
}
80
86
81
87
/// Returns a stream of logs emitted but the container instance
88
+ ///
89
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerLogs)
82
90
pub fn logs (
83
91
& self ,
84
92
opts : & LogsOptions ,
@@ -106,32 +114,42 @@ impl<'docker> Container<'docker> {
106
114
. await
107
115
}
108
116
109
- /// Attaches a `[TtyMultiplexer]` to the container.
117
+ /// Attaches a [Multiplexer](crate::tty::Multiplexer) to the container.
118
+ ///
119
+ /// The [Multiplexer](crate::tty::Multiplexer) implements Stream for returning Stdout and
120
+ /// Stderr chunks. It also implements `[AsyncWrite]` for writing to Stdin.
110
121
///
111
- /// The `[TtyMultiplexer]` implements Stream for returning Stdout and Stderr chunks. It also implements `[AsyncWrite]` for writing to Stdin.
122
+ /// The multiplexer can be split into its read and write halves with the
123
+ /// [split](crate::tty::Multiplexer::split) method
112
124
///
113
- /// The multiplexer can be split into its read and write halves with the `[split](TtyMultiplexer::split)` method
125
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerAttach)
114
126
pub async fn attach ( & self ) -> Result < TtyMultiPlexer < ' docker > > {
115
127
let tcp_stream = self . attach_raw ( ) . await ?;
116
128
117
129
Ok ( TtyMultiPlexer :: new ( tcp_stream) )
118
130
}
119
131
120
132
/// Returns a set of changes made to the container instance
133
+ ///
134
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerChanges)
121
135
pub async fn changes ( & self ) -> Result < Vec < Change > > {
122
136
self . docker
123
137
. get_json :: < Vec < Change > > ( & format ! ( "/containers/{}/changes" , self . id) [ ..] )
124
138
. await
125
139
}
126
140
127
141
/// Exports the current docker container into a tarball
142
+ ///
143
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerExport)
128
144
pub fn export ( & self ) -> impl Stream < Item = Result < Vec < u8 > > > + ' docker {
129
145
self . docker
130
146
. stream_get ( format ! ( "/containers/{}/export" , self . id) )
131
147
. map_ok ( |c| c. to_vec ( ) )
132
148
}
133
149
134
150
/// Returns a stream of stats specific to this container instance
151
+ ///
152
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerStats)
135
153
pub fn stats ( & self ) -> impl Stream < Item = Result < Stats > > + Unpin + ' docker {
136
154
let codec = futures_codec:: LinesCodec { } ;
137
155
@@ -152,6 +170,8 @@ impl<'docker> Container<'docker> {
152
170
}
153
171
154
172
/// Start the container instance
173
+ ///
174
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerStart)
155
175
pub async fn start ( & self ) -> Result < ( ) > {
156
176
self . docker
157
177
. post ( & format ! ( "/containers/{}/start" , self . id) [ ..] , None )
@@ -160,6 +180,8 @@ impl<'docker> Container<'docker> {
160
180
}
161
181
162
182
/// Stop the container instance
183
+ ///
184
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerStop)
163
185
pub async fn stop (
164
186
& self ,
165
187
wait : Option < Duration > ,
@@ -177,6 +199,8 @@ impl<'docker> Container<'docker> {
177
199
}
178
200
179
201
/// Restart the container instance
202
+ ///
203
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerRestart)
180
204
pub async fn restart (
181
205
& self ,
182
206
wait : Option < Duration > ,
@@ -193,6 +217,8 @@ impl<'docker> Container<'docker> {
193
217
}
194
218
195
219
/// Kill the container instance
220
+ ///
221
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerKill)
196
222
pub async fn kill (
197
223
& self ,
198
224
signal : Option < & str > ,
@@ -209,6 +235,8 @@ impl<'docker> Container<'docker> {
209
235
}
210
236
211
237
/// Rename the container instance
238
+ ///
239
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerRename)
212
240
pub async fn rename (
213
241
& self ,
214
242
name : & str ,
@@ -226,6 +254,8 @@ impl<'docker> Container<'docker> {
226
254
}
227
255
228
256
/// Pause the container instance
257
+ ///
258
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerPause)
229
259
pub async fn pause ( & self ) -> Result < ( ) > {
230
260
self . docker
231
261
. post ( & format ! ( "/containers/{}/pause" , self . id) [ ..] , None )
@@ -234,6 +264,8 @@ impl<'docker> Container<'docker> {
234
264
}
235
265
236
266
/// Unpause the container instance
267
+ ///
268
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerUnpause)
237
269
pub async fn unpause ( & self ) -> Result < ( ) > {
238
270
self . docker
239
271
. post ( & format ! ( "/containers/{}/unpause" , self . id) [ ..] , None )
@@ -242,6 +274,8 @@ impl<'docker> Container<'docker> {
242
274
}
243
275
244
276
/// Wait until the container stops
277
+ ///
278
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerWait)
245
279
pub async fn wait ( & self ) -> Result < Exit > {
246
280
self . docker
247
281
. post_json ( format ! ( "/containers/{}/wait" , self . id) , Payload :: None )
@@ -251,6 +285,8 @@ impl<'docker> Container<'docker> {
251
285
/// Delete the container instance
252
286
///
253
287
/// Use remove instead to use the force/v options.
288
+ ///
289
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerDelete)
254
290
pub async fn delete ( & self ) -> Result < ( ) > {
255
291
self . docker
256
292
. delete ( & format ! ( "/containers/{}" , self . id) [ ..] )
@@ -259,6 +295,8 @@ impl<'docker> Container<'docker> {
259
295
}
260
296
261
297
/// Delete the container instance (todo: force/v)
298
+ ///
299
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerRemove)
262
300
pub async fn remove (
263
301
& self ,
264
302
opts : RmContainerOptions ,
@@ -272,6 +310,8 @@ impl<'docker> Container<'docker> {
272
310
}
273
311
274
312
/// Execute a command in this container
313
+ ///
314
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#tag/Exec)
275
315
pub fn exec (
276
316
& self ,
277
317
opts : & ExecContainerOptions ,
@@ -287,6 +327,8 @@ impl<'docker> Container<'docker> {
287
327
/// directory, `path` should end in `/` or `/`. (assuming a path separator of `/`). If `path`
288
328
/// ends in `/.` then this indicates that only the contents of the path directory should be
289
329
/// copied. A symlink is always resolved to its target.
330
+ ///
331
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerArchive)
290
332
pub fn copy_from (
291
333
& self ,
292
334
path : & Path ,
@@ -303,6 +345,8 @@ impl<'docker> Container<'docker> {
303
345
///
304
346
/// The file will be copied at the given location (see `path`) and will be owned by root
305
347
/// with access mask 644.
348
+ ///
349
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/PutContainerArchive)
306
350
pub async fn copy_file_into < P : AsRef < Path > > (
307
351
& self ,
308
352
path : P ,
@@ -332,6 +376,8 @@ impl<'docker> Container<'docker> {
332
376
/// Copy a tarball (see `body`) to the container.
333
377
///
334
378
/// The tarball will be copied to the container and extracted at the given location (see `path`).
379
+ ///
380
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/PutContainerArchive)
335
381
pub async fn copy_to (
336
382
& self ,
337
383
path : & Path ,
@@ -354,6 +400,8 @@ impl<'docker> Container<'docker> {
354
400
}
355
401
356
402
/// Interface for docker containers
403
+ ///
404
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#tag/Containers)
357
405
pub struct Containers < ' docker > {
358
406
docker : & ' docker Docker ,
359
407
}
@@ -365,6 +413,8 @@ impl<'docker> Containers<'docker> {
365
413
}
366
414
367
415
/// Lists the container instances on the docker host
416
+ ///
417
+ /// [Api Reference](https://docs.docker.com/engine/api/v1.41/#operation/ContainerList)
368
418
pub async fn list (
369
419
& self ,
370
420
opts : & ContainerListOptions ,
@@ -457,15 +507,17 @@ impl ContainerListOptionsBuilder {
457
507
& mut self ,
458
508
filters : Vec < ContainerFilter > ,
459
509
) -> & mut Self {
460
- let mut param = HashMap :: new ( ) ;
510
+ let mut param: HashMap < & str , Vec < String > > = HashMap :: new ( ) ;
461
511
for f in filters {
462
- match f {
463
- ContainerFilter :: ExitCode ( c) => param . insert ( "exit ", vec ! [ c. to_string( ) ] ) ,
464
- ContainerFilter :: Status ( s) => param . insert ( "status" , vec ! [ s ] ) ,
465
- ContainerFilter :: LabelName ( n) => param . insert ( "label" , vec ! [ n ] ) ,
466
- ContainerFilter :: Label ( n, v) => param . insert ( "label" , vec ! [ format!( "{}={}" , n, v) ] ) ,
467
- ContainerFilter :: Name ( n) => param . insert ( "name" , vec ! [ n ] ) ,
512
+ let ( key , value ) = match f {
513
+ ContainerFilter :: ExitCode ( c) => ( "exited ", c. to_string ( ) ) ,
514
+ ContainerFilter :: Status ( s) => ( "status" , s ) ,
515
+ ContainerFilter :: LabelName ( n) => ( "label" , n ) ,
516
+ ContainerFilter :: Label ( n, v) => ( "label" , format ! ( "{}={}" , n, v) ) ,
517
+ ContainerFilter :: Name ( n) => ( "name" , n . to_string ( ) ) ,
468
518
} ;
519
+
520
+ param. entry ( key) . or_insert_with ( Vec :: new) . push ( value) ;
469
521
}
470
522
// structure is a a json encoded object mapping string keys to a list
471
523
// of string values
@@ -1242,12 +1294,24 @@ pub struct Port {
1242
1294
#[ derive( Clone , Debug , Serialize , Deserialize ) ]
1243
1295
pub struct Stats {
1244
1296
pub read : String ,
1245
- pub networks : HashMap < String , NetworkInfo > ,
1297
+ pub networks : HashMap < String , NetworkStats > ,
1246
1298
pub memory_stats : MemoryStats ,
1247
1299
pub blkio_stats : BlkioStats ,
1248
1300
pub cpu_stats : CpuStats ,
1249
1301
}
1250
1302
1303
+ #[ derive( Clone , Debug , Serialize , Deserialize ) ]
1304
+ pub struct NetworkStats {
1305
+ pub rx_dropped : u64 ,
1306
+ pub rx_bytes : u64 ,
1307
+ pub rx_errors : u64 ,
1308
+ pub tx_packets : u64 ,
1309
+ pub tx_dropped : u64 ,
1310
+ pub rx_packets : u64 ,
1311
+ pub tx_errors : u64 ,
1312
+ pub tx_bytes : u64 ,
1313
+ }
1314
+
1251
1315
#[ derive( Clone , Debug , Serialize , Deserialize ) ]
1252
1316
pub struct MemoryStats {
1253
1317
pub max_usage : u64 ,
@@ -1363,6 +1427,7 @@ pub struct Exit {
1363
1427
#[ cfg( test) ]
1364
1428
mod tests {
1365
1429
use super :: * ;
1430
+ use crate :: container:: ContainerFilter :: { ExitCode , Label , LabelName , Status } ;
1366
1431
1367
1432
#[ test]
1368
1433
fn container_options_simple ( ) {
@@ -1516,6 +1581,69 @@ mod tests {
1516
1581
) ;
1517
1582
}
1518
1583
1584
+ #[ test]
1585
+ fn container_list_options_multiple_labels ( ) {
1586
+ let options = ContainerListOptions :: builder ( )
1587
+ . filter ( vec ! [
1588
+ Label ( "label1" . to_string( ) , "value" . to_string( ) ) ,
1589
+ LabelName ( "label2" . to_string( ) ) ,
1590
+ ] )
1591
+ . build ( ) ;
1592
+
1593
+ let form = form_urlencoded:: Serializer :: new ( String :: new ( ) )
1594
+ . append_pair ( "filters" , r#"{"label":["label1=value","label2"]}"# )
1595
+ . finish ( ) ;
1596
+
1597
+ assert_eq ! ( form, options. serialize( ) . unwrap( ) )
1598
+ }
1599
+
1600
+ #[ test]
1601
+ fn container_list_options_exit_code ( ) {
1602
+ let options = ContainerListOptions :: builder ( )
1603
+ . filter ( vec ! [ ExitCode ( 0 ) ] )
1604
+ . build ( ) ;
1605
+
1606
+ let form = form_urlencoded:: Serializer :: new ( String :: new ( ) )
1607
+ . append_pair ( "filters" , r#"{"exited":["0"]}"# )
1608
+ . finish ( ) ;
1609
+
1610
+ assert_eq ! ( form, options. serialize( ) . unwrap( ) )
1611
+ }
1612
+
1613
+ #[ test]
1614
+ fn container_list_options_status ( ) {
1615
+ let options = ContainerListOptions :: builder ( )
1616
+ . filter ( vec ! [ Status ( "running" . to_string( ) ) ] )
1617
+ . build ( ) ;
1618
+
1619
+ let form = form_urlencoded:: Serializer :: new ( String :: new ( ) )
1620
+ . append_pair ( "filters" , r#"{"status":["running"]}"# )
1621
+ . finish ( ) ;
1622
+
1623
+ assert_eq ! ( form, options. serialize( ) . unwrap( ) )
1624
+ }
1625
+
1626
+ #[ test]
1627
+ fn container_list_options_combined ( ) {
1628
+ let options = ContainerListOptions :: builder ( )
1629
+ . all ( )
1630
+ . filter ( vec ! [
1631
+ Label ( "label1" . to_string( ) , "value" . to_string( ) ) ,
1632
+ LabelName ( "label2" . to_string( ) ) ,
1633
+ ExitCode ( 0 ) ,
1634
+ Status ( "running" . to_string( ) ) ,
1635
+ ] )
1636
+ . build ( ) ;
1637
+
1638
+ let serialized = options. serialize ( ) . unwrap ( ) ;
1639
+
1640
+ assert ! ( serialized. contains( "all=true" ) ) ;
1641
+ assert ! ( serialized. contains( "filters=" ) ) ;
1642
+ assert ! ( serialized. contains( "%22label%22%3A%5B%22label1%3Dvalue%22%2C%22label2%22%5D" ) ) ;
1643
+ assert ! ( serialized. contains( "%22status%22%3A%5B%22running%22%5D" ) ) ;
1644
+ assert ! ( serialized. contains( "%22exited%22%3A%5B%220%22%5D" ) ) ;
1645
+ }
1646
+
1519
1647
#[ cfg( feature = "chrono" ) ]
1520
1648
#[ test]
1521
1649
fn logs_options ( ) {
0 commit comments