mirror of
https://github.com/pre-commit/pre-commit.git
synced 2026-04-15 18:11:48 +04:00
improve Docker env detection heuristic
With cgroupsv2, /proc/1/cgroup contains only `0::/`. Use `/.dockerenv` to detect Docker environment and hostname to detect the current container id.
This commit is contained in:
parent
5f0c773e74
commit
7b1b6604bb
2 changed files with 33 additions and 4 deletions
|
|
@ -4,6 +4,8 @@ import functools
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import socket
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
|
|
||||||
from pre_commit import lang_base
|
from pre_commit import lang_base
|
||||||
|
|
@ -21,9 +23,11 @@ in_env = lang_base.no_env # no special environment for docker
|
||||||
def _is_in_docker() -> bool:
|
def _is_in_docker() -> bool:
|
||||||
try:
|
try:
|
||||||
with open('/proc/1/cgroup', 'rb') as f:
|
with open('/proc/1/cgroup', 'rb') as f:
|
||||||
return b'docker' in f.read()
|
if b'docker' in f.read():
|
||||||
|
return True
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return False
|
pass
|
||||||
|
return os.path.exists('/.dockerenv')
|
||||||
|
|
||||||
|
|
||||||
def _get_container_id() -> str:
|
def _get_container_id() -> str:
|
||||||
|
|
@ -34,6 +38,9 @@ def _get_container_id() -> str:
|
||||||
for line in f.readlines():
|
for line in f.readlines():
|
||||||
if line.split(b':')[1] == b'cpuset':
|
if line.split(b':')[1] == b'cpuset':
|
||||||
return os.path.basename(line.split(b':')[2]).strip().decode()
|
return os.path.basename(line.split(b':')[2]).strip().decode()
|
||||||
|
hostname = socket.gethostname()
|
||||||
|
if re.match(r'^[0-9a-f]{12}$', hostname):
|
||||||
|
return hostname
|
||||||
raise RuntimeError('Failed to find the container ID in /proc/1/cgroup.')
|
raise RuntimeError('Failed to find the container ID in /proc/1/cgroup.')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,13 @@ DOCKER_CGROUP_EXAMPLE = b'''\
|
||||||
0::/system.slice/containerd.service
|
0::/system.slice/containerd.service
|
||||||
''' # noqa: E501
|
''' # noqa: E501
|
||||||
|
|
||||||
|
DOCKER_CGROUPV2_EXAMPLE = b"""\
|
||||||
|
0::/
|
||||||
|
"""
|
||||||
|
|
||||||
# The ID should match the above cgroup example.
|
# The ID should match the above cgroup example.
|
||||||
CONTAINER_ID = 'c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7' # noqa: E501
|
CONTAINER_ID = 'c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7' # noqa: E501
|
||||||
|
SHORT_CONTAINER_ID = CONTAINER_ID[:12]
|
||||||
|
|
||||||
NON_DOCKER_CGROUP_EXAMPLE = b'''\
|
NON_DOCKER_CGROUP_EXAMPLE = b'''\
|
||||||
12:perf_event:/
|
12:perf_event:/
|
||||||
|
|
@ -117,8 +122,17 @@ def test_in_docker_docker_in_file():
|
||||||
assert docker._is_in_docker() is True
|
assert docker._is_in_docker() is True
|
||||||
|
|
||||||
|
|
||||||
|
def _mock_dockerenv(exists):
|
||||||
|
return mock.patch('os.path.exists', return_value=exists)
|
||||||
|
|
||||||
|
|
||||||
|
def test_in_docker_cgroupv2():
|
||||||
|
with _mock_open(DOCKER_CGROUPV2_EXAMPLE), _mock_dockerenv(True):
|
||||||
|
assert docker._is_in_docker() is True
|
||||||
|
|
||||||
|
|
||||||
def test_in_docker_docker_not_in_file():
|
def test_in_docker_docker_not_in_file():
|
||||||
with _mock_open(NON_DOCKER_CGROUP_EXAMPLE):
|
with _mock_open(NON_DOCKER_CGROUP_EXAMPLE), _mock_dockerenv(False):
|
||||||
assert docker._is_in_docker() is False
|
assert docker._is_in_docker() is False
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -127,8 +141,16 @@ def test_get_container_id():
|
||||||
assert docker._get_container_id() == CONTAINER_ID
|
assert docker._get_container_id() == CONTAINER_ID
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_container_id_cgroupv2():
|
||||||
|
with _mock_open(DOCKER_CGROUPV2_EXAMPLE), \
|
||||||
|
mock.patch('socket.gethostname', return_value=SHORT_CONTAINER_ID):
|
||||||
|
assert docker._get_container_id() == SHORT_CONTAINER_ID
|
||||||
|
|
||||||
|
|
||||||
def test_get_container_id_failure():
|
def test_get_container_id_failure():
|
||||||
with _mock_open(b''), pytest.raises(RuntimeError):
|
with _mock_open(b''), \
|
||||||
|
mock.patch('socket.gethostname', return_value='foo'), \
|
||||||
|
pytest.raises(RuntimeError):
|
||||||
docker._get_container_id()
|
docker._get_container_id()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue