Files
molecules/bin/undocker.py

130 lines
3.7 KiB
Python
Executable File

#!/usr/bin/env python
import argparse
import json
import logging
import os
import sys
import tarfile
import tempfile
from contextlib import closing
LOG = logging.getLogger(__name__)
def parse_args():
p = argparse.ArgumentParser()
p.add_argument('--ignore-errors', '-i',
action='store_true',
help='Ignore OS errors when extracting files')
p.add_argument('--output', '-o',
default='.',
help='Output directory (defaults to ".")')
p.add_argument('--verbose', '-v',
action='store_const',
const=logging.INFO,
dest='loglevel')
p.add_argument('--debug', '-d',
action='store_const',
const=logging.DEBUG,
dest='loglevel')
p.add_argument('--layers',
action='store_true',
help='List layers in an image')
p.add_argument('--list', '--ls',
action='store_true',
help='List images/tags contained in archive')
p.add_argument('--layer', '-l',
action='append',
help='Extract only the specified layer')
p.add_argument('image', nargs='?')
p.set_defaults(level=logging.WARN)
return p.parse_args()
def find_layers(img, id):
with closing(img.extractfile('%s/json' % id)) as fd:
info = json.load(fd)
LOG.debug('layer = %s', id)
for k in ['os', 'architecture', 'author', 'created']:
if k in info:
LOG.debug('%s = %s', k, info[k])
yield id
if 'parent' in info:
pid = info['parent']
for layer in find_layers(img, pid):
yield layer
def main():
args = parse_args()
logging.basicConfig(level=args.loglevel)
with tempfile.NamedTemporaryFile() as fd:
while True:
data = sys.stdin.read(8192)
if not data:
break
fd.write(data)
fd.seek(0)
with tarfile.TarFile(fileobj=fd) as img:
repos = img.extractfile('repositories')
repos = json.load(repos)
if args.list:
for name, tags in repos.items():
print '%s: %s' % (
name,
' '.join(tags))
sys.exit(0)
if not args.image:
if len(repos) == 1:
args.image = repos.keys()[0]
else:
LOG.error('No image name specified and multiple '
'images contained in archive')
sys.exit(1)
try:
name, tag = args.image.split(':', 1)
except ValueError:
name, tag = args.image, 'latest'
try:
top = repos[name][tag]
except KeyError:
LOG.error('failed to find image %s with tag %s',
name,
tag)
sys.exit(1)
LOG.info('extracting image %s (%s)', name, top)
layers = list(find_layers(img, top))
if args.layers:
print '\n'.join(reversed(layers))
sys.exit(0)
if not os.path.isdir(args.output):
os.mkdir(args.output)
for id in reversed(layers):
if args.layer and not id in args.layer:
continue
LOG.info('extracting layer %s', id)
with tarfile.TarFile(
fileobj=img.extractfile('%s/layer.tar' % id),
errorlevel=(0 if args.ignore_errors else 1)) as layer:
layer.extractall(path=args.output)
if __name__ == '__main__':
main()