@@ -1351,19 +1351,76 @@ pub fn get_image(
13511351 Ok ( image)
13521352}
13531353
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+ }
13591379
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" ) {
13611388 let mut command = engine. subcommand ( "inspect" ) ;
13621389 command. arg ( hostname) ;
1363- command
1364- } ;
1390+ let out = command. run_and_get_output ( msg_info) ?;
13651391
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) ?;
13671424 let info = serde_json:: from_str ( & output) . wrap_err ( "failed to parse docker inspect output" ) ?;
13681425 dockerinfo_parse_mounts ( & info)
13691426}
@@ -1674,9 +1731,8 @@ mod tests {
16741731
16751732 let mut msg_info = MessageInfo :: default ( ) ;
16761733 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" ) ;
16801736 reset_env ( vars) ;
16811737 return Ok ( ( ) ) ;
16821738 }
@@ -1686,12 +1742,8 @@ mod tests {
16861742 reset_env ( vars) ;
16871743 return Ok ( ( ) ) ;
16881744 }
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 ( ) {
16951747 eprintln ! ( "inspect failed" ) ;
16961748 reset_env ( vars) ;
16971749 return Ok ( ( ) ) ;
0 commit comments