Beispiel #1
0
 def test_oci_tool_buildah(
     self, mock_RuntimeConfig, mock_OCIBuildah
 ):
     self.runtime_config.get_oci_archive_tool.return_value = 'buildah'
     mock_RuntimeConfig.return_value = self.runtime_config
     OCI.new()
     mock_OCIBuildah.assert_called_once_with()
Beispiel #2
0
 def test_oci_tool_umoci(
     self, mock_RuntimeConfig, mock_OCIUmoci
 ):
     self.runtime_config.get_oci_archive_tool.return_value = 'umoci'
     mock_RuntimeConfig.return_value = self.runtime_config
     OCI.new()
     mock_OCIUmoci.assert_called_once_with()
Beispiel #3
0
    def sync_data(self):
        """
        Synchronize data from the given base image to the target root
        directory.
        """
        if not self.unknown_uri:
            compressor = Compress(self.image_file)
            if compressor.get_format():
                compressor.uncompress(True)
                self.uncompressed_image = compressor.uncompressed_filename
            else:
                self.uncompressed_image = self.image_file
            image_uri = '{0}:{1}'.format(
                self.archive_transport, self.uncompressed_image
            )
        else:
            log.warning('Bypassing base image URI to OCI tools')
            image_uri = self.unknown_uri

        oci = OCI()
        oci.import_container_image(image_uri)
        oci.unpack()
        oci.import_rootfs(self.root_dir)

        # A copy of the uncompressed image and its checksum are
        # kept inside the root_dir in order to ensure the later steps
        # i.e. system create are atomic and don't need any third
        # party archive.
        image_copy = Defaults.get_imported_root_image(self.root_dir)
        Path.create(os.path.dirname(image_copy))
        oci.export_container_image(
            image_copy, 'oci-archive', Defaults.get_container_base_image_tag()
        )
        self._make_checksum(image_copy)
Beispiel #4
0
    def __init__(self, root_dir, custom_args=None):
        self.root_dir = root_dir
        self.oci_root_dir = None
        if custom_args:
            self.oci_config = custom_args
        else:
            self.oci_config = {}

        self.runtime_config = RuntimeConfig()

        # for builds inside the buildservice we include a reference to the
        # specific build. Thus disturl label only exists inside the
        # buildservice.
        if Defaults.is_buildservice_worker():
            bs_label = 'org.openbuildservice.disturl'
            # Do not label anything if any build service label is
            # already present
            if 'labels' not in self.oci_config or \
                    bs_label not in self.oci_config['labels']:
                self._append_buildservice_disturl_label()

        if 'container_name' not in self.oci_config:
            log.info('No container configuration provided, '
                     'using default container name "kiwi-container:latest"')
            self.oci_config['container_name'] = \
                Defaults.get_default_container_name()
            self.oci_config['container_tag'] = \
                Defaults.get_default_container_tag()

        if 'container_tag' not in self.oci_config:
            self.oci_config['container_tag'] = \
                Defaults.get_default_container_tag()

        if 'entry_command' not in self.oci_config and \
                'entry_subcommand' not in self.oci_config:
            self.oci_config['entry_subcommand'] = \
                Defaults.get_default_container_subcommand()

        if 'history' not in self.oci_config:
            self.oci_config['history'] = {}
        if 'created_by' not in self.oci_config['history']:
            self.oci_config['history']['created_by'] = \
                Defaults.get_default_container_created_by()

        self.oci = OCI(self.oci_config['container_tag'])
Beispiel #5
0
    def create(self, filename, base_image, ensure_empty_tmpdirs=True):
        """
        Create compressed oci system container tar archive

        :param string filename: archive file name
        :param string base_image: archive used as a base image
        """
        exclude_list = Defaults.\
            get_exclude_list_for_root_data_sync(ensure_empty_tmpdirs) + Defaults.\
            get_exclude_list_from_custom_exclude_files(self.root_dir)
        exclude_list.append('dev/*')
        exclude_list.append('sys/*')
        exclude_list.append('proc/*')

        oci = OCI.new()
        if base_image:
            oci.import_container_image('oci-archive:{0}:{1}'.format(
                base_image, Defaults.get_container_base_image_tag()))
        else:
            # Apply default subcommand only for base images
            if 'entry_command' not in self.oci_config and \
                    'entry_subcommand' not in self.oci_config:
                self.oci_config['entry_subcommand'] = \
                    Defaults.get_default_container_subcommand()
            oci.init_container()

        image_ref = '{0}:{1}'.format(self.oci_config['container_name'],
                                     self.oci_config['container_tag'])

        oci.unpack()
        oci.sync_rootfs(self.root_dir, exclude_list)
        oci.repack(self.oci_config)
        oci.set_config(self.oci_config)
        oci.post_process()

        image_ref = '{0}:{1}'.format(self.oci_config['container_name'],
                                     self.oci_config['container_tag'])
        additional_refs = []
        if self.archive_transport == 'docker-archive':
            if 'additional_names' in self.oci_config:
                additional_refs = []
                for name in self.oci_config['additional_names']:
                    name_parts = name.partition(':')
                    if not name_parts[0]:
                        additional_refs.append('{0}:{1}'.format(
                            self.oci_config['container_name'], name_parts[2]))
                    elif not name_parts[2]:
                        additional_refs.append('{0}:{1}'.format(
                            name_parts[0], self.oci_config['container_tag']))
                    else:
                        additional_refs.append('{0}:{1}'.format(
                            name_parts[0], name_parts[2]))

        oci.export_container_image(filename, self.archive_transport, image_ref,
                                   additional_refs)

        return filename
Beispiel #6
0
    def create(self, filename, base_image):
        """
        Create compressed oci system container tar archive

        :param string filename: archive file name
        :param string base_image: archive used as a base image
        """
        exclude_list = Defaults.get_exclude_list_for_root_data_sync()
        exclude_list.append('dev/*')
        exclude_list.append('sys/*')
        exclude_list.append('proc/*')

        oci = OCI.new()
        if base_image:
            oci.import_container_image(
                'oci-archive:{0}:{1}'.format(
                    base_image, Defaults.get_container_base_image_tag()
                )
            )
        else:
            oci.init_container()

        image_ref = '{0}:{1}'.format(
            self.oci_config['container_name'], self.oci_config['container_tag']
        )

        oci.unpack()
        oci.sync_rootfs(self.root_dir, exclude_list)
        oci.repack(self.oci_config)
        oci.set_config(self.oci_config)
        oci.post_process()

        if self.archive_transport == 'docker-archive':
            image_ref = '{0}:{1}'.format(
                self.oci_config['container_name'],
                self.oci_config['container_tag']
            )
            additional_refs = []
            if 'additional_tags' in self.oci_config:
                additional_refs = []
                for tag in self.oci_config['additional_tags']:
                    additional_refs.append('{0}:{1}'.format(
                        self.oci_config['container_name'], tag
                    ))
        else:
            image_ref = self.oci_config['container_tag']
            additional_refs = []

        oci.export_container_image(
            filename, self.archive_transport, image_ref, additional_refs
        )

        if self.runtime_config.get_container_compression():
            compressor = Compress(filename)
            return compressor.xz(self.runtime_config.get_xz_options())
        else:
            return filename
Beispiel #7
0
    def sync_data(self):
        """
        Synchronize data from the given base image to the target root
        directory.
        """
        self.extract_oci_image()

        oci = OCI('base_layer', self.oci_layout_dir)
        oci.unpack()
        oci.import_rootfs(self.root_dir)

        # A copy of the uncompressed image and its checksum are
        # kept inside the root_dir in order to ensure the later steps
        # i.e. system create are atomic and don't need any third
        # party archive.
        image_copy = Defaults.get_imported_root_image(self.root_dir)
        Path.create(os.path.dirname(image_copy))
        image_tar = ArchiveTar(image_copy)
        image_tar.create(self.oci_layout_dir)
        self._make_checksum(image_copy)
Beispiel #8
0
 def test_oci_tool_not_supported(self, mock_RuntimeConfig):
     self.runtime_config.get_oci_archive_tool.return_value = 'foo'
     mock_RuntimeConfig.return_value = self.runtime_config
     with raises(KiwiOCIArchiveToolError):
         OCI()
Beispiel #9
0
class ContainerImageOCI(object):
    """
    Create oci container from a root directory

    :param string root_dir: root directory path name
    :param dict custom_args:
        Custom processing arguments defined as hash keys:

        Example

        .. code:: python

            {
                'container_name': 'name',
                'container_tag': '1.0',
                'additional_tags': ['current', 'foobar'],
                'entry_command': ['/bin/bash', '-x'],
                'entry_subcommand': ['ls', '-l'],
                'maintainer': 'tux',
                'user': '******',
                'workingdir': '/root',
                'expose_ports': ['80', '42'],
                'volumes': ['/var/log', '/tmp'],
                'environment': {'PATH': '/bin'},
                'labels': {'name': 'value'},
                'history': {
                    'created_by': 'some explanation here',
                    'comment': 'some comment here',
                    'author': 'tux'
                }
            }
    """
    def __init__(self, root_dir, custom_args=None):
        self.root_dir = root_dir
        self.oci_root_dir = None
        if custom_args:
            self.oci_config = custom_args
        else:
            self.oci_config = {}

        self.runtime_config = RuntimeConfig()

        # for builds inside the buildservice we include a reference to the
        # specific build. Thus disturl label only exists inside the
        # buildservice.
        if Defaults.is_buildservice_worker():
            bs_label = 'org.openbuildservice.disturl'
            # Do not label anything if any build service label is
            # already present
            if 'labels' not in self.oci_config or \
                    bs_label not in self.oci_config['labels']:
                self._append_buildservice_disturl_label()

        if 'container_name' not in self.oci_config:
            log.info('No container configuration provided, '
                     'using default container name "kiwi-container:latest"')
            self.oci_config['container_name'] = \
                Defaults.get_default_container_name()
            self.oci_config['container_tag'] = \
                Defaults.get_default_container_tag()

        if 'container_tag' not in self.oci_config:
            self.oci_config['container_tag'] = \
                Defaults.get_default_container_tag()

        if 'entry_command' not in self.oci_config and \
                'entry_subcommand' not in self.oci_config:
            self.oci_config['entry_subcommand'] = \
                Defaults.get_default_container_subcommand()

        if 'history' not in self.oci_config:
            self.oci_config['history'] = {}
        if 'created_by' not in self.oci_config['history']:
            self.oci_config['history']['created_by'] = \
                Defaults.get_default_container_created_by()

        self.oci = OCI(self.oci_config['container_tag'])

    def create(self, filename, base_image):
        """
        Create compressed oci system container tar archive

        :param string filename: archive file name
        :param string base_image: archive used as a base image
        """
        exclude_list = Defaults.get_exclude_list_for_root_data_sync()
        exclude_list.append('boot')
        exclude_list.append('dev')
        exclude_list.append('sys')
        exclude_list.append('proc')

        if base_image:
            Path.create(self.oci.container_dir)
            image_tar = ArchiveTar(base_image)
            image_tar.extract(self.oci.container_dir)

        self.oci.init_layout(bool(base_image))

        self.oci.unpack()
        self.oci.sync_rootfs(''.join([self.root_dir, os.sep]), exclude_list)
        self.oci.repack(self.oci_config)

        if 'additional_tags' in self.oci_config:
            for tag in self.oci_config['additional_tags']:
                self.oci.add_tag(tag)

        self.oci.set_config(self.oci_config, bool(base_image))

        self.oci.garbage_collect()

        return self.pack_image_to_file(filename)

    def pack_image_to_file(self, filename):
        """
        Packs the oci image into the given filename.

        :param string filename: file name of the resulting packed image
        """
        oci_tarfile = ArchiveTar(filename)
        container_compressor = self.runtime_config.get_container_compression()
        if container_compressor:
            return oci_tarfile.create_xz_compressed(
                self.oci.container_dir,
                xz_options=self.runtime_config.get_xz_options())
        else:
            return oci_tarfile.create(self.oci.container_dir)

    def _append_buildservice_disturl_label(self):
        with open(os.sep + Defaults.get_buildservice_env_name()) as env:
            for line in env:
                if line.startswith('BUILD_DISTURL') and '=' in line:
                    disturl = line.split('=')[1].lstrip('\'\"').rstrip(
                        '\n\'\"')
                    if disturl:
                        self.oci_config['labels'] = {
                            'org.openbuildservice.disturl': disturl
                        }
                        return
            log.warning('Could not find BUILD_DISTURL inside .buildenv')