@@ -1351,19 +1351,76 @@ pub fn get_image(
1351
1351
Ok ( image)
1352
1352
}
1353
1353
1354
- fn docker_read_mount_paths (
1355
- engine : & Engine ,
1356
- msg_info : & mut MessageInfo ,
1357
- ) -> Result < Vec < MountDetail > > {
1358
- let hostname = env:: var ( "HOSTNAME" ) . wrap_err ( "HOSTNAME environment variable not found" ) ?;
1354
+ fn docker_inspect_self_mountinfo ( engine : & Engine , msg_info : & mut MessageInfo ) -> Result < String > {
1355
+ if cfg ! ( not( target_os = "linux" ) ) {
1356
+ eyre:: bail!( "/proc/self/mountinfo is unavailable when target_os != linux" ) ;
1357
+ }
1358
+
1359
+ // The ID for the current Docker container might be in mountinfo,
1360
+ // somewhere in a mount root. Full IDs are 64-char hexadecimal
1361
+ // strings, so the first matching path segment in a mount root
1362
+ // containing /docker/ is likely to be what we're looking for. See:
1363
+ // https://www.kernel.org/doc/Documentation/filesystems/proc.txt
1364
+ // https://community.toradex.com/t/15240/4
1365
+ let mountinfo = file:: read ( "/proc/self/mountinfo" ) ?;
1366
+ let container_id = mountinfo
1367
+ . lines ( )
1368
+ . filter_map ( |s| s. split ( ' ' ) . nth ( 3 ) )
1369
+ . filter ( |s| s. contains ( "/docker/" ) )
1370
+ . flat_map ( |s| s. split ( '/' ) )
1371
+ . find ( |s| s. len ( ) == 64 && s. as_bytes ( ) . iter ( ) . all ( u8:: is_ascii_hexdigit) )
1372
+ . ok_or_else ( || eyre:: eyre!( "couldn't find container id in mountinfo" ) ) ?;
1373
+
1374
+ engine
1375
+ . subcommand ( "inspect" )
1376
+ . arg ( container_id)
1377
+ . run_and_get_stdout ( msg_info)
1378
+ }
1359
1379
1360
- let mut docker: Command = {
1380
+ fn docker_inspect_self ( engine : & Engine , msg_info : & mut MessageInfo ) -> Result < String > {
1381
+ // Try to find the container ID by looking at HOSTNAME, and fallback to
1382
+ // parsing `/proc/self/mountinfo` if HOSTNAME is unset or if there's no
1383
+ // container that matches it (necessary e.g. when the container uses
1384
+ // `--network=host`, which is act's default, see issue #1321).
1385
+ // If `docker inspect` fails with unexpected output, skip the fallback
1386
+ // and fail instantly.
1387
+ if let Ok ( hostname) = env:: var ( "HOSTNAME" ) {
1361
1388
let mut command = engine. subcommand ( "inspect" ) ;
1362
1389
command. arg ( hostname) ;
1363
- command
1364
- } ;
1390
+ let out = command. run_and_get_output ( msg_info) ?;
1365
1391
1366
- let output = docker. run_and_get_stdout ( msg_info) ?;
1392
+ if out. status . success ( ) {
1393
+ Ok ( out. stdout ( ) ?)
1394
+ } else {
1395
+ let val = serde_json:: from_slice :: < serde_json:: Value > ( & out. stdout ) ;
1396
+ if let Ok ( val) = val {
1397
+ if let Some ( array) = val. as_array ( ) {
1398
+ // `docker inspect` completed but returned an empty array, most
1399
+ // likely indicating that the hostname isn't a valid container ID.
1400
+ if array. is_empty ( ) {
1401
+ msg_info. debug ( "docker inspect found no containers matching HOSTNAME, retrying using mountinfo" ) ?;
1402
+ return docker_inspect_self_mountinfo ( engine, msg_info) ;
1403
+ }
1404
+ }
1405
+ }
1406
+
1407
+ let report = command
1408
+ . status_result ( msg_info, out. status , Some ( & out) )
1409
+ . expect_err ( "we know the command failed" )
1410
+ . to_section_report ( ) ;
1411
+ Err ( report)
1412
+ }
1413
+ } else {
1414
+ msg_info. debug ( "HOSTNAME environment variable is unset" ) ?;
1415
+ docker_inspect_self_mountinfo ( engine, msg_info)
1416
+ }
1417
+ }
1418
+
1419
+ fn docker_read_mount_paths (
1420
+ engine : & Engine ,
1421
+ msg_info : & mut MessageInfo ,
1422
+ ) -> Result < Vec < MountDetail > > {
1423
+ let output = docker_inspect_self ( engine, msg_info) ?;
1367
1424
let info = serde_json:: from_str ( & output) . wrap_err ( "failed to parse docker inspect output" ) ?;
1368
1425
dockerinfo_parse_mounts ( & info)
1369
1426
}
@@ -1674,9 +1731,8 @@ mod tests {
1674
1731
1675
1732
let mut msg_info = MessageInfo :: default ( ) ;
1676
1733
let engine = create_engine ( & mut msg_info) ;
1677
- let hostname = env:: var ( "HOSTNAME" ) ;
1678
- if engine. is_err ( ) || hostname. is_err ( ) {
1679
- eprintln ! ( "could not get container engine or no hostname found" ) ;
1734
+ if engine. is_err ( ) {
1735
+ eprintln ! ( "could not get container engine" ) ;
1680
1736
reset_env ( vars) ;
1681
1737
return Ok ( ( ) ) ;
1682
1738
}
@@ -1686,12 +1742,8 @@ mod tests {
1686
1742
reset_env ( vars) ;
1687
1743
return Ok ( ( ) ) ;
1688
1744
}
1689
- let hostname = hostname. unwrap ( ) ;
1690
- let output = engine
1691
- . subcommand ( "inspect" )
1692
- . arg ( hostname)
1693
- . run_and_get_output ( & mut msg_info) ?;
1694
- if !output. status . success ( ) {
1745
+ let output = docker_inspect_self ( & engine, & mut msg_info) ;
1746
+ if output. is_err ( ) {
1695
1747
eprintln ! ( "inspect failed" ) ;
1696
1748
reset_env ( vars) ;
1697
1749
return Ok ( ( ) ) ;
0 commit comments