Beispiel #1
0
def load_image(url, imageName=None, imageTag=None):
    """
    Load docker image from URL as imageName:tag, if no imageName or tag is given
    it will use whatever is inside the zstd compressed tarball.

    Returns an object with properties 'image', 'tag' and 'layer'.
    """
    # If imageName is given and we don't have an imageTag
    # we parse out the imageTag from imageName, or default it to 'latest'
    # if no imageName and no imageTag is given, 'repositories' won't be rewritten
    if imageName and not imageTag:
        if ':' in imageName:
            imageName, imageTag = imageName.split(':', 1)
        else:
            imageTag = 'latest'

    curl, zstd, docker = None, None, None
    image, tag, layer = None, None, None
    error = None
    try:
        # Setup piping: curl | zstd | tarin
        curl = Popen(['curl', '-#', '--fail', '-L', '--retry', '8', url], stdout=PIPE)
        zstd = Popen(['zstd', '-d'], stdin=curl.stdout, stdout=PIPE)
        tarin = tarfile.open(mode='r|', fileobj=zstd.stdout)
        # Seutp piping: tarout | docker
        docker = Popen(['docker', 'load'], stdin=PIPE)
        tarout = tarfile.open(mode='w|', fileobj=docker.stdin, format=tarfile.GNU_FORMAT)

        # Read from tarin and write to tarout
        for member in tarin:
            # Write non-file members directly (don't use extractfile on links)
            if not member.isfile():
                tarout.addfile(member)
                continue

            # Open reader for the member
            reader = tarin.extractfile(member)

            # If member is repository, we parse and possibly rewrite the image tags
            if member.name == 'repositories':
                # Read and parse repositories
                repos = json.loads(reader.read())
                reader.close()

                # If there is more than one image or tag, we can't handle it here
                if len(repos.keys()) > 1:
                    raise Exception('file contains more than one image')
                image = repos.keys()[0]
                if len(repos[image].keys()) > 1:
                    raise Exception('file contains more than one tag')
                tag = repos[image].keys()[0]
                layer = repos[image][tag]

                # Rewrite the repositories file
                data = json.dumps({imageName or image: {imageTag or tag: layer}})
                reader = BytesIO(data)
                member.size = len(data)

            # Add member and reader
            tarout.addfile(member, reader)
            reader.close()
        tarout.close()
    except Exception:
        error = sys.exc_info()[0]
    finally:
        def trykill(proc):
            try:
                proc.kill()
            except:
                pass

        # Check that all subprocesses finished correctly
        if curl and curl.wait() != 0:
            trykill(zstd)
            trykill(docker)
            raise Exception('failed to download from url: {}'.format(url))
        if zstd and zstd.wait() != 0:
            trykill(docker)
            raise Exception('zstd decompression failed')
        if docker:
            docker.stdin.close()
        if docker and docker.wait() != 0:
            raise Exception('loading into docker failed')
        if error:
            raise error

    # Check that we found a repositories file
    if not image or not tag or not layer:
        raise Exception('No repositories file found!')

    return {'image': image, 'tag': tag, 'layer': layer}
Beispiel #2
0
def load_image(url, imageName=None, imageTag=None):
    """
    Load docker image from URL as imageName:tag, if no imageName or tag is given
    it will use whatever is inside the zstd compressed tarball.

    Returns an object with properties 'image', 'tag' and 'layer'.
    """
    # If imageName is given and we don't have an imageTag
    # we parse out the imageTag from imageName, or default it to 'latest'
    # if no imageName and no imageTag is given, 'repositories' won't be rewritten
    if imageName and not imageTag:
        if ':' in imageName:
            imageName, imageTag = imageName.split(':', 1)
        else:
            imageTag = 'latest'

    curl, zstd, docker = None, None, None
    image, tag, layer = None, None, None
    error = None
    try:
        # Setup piping: curl | zstd | tarin
        curl = Popen(['curl', '-#', '--fail', '-L', '--retry', '8', url], stdout=PIPE)
        zstd = Popen(['zstd', '-d'], stdin=curl.stdout, stdout=PIPE)
        tarin = tarfile.open(mode='r|', fileobj=zstd.stdout)
        # Seutp piping: tarout | docker
        docker = Popen(['docker', 'load'], stdin=PIPE)
        tarout = tarfile.open(mode='w|', fileobj=docker.stdin, format=tarfile.GNU_FORMAT)

        # Read from tarin and write to tarout
        for member in tarin:
            # Write non-file members directly (don't use extractfile on links)
            if not member.isfile():
                tarout.addfile(member)
                continue

            # Open reader for the member
            reader = tarin.extractfile(member)

            # If member is repository, we parse and possibly rewrite the image tags
            if member.name == 'repositories':
                # Read and parse repositories
                repos = json.loads(reader.read())
                reader.close()

                # If there is more than one image or tag, we can't handle it here
                if len(repos.keys()) > 1:
                    raise Exception('file contains more than one image')
                image = repos.keys()[0]
                if len(repos[image].keys()) > 1:
                    raise Exception('file contains more than one tag')
                tag = repos[image].keys()[0]
                layer = repos[image][tag]

                # Rewrite the repositories file
                data = json.dumps({imageName or image: {imageTag or tag: layer}})
                reader = BytesIO(data)
                member.size = len(data)

            # Add member and reader
            tarout.addfile(member, reader)
            reader.close()
        tarout.close()
    except Exception:
        error = sys.exc_info()[0]
    finally:
        def trykill(proc):
            try:
                proc.kill()
            except:
                pass

        # Check that all subprocesses finished correctly
        if curl and curl.wait() != 0:
            trykill(zstd)
            trykill(docker)
            raise Exception('failed to download from url: {}'.format(url))
        if zstd and zstd.wait() != 0:
            trykill(docker)
            raise Exception('zstd decompression failed')
        if docker:
            docker.stdin.close()
        if docker and docker.wait() != 0:
            raise Exception('loading into docker failed')
        if error:
            raise error

    # Check that we found a repositories file
    if not image or not tag or not layer:
        raise Exception('No repositories file found!')

    return {'image': image, 'tag': tag, 'layer': layer}