Skip to content

Commit

Permalink
A more reliable way to get the container id.
Browse files Browse the repository at this point in the history
The hostname is not always the container id. Get the container id from
/proc/1/cgroup. Fixes #1918.
  • Loading branch information
adarnimrod committed May 27, 2021
1 parent 229a4e0 commit 1de2410
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 40 deletions.
6 changes: 3 additions & 3 deletions pre_commit/languages/docker.py
@@ -1,7 +1,6 @@
import hashlib
import json
import os
import socket
from typing import Sequence
from typing import Tuple

Expand Down Expand Up @@ -29,9 +28,10 @@ def _is_in_docker() -> bool:
def _get_docker_path(path: str) -> str:
if not _is_in_docker():
return path
hostname = socket.gethostname()
with open('/proc/1/cgroup', 'rb') as f:
container_id = os.path.basename(f.readlines()[0]).strip().decode()

_, out, _ = cmd_output_b('docker', 'inspect', hostname)
_, out, _ = cmd_output_b('docker', 'inspect', container_id)

container, = json.loads(out)
for mount in container['Mounts']:
Expand Down
88 changes: 51 additions & 37 deletions tests/languages/docker_test.py
Expand Up @@ -9,6 +9,38 @@

from pre_commit.languages import docker

docker_cgroup_example = b'''\
12:hugetlb:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
11:blkio:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
10:freezer:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
9:cpu,cpuacct:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
8:pids:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
7:rdma:/
6:net_cls,net_prio:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
5:cpuset:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
4:devices:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
3:memory:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
2:perf_event:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
1:name=systemd:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
0::/system.slice/containerd.service
''' # noqa: E501

non_docker_cgroup_example = b'''\
12:perf_event:/
11:hugetlb:/
10:devices:/
9:blkio:/
8:rdma:/
7:cpuset:/
6:cpu,cpuacct:/
5:freezer:/
4:memory:/
3:pids:/
2:net_cls,net_prio:/
1:name=systemd:/init.scope
0::/init.scope
'''


def test_docker_fallback_user():
def invalid_attribute():
Expand Down Expand Up @@ -37,47 +69,19 @@ def _mock_open(data):


def test_in_docker_docker_in_file():
docker_cgroup_example = b'''\
12:hugetlb:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
11:blkio:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
10:freezer:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
9:cpu,cpuacct:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
8:pids:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
7:rdma:/
6:net_cls,net_prio:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
5:cpuset:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
4:devices:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
3:memory:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
2:perf_event:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
1:name=systemd:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7
0::/system.slice/containerd.service
''' # noqa: E501
with _mock_open(docker_cgroup_example):
assert docker._is_in_docker() is True


def test_in_docker_docker_not_in_file():
non_docker_cgroup_example = b'''\
12:perf_event:/
11:hugetlb:/
10:devices:/
9:blkio:/
8:rdma:/
7:cpuset:/
6:cpu,cpuacct:/
5:freezer:/
4:memory:/
3:pids:/
2:net_cls,net_prio:/
1:name=systemd:/init.scope
0::/init.scope
'''
with _mock_open(non_docker_cgroup_example):
assert docker._is_in_docker() is False


def test_get_docker_path_not_in_docker_returns_same():
with mock.patch.object(docker, '_is_in_docker', return_value=False):
with mock.patch.object(
docker, '_is_in_docker', return_value=False,
), _mock_open(non_docker_cgroup_example):
assert docker._get_docker_path('abc') == 'abc'


Expand All @@ -103,23 +107,27 @@ def _docker_output(out):
def test_get_docker_path_in_docker_no_binds_same_path(in_docker):
docker_out = json.dumps([{'Mounts': []}]).encode()

with _docker_output(docker_out):
with _docker_output(docker_out), _mock_open(docker_cgroup_example):
assert docker._get_docker_path('abc') == 'abc'


def test_get_docker_path_in_docker_binds_path_equal(in_docker):
binds_list = [{'Source': '/opt/my_code', 'Destination': '/project'}]
docker_out = json.dumps([{'Mounts': binds_list}]).encode()

with _linux_commonpath(), _docker_output(docker_out):
with _linux_commonpath(), _docker_output(docker_out), _mock_open(
docker_cgroup_example,
):
assert docker._get_docker_path('/project') == '/opt/my_code'


def test_get_docker_path_in_docker_binds_path_complex(in_docker):
binds_list = [{'Source': '/opt/my_code', 'Destination': '/project'}]
docker_out = json.dumps([{'Mounts': binds_list}]).encode()

with _linux_commonpath(), _docker_output(docker_out):
with _linux_commonpath(), _docker_output(docker_out), _mock_open(
docker_cgroup_example,
):
path = '/project/test/something'
assert docker._get_docker_path(path) == '/opt/my_code/test/something'

Expand All @@ -128,7 +136,9 @@ def test_get_docker_path_in_docker_no_substring(in_docker):
binds_list = [{'Source': '/opt/my_code', 'Destination': '/project'}]
docker_out = json.dumps([{'Mounts': binds_list}]).encode()

with _linux_commonpath(), _docker_output(docker_out):
with _linux_commonpath(), _docker_output(docker_out), _mock_open(
docker_cgroup_example,
):
path = '/projectSuffix/test/something'
assert docker._get_docker_path(path) == path

Expand All @@ -141,15 +151,19 @@ def test_get_docker_path_in_docker_binds_path_many_binds(in_docker):
]
docker_out = json.dumps([{'Mounts': binds_list}]).encode()

with _linux_commonpath(), _docker_output(docker_out):
with _linux_commonpath(), _docker_output(docker_out), _mock_open(
docker_cgroup_example,
):
assert docker._get_docker_path('/project') == '/opt/my_code'


def test_get_docker_path_in_docker_windows(in_docker):
binds_list = [{'Source': r'c:\users\user', 'Destination': r'c:\folder'}]
docker_out = json.dumps([{'Mounts': binds_list}]).encode()

with _nt_commonpath(), _docker_output(docker_out):
with _nt_commonpath(), _docker_output(docker_out), _mock_open(
docker_cgroup_example,
):
path = r'c:\folder\test\something'
expected = r'c:\users\user\test\something'
assert docker._get_docker_path(path) == expected

0 comments on commit 1de2410

Please sign in to comment.