Ejemplo n.º 1
0
 def extract(archive_location, extracted_location, skip_symlinks=False):
     """
     Extract the image archive tarball at ``archive_location`` to
     ``extracted_location``. Skip symlinks and links if ``skip_symlinks`` is True.
     """
     utils.extract_tar(
         location=archive_location,
         target_dir=extracted_location,
         skip_symlinks=skip_symlinks,
     )
Ejemplo n.º 2
0
 def get_images_from_tarball(location, target_dir, force_extract=False):
     """
     Yield Image objects found in the tarball at `location` that will be
     extracted to `target_dir`. The tarball must be in the format of a "docker
     save" command tarball.
     If `force_extract` is False, do not extract to target_dir if target_dir
     already exists
     """
     if force_extract or not os.path.exists(target_dir):
         utils.extract_tar(location, target_dir)
     return Image.get_images_from_dir(target_dir)
Ejemplo n.º 3
0
 def extract(self, extracted_location, skip_symlinks=True):
     """
     Extract this layer archive in the `extracted_location` directory and set
     this Layer ``extracted_location`` attribute to ``extracted_location``.
     """
     self.extracted_location = extracted_location
     utils.extract_tar(
         location=self.archive_location,
         target_dir=extracted_location,
         skip_symlinks=skip_symlinks,
     )
Ejemplo n.º 4
0
    def extract(self, target_dir, use_layer_id=True, force_extract=False):
        """
        Extract layer tarball to `target_dir` directory.
        If `use_layer_id` is True, extract in a dir named ``target_dir/layer_id/``
        Cache the location where this layer was last extracted in the
        ``self.extracted_to_location`` attribute.

        If `force_extract` is False, do not extract if self.extracted_to_location
        already exists
        """
        if use_layer_id:
            self.extracted_to_location = path.join(target_dir, self.layer_id)

        if force_extract or not os.path.exists(self.extracted_to_location):
            utils.extract_tar(self.layer_location, self.extracted_to_location)
Ejemplo n.º 5
0
 def test_extract_tree_with_colon_in_filenames(self):
     expected = (
         'colon/libc6:amd64.list',
     )
     test_dir = self.get_test_loc('tar/colon.tar.xz')
     temp_dir = self.get_temp_dir()
     errors = utils.extract_tar(location=test_dir, target_dir=temp_dir)
     check_files(temp_dir, expected)
     assert not errors
Ejemplo n.º 6
0
 def test_extract_tar_absolute(self):
     expected = (
         'tmp/subdir/a.txt',
         'tmp/subdir/b.txt',
     )
     test_dir = self.get_test_loc('tar/absolute_path.tar')
     temp_dir = self.get_temp_dir()
     errors = utils.extract_tar(location=test_dir, target_dir=temp_dir)
     check_files(temp_dir, expected)
     assert not errors
Ejemplo n.º 7
0
 def test_extract_tar_relative(self):
     expected = ()
     test_dir = self.get_test_loc('tar/tar_relative.tar')
     temp_dir = self.get_temp_dir()
     errors = utils.extract_tar(location=test_dir, target_dir=temp_dir)
     check_files(temp_dir, expected)
     assert errors
     for error in errors:
         assert 'skipping unsupported' in error
         assert 'with relative path' in error
Ejemplo n.º 8
0
def rebuild_rootfs(img, target_dir):
    """
    Extract and merge all layers of the `image` Image in `target_dir`.
    Extraction is done in sequence from bottom (root) to top (latest layer)
    and the "whiteout" unionfs/overlayfs procedure is applied at each step
    as per the OCI spec:
        https://github.com/opencontainers/image-spec/blob/master/layer.md#whiteouts

    Return a list of deleted "whiteout" files.

    The extraction process consists of these steps:
     - extract the layer in a temp directory
     - find whiteouts in that layer temp dir
     - remove files/directories corresponding to these whiteouts in the target directory
     - remove whiteouts special marker files or dirs in the tempdirectory
     - move layer to the target directory, overwriting existing files

    See also some related implementations and links:
    https://github.com/moby/moby/blob/d1f470946/pkg/archive/whiteouts.go
    https://github.com/virt-manager/virt-bootstrap/commit/8a7e752d6614f8425874adbbdab16443ee0b1d9b
    https://github.com/goldmann/docker-squash


    https://github.com/moby/moby/blob/master/image/spec/v1.md
    https://github.com/moby/moby/blob/master/image/spec/v1.1.md
    https://github.com/moby/moby/blob/master/image/spec/v1.2.md
    """

    assert path.isdir(target_dir)
    assert path.exists(target_dir)
    extract_errors = []
    # log  deletions
    deletions = []

    for layer_num, layer in enumerate(img.layers):
        layer_id = layer.layer_id
        layer_tarball = path.join(img.base_location, layer_id, LAYER_TAR_FILE)
        logger.debug(
            'Extracting layer {layer_num} tarball: {layer_tarball}'.format(
                **locals()))
        temp_target = tempfile.mkdtemp('container_inspector-docker')

        # 1. extract a layer to temp.
        # Note that we are not preserving any special file and any file permission
        utils.extract_tar(location=layer_tarball, target_dir=temp_target)
        logger.debug('  Extracted layer to: {}'.format(temp_target))

        # 2. find whiteouts in that layer.
        layer_whiteouts = list(find_whiteouts(temp_target))
        logger.debug(
            '  Merging extracted layers and applying AUFS whiteouts/deletes')
        logger.debug('  Whiteouts:\n' +
                     '     \n'.join(map(repr, layer_whiteouts)))

        # 3. remove whiteouts in the previous layer stack (e.g. the WIP rootfs)
        for layer_whiteout_marker, target_whiteable_path in layer_whiteouts:
            logger.debug(
                '    Deleting whiteout dir or file: {target_whiteable_path}'.
                format(**locals()))
            whiteable = path.join(target_dir, target_whiteable_path)
            utils.delete(whiteable)
            # also delete the whiteout marker file
            utils.delete(layer_whiteout_marker)
            deletions.extend(target_whiteable_path)

        # 4. finall copy/overwrite the extracted layer over the WIP rootfs
        logger.debug(
            '  Moving extracted layer from: {temp_target} to: {target_dir}'.
            format(**locals()))
        utils.copytree(temp_target, target_dir)
        logger.debug('  Moved layer to: {}'.format(target_dir))
        utils.delete(temp_target)

    return deletions