tests/docker/docker.py: add update operation

This adds a new operation to the docker script to allow updating of
binaries in an existing container. This is because it would be
inefficient to re-build the whole container just for an update to the
QEMU binary.

To update the executable run:

    ./tests/docker/docker.py update \
        debian:armhf ./arm-linux-user/qemu-arm

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 1468934445-32183-6-git-send-email-famz@redhat.com
Signed-off-by: Fam Zheng <famz@redhat.com>
This commit is contained in:
Alex Bennée 2016-07-19 21:20:40 +08:00 committed by Fam Zheng
parent 95c975013a
commit 6e733da676

View File

@ -21,6 +21,8 @@
import argparse import argparse
import tempfile import tempfile
import re import re
from tarfile import TarFile, TarInfo
from StringIO import StringIO
from shutil import copy, rmtree from shutil import copy, rmtree
def _text_checksum(text): def _text_checksum(text):
@ -94,9 +96,11 @@ def __init__(self):
self._instances = [] self._instances = []
atexit.register(self._kill_instances) atexit.register(self._kill_instances)
def _do(self, cmd, quiet=True, **kwargs): def _do(self, cmd, quiet=True, infile=None, **kwargs):
if quiet: if quiet:
kwargs["stdout"] = subprocess.PIPE kwargs["stdout"] = subprocess.PIPE
if infile:
kwargs["stdin"] = infile
return subprocess.call(self._command + cmd, **kwargs) return subprocess.call(self._command + cmd, **kwargs)
def _do_kill_instances(self, only_known, only_active=True): def _do_kill_instances(self, only_known, only_active=True):
@ -152,6 +156,11 @@ def build_image(self, tag, docker_dir, dockerfile, quiet=True, argv=None):
[docker_dir], [docker_dir],
quiet=quiet) quiet=quiet)
def update_image(self, tag, tarball, quiet=True):
"Update a tagged image using "
self._do(["build", "-t", tag, "-"], quiet=quiet, infile=tarball)
def image_matches_dockerfile(self, tag, dockerfile): def image_matches_dockerfile(self, tag, dockerfile):
try: try:
checksum = self.get_image_dockerfile_checksum(tag) checksum = self.get_image_dockerfile_checksum(tag)
@ -245,6 +254,54 @@ def run(self, args, argv):
return 0 return 0
class UpdateCommand(SubCommand):
""" Update a docker image with new executables. Arguments: <tag> <executable>"""
name = "update"
def args(self, parser):
parser.add_argument("tag",
help="Image Tag")
parser.add_argument("executable",
help="Executable to copy")
def run(self, args, argv):
# Create a temporary tarball with our whole build context and
# dockerfile for the update
tmp = tempfile.NamedTemporaryFile(suffix="dckr.tar.gz")
tmp_tar = TarFile(fileobj=tmp, mode='w')
# Add the executable to the tarball
bn = os.path.basename(args.executable)
ff = "/usr/bin/%s" % bn
tmp_tar.add(args.executable, arcname=ff)
# Add any associated libraries
libs = _get_so_libs(args.executable)
if libs:
for l in libs:
tmp_tar.add(os.path.realpath(l), arcname=l)
# Create a Docker buildfile
df = StringIO()
df.write("FROM %s\n" % args.tag)
df.write("ADD . /\n")
df.seek(0)
df_tar = TarInfo(name="Dockerfile")
df_tar.size = len(df.buf)
tmp_tar.addfile(df_tar, fileobj=df)
tmp_tar.close()
# reset the file pointers
tmp.flush()
tmp.seek(0)
# Run the build with our tarball context
dkr = Docker()
dkr.update_image(args.tag, tmp, quiet=args.quiet)
return 0
class CleanCommand(SubCommand): class CleanCommand(SubCommand):
"""Clean up docker instances""" """Clean up docker instances"""
name = "clean" name = "clean"