|
1 | 1 | import logging |
2 | 2 | import os |
| 3 | +import re |
3 | 4 | import sys |
4 | 5 |
|
5 | 6 | import docker |
| 7 | +from more_itertools import ( |
| 8 | + one, |
| 9 | +) |
6 | 10 |
|
7 | 11 | from azul.logging import ( |
8 | 12 | configure_script_logging, |
|
26 | 30 |
|
27 | 31 | def resolve_container_path(container_path): |
28 | 32 | container_path = os.path.realpath(container_path) |
29 | | - proc_cgroup = '/proc/self/cgroup' |
| 33 | + mountinfo_path = '/proc/self/mountinfo' |
30 | 34 | try: |
31 | | - with open(proc_cgroup) as f: |
32 | | - log.info('Found %s', proc_cgroup) |
33 | | - # Entries in /proc/self/cgroup look like this (note the nesting): |
34 | | - # 11:name=systemd:/docker/82c1bd2…23b5bcf/docker/6547bce…60ca5a7 |
35 | | - prefix, container_id = next(f).strip().split(':')[2].split('/')[-2:] |
| 35 | + with open(mountinfo_path) as f: |
| 36 | + log.info('Trying to extract ID of current container from %s', mountinfo_path) |
| 37 | + # Entries of interest in /proc/self/mountinfo look as follows: |
| 38 | + # 752 744 259:2 /docker/containers/dc61d9…/… |
| 39 | + # dc61d9… is the container ID |
| 40 | + container_ids = set() |
| 41 | + for line in f: |
| 42 | + assert line.endswith('\n'), line |
| 43 | + parts = line[:-1].split(' ') |
| 44 | + assert len(parts) > 9, line |
| 45 | + root = parts[3] |
| 46 | + for prefix in ('/var/lib/docker/containers/', '/docker/containers/'): |
| 47 | + if root.startswith(prefix): |
| 48 | + log.info('Extracting container ID from %s', root) |
| 49 | + id = root[len(prefix):].split('/')[0] |
| 50 | + assert re.fullmatch(r'[0-9a-f]{64}', id), id |
| 51 | + container_ids.add(id) |
36 | 52 | except FileNotFoundError: |
37 | | - log.info('Did not find %s', proc_cgroup) |
| 53 | + log.info('Did not find %s', mountinfo_path) |
38 | 54 | else: |
39 | | - if prefix == 'docker': |
40 | | - api = docker.client.from_env().api |
41 | | - for mount in api.inspect_container(container_id)['Mounts']: |
42 | | - if container_path.startswith(mount['Destination']): |
43 | | - tail = os.path.relpath(container_path, mount['Destination']) |
44 | | - host_path = os.path.normpath(os.path.join(mount['Source'], tail)) |
45 | | - log.info('Resolved %s to %s', container_path, host_path) |
46 | | - return host_path |
| 55 | + api = docker.client.from_env().api |
| 56 | + container_id = one(container_ids) |
| 57 | + for mount in api.inspect_container(container_id)['Mounts']: |
| 58 | + if container_path.startswith(mount['Destination']): |
| 59 | + tail = os.path.relpath(container_path, mount['Destination']) |
| 60 | + host_path = os.path.normpath(os.path.join(mount['Source'], tail)) |
| 61 | + log.info('Resolved %s to %s', container_path, host_path) |
| 62 | + return host_path |
47 | 63 | log.error('Failed to resolve container path %s', container_path) |
48 | 64 | return None |
49 | 65 |
|
|
0 commit comments