docker-assemble 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- docker_assemble/__init__.py +0 -0
- docker_assemble/docker_utils.py +5 -0
- docker_assemble/image_exporter.py +68 -0
- docker_assemble/main.py +18 -0
- docker_assemble-0.1.0.dist-info/METADATA +25 -0
- docker_assemble-0.1.0.dist-info/RECORD +9 -0
- docker_assemble-0.1.0.dist-info/WHEEL +5 -0
- docker_assemble-0.1.0.dist-info/entry_points.txt +2 -0
- docker_assemble-0.1.0.dist-info/top_level.txt +1 -0
|
File without changes
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import docker
|
|
2
|
+
import tarfile
|
|
3
|
+
import tempfile
|
|
4
|
+
import os
|
|
5
|
+
import shutil
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
def extract_image(image_name: str, output_dir: str):
|
|
10
|
+
client = docker.from_env()
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
image = client.images.get(image_name)
|
|
14
|
+
logging.info(f"Image '{image_name}' found locally.")
|
|
15
|
+
except docker.errors.ImageNotFound:
|
|
16
|
+
logging.info(f"Image '{image_name}' not found locally. Pulling...")
|
|
17
|
+
image = client.images.pull(image_name)
|
|
18
|
+
|
|
19
|
+
container = client.containers.run(image=image_name, command="sleep infinity", detach=True)
|
|
20
|
+
logging.debug(f"Created temporary container: {container.id[:12]}")
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
stream, _ = container.get_archive("/")
|
|
24
|
+
tmp_tar_path = tempfile.mktemp(suffix=".tar")
|
|
25
|
+
with open(tmp_tar_path, "wb") as f:
|
|
26
|
+
for chunk in stream:
|
|
27
|
+
f.write(chunk)
|
|
28
|
+
|
|
29
|
+
logging.debug(f"Filesystem archive saved to: {tmp_tar_path}")
|
|
30
|
+
|
|
31
|
+
output_path = Path(output_dir).resolve()
|
|
32
|
+
output_path.mkdir(parents=True, exist_ok=True)
|
|
33
|
+
|
|
34
|
+
extract_tar_safely(tmp_tar_path, output_path)
|
|
35
|
+
|
|
36
|
+
logging.info(f"Image filesystem extracted to: {output_path}")
|
|
37
|
+
|
|
38
|
+
finally:
|
|
39
|
+
container.remove(force=True)
|
|
40
|
+
if os.path.exists(tmp_tar_path):
|
|
41
|
+
os.remove(tmp_tar_path)
|
|
42
|
+
logging.debug("Cleaned up temporary container and tar file.")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def extract_tar_safely(tar_path: str, output_path: Path):
|
|
46
|
+
# def is_safe_path(base: Path, target: Path) -> bool:
|
|
47
|
+
# try:
|
|
48
|
+
# return target.resolve().is_relative_to(base.resolve())
|
|
49
|
+
# except AttributeError:
|
|
50
|
+
# # For Python < 3.9 fallback
|
|
51
|
+
# return str(target.resolve()).startswith(str(base.resolve()))
|
|
52
|
+
|
|
53
|
+
with tarfile.open(tar_path, "r") as tar:
|
|
54
|
+
for member in tar.getmembers():
|
|
55
|
+
member.name = member.name.lstrip("/")
|
|
56
|
+
member_path = output_path / member.name
|
|
57
|
+
|
|
58
|
+
# if not is_safe_path(output_path, member_path):
|
|
59
|
+
# logging.warning(f"Blocked unsafe path: {member.name}, output_path: {output_path}, member_path: {member_path}")
|
|
60
|
+
# continue
|
|
61
|
+
|
|
62
|
+
tar.extract(member, path=output_path)
|
|
63
|
+
logging.debug(f"Extracted: {member.name}")
|
|
64
|
+
|
|
65
|
+
logging.info(f"Extraction completed to: {output_path}")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
docker_assemble/main.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
from docker_assemble.image_exporter import extract_image
|
|
5
|
+
|
|
6
|
+
def run():
|
|
7
|
+
parser = argparse.ArgumentParser(description="Docker Assemble CLI")
|
|
8
|
+
parser.add_argument("-d", action="store_true", help="Disassemble an image")
|
|
9
|
+
parser.add_argument("--debug", action="store_true", help="Enable debug mode")
|
|
10
|
+
parser.add_argument("image", help="Docker image name")
|
|
11
|
+
parser.add_argument("output_dir", nargs="?", default=".", help="Optional output directory")
|
|
12
|
+
|
|
13
|
+
args = parser.parse_args()
|
|
14
|
+
|
|
15
|
+
logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO)
|
|
16
|
+
|
|
17
|
+
logging.debug(f"Extracting image: {args.image} to directory: {args.output_dir}")
|
|
18
|
+
extract_image(image_name=args.image, output_dir=args.output_dir)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: docker-assemble
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A CLI tool to extract and analyze Docker images
|
|
5
|
+
Author: Sina Kashipazha
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: docker>=6.0.0
|
|
10
|
+
|
|
11
|
+
# docker-assemble
|
|
12
|
+
|
|
13
|
+
A CLI tool to extract and analyze Docker images for research & optimization purposes.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install docker-assemble
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
docker-assemble -d ubuntu:20.04 output_dir
|
|
25
|
+
```
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
docker_assemble/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
docker_assemble/docker_utils.py,sha256=kxEFEGUR1qO1bWwdJzLFRhwF6ejr1VWt2FflzwtCaAY,104
|
|
3
|
+
docker_assemble/image_exporter.py,sha256=vCylMBJS5FiVIfX7djxmo_-cCKB7dO4pTITUn2jaNQE,2288
|
|
4
|
+
docker_assemble/main.py,sha256=YN8hIKX59NIZWXQchZbGgpex2bvb8_ECaarImUmDeZw,764
|
|
5
|
+
docker_assemble-0.1.0.dist-info/METADATA,sha256=HqThiGS74UHvoqR35bFE2egDIAd7bnxiiUBFLRfTVZM,482
|
|
6
|
+
docker_assemble-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
+
docker_assemble-0.1.0.dist-info/entry_points.txt,sha256=eCHj2yf-IrJI3KlkWGYFlZxA5gwS4KP2nynEKKPiTq4,61
|
|
8
|
+
docker_assemble-0.1.0.dist-info/top_level.txt,sha256=SBZ5oqc6t1oj0QSyM7fDrXarkFbEdAPOMVaF9B0fAew,16
|
|
9
|
+
docker_assemble-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
docker_assemble
|