Skip to content

Instantly share code, notes, and snippets.

@ammachado
Forked from bencord0/docker-unpack.py
Created June 28, 2018 21:39
Show Gist options
  • Save ammachado/6c1328bb255c75178a381573718e9377 to your computer and use it in GitHub Desktop.
Save ammachado/6c1328bb255c75178a381573718e9377 to your computer and use it in GitHub Desktop.
Unpack a docker image.
#!/usr/bin/env python
import argparse
import json
import os
import sys
import tarfile
parser = argparse.ArgumentParser()
parser.add_argument(
'--image', '-i', required=True,
help='Read from file, instead of STDIN')
parser.add_argument(
'--destination', '-d', default='chroots',
help='Directory to save extracted images')
def main(tf, dest):
manifests = json.loads(tf.extractfile('manifest.json').read().decode('utf-8'))
for manifest in manifests:
layers = manifest['Layers']
repotag, *othertags = manifest["RepoTags"]
print("Found image:", repotag)
for othertag in othertags:
print(" aka:", othertag)
path = os.path.join(dest, repotag.replace('/', '-').replace(':', '-'))
def filter_delete(m):
if '/' in m.name:
dirname, basename = m.name.rsplit('/', 1)
else:
dirname, basename = '', m.name
# Remove files that have been deleted by this layer
if basename.startswith('.wh.') and m.mode == 0:
os.unlink(os.path.join(path, dirname, basename[4:]))
return False
return True
def no_specials(m):
if m.isdir() or m.isfile() or m.islnk() or m.issym():
return True
return False
class mfilter:
checks = [filter_delete]
def __init__(self, members):
self.members = iter(members)
def __iter__(self):
return self
def __next__(self):
while True:
m = next(self.members)
for check in self.checks:
if not check(m):
break
else:
return m
def extract_layer(layer):
with tarfile.open(fileobj=tf.extractfile(layer)) as lyr:
try:
lyr.extractall(path=path, members=mfilter(lyr))
except PermissionError:
mfilter.checks.append(no_specials)
lyr.extractall(path=path, members=mfilter(lyr))
for layer in layers:
print("-----> Extracting layer:", layer)
extract_layer(layer)
print("Extracted `{}` to `{}`".format(repotag, path))
if __name__ == '__main__':
args = parser.parse_args()
with tarfile.open(args.image) as tf:
main(tf, args.destination)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment