Source code for kiwi.container.oci

# Copyright (c) 2015 SUSE Linux GmbH.  All rights reserved.
# This file is part of kiwi.
# kiwi is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# kiwi is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with kiwi.  If not, see <>
import os
import logging
import sys
from typing import Dict, List, Optional
if sys.version_info >= (3, 8):
    from typing import TypedDict  # pragma: no cover
else:  # pragma: no cover
    from typing_extensions import TypedDict  # pragma: no cover

# project
from kiwi.utils.compress import Compress
from kiwi.runtime_config import RuntimeConfig
from kiwi.defaults import Defaults
from kiwi.oci_tools import OCI
from kiwi.container.base import ContainerImageBase

log = logging.getLogger('kiwi')

[docs] class OciConfig(TypedDict, total=False): container_name: str container_tag: str additional_names: List[str] entry_command: List[str] entry_subcommand: List[str] maintainer: str user: str workingdir: str expose_ports: List[str] volumes: List[str] environment: Dict[str, str] labels: Dict[str, str] history: Dict[str, str]
[docs] class ContainerImageOCI(ContainerImageBase): """ 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_names': ['current', 'foobar'], 'entry_command': ['/bin/bash', '-x'], 'entry_subcommand': ['ls', '-l'], 'maintainer': 'tux', 'user': 'root', '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: str, transport: str, custom_args: Optional[OciConfig] = None ) -> None: self.root_dir = root_dir self.archive_transport = transport self.oci_config = custom_args or {} # 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 the 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: '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 '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()
[docs] def create( self, filename: str, base_image: str, ensure_empty_tmpdirs: bool = True, compress_archive: bool = False ) -> str: """ Create compressed oci system container tar archive :param string filename: archive file name :param string base_image: archive used as a base image :param bool ensure_empty_tmpdirs: exclude system tmp directories :param bool compress_archive: compress container archive """ 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/*') with as oci: 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: List[str] = [] 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 ) if compress_archive: compress = Compress(filename) filename = compress.xz(RuntimeConfig().get_xz_options()) return filename
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: label = {'org.openbuildservice.disturl': disturl} if self.oci_config.get('labels'): self.oci_config['labels'].update(label) else: self.oci_config['labels'] = label return log.warning('Could not find BUILD_DISTURL inside .buildenv')