From f0612486ddef32b82e43153daec79f13039e3920 Mon Sep 17 00:00:00 2001 From: David Cassany Date: Tue, 6 Nov 2018 16:31:37 +0100 Subject: [PATCH] Add history metadata for container builds This commit adds the history section in contianerconfig. With it 'author', 'created_by' and 'comment' can be customized. In addition 'created' is always included with the image creation date time. 'created_by' entry is set to 'KIWI __version__' by default if nothing is provided. Fixes #852 --- kiwi/container/oci.py | 17 +++- kiwi/defaults.py | 16 +++- kiwi/oci_tools/base.py | 7 +- kiwi/oci_tools/umoci.py | 44 ++++++--- kiwi/schema/kiwi.rnc | 29 +++++- kiwi/schema/kiwi.rng | 39 ++++++++ kiwi/xml_parse.py | 125 +++++++++++++++++++++++++- kiwi/xml_state.py | 20 +++++ test/data/example_config.xml | 1 + test/unit/container_image_oci_test.py | 20 +++-- test/unit/oci_tools_umoci_test.py | 63 ++++++++----- test/unit/xml_state_test.py | 11 ++- 12 files changed, 333 insertions(+), 59 deletions(-) diff --git a/kiwi/container/oci.py b/kiwi/container/oci.py index f5a3870c..e61750dd 100644 --- a/kiwi/container/oci.py +++ b/kiwi/container/oci.py @@ -52,7 +52,12 @@ class ContainerImageOCI(object): 'expose_ports': ['80', '42'], 'volumes': ['/var/log', '/tmp'], 'environment': {'PATH': '/bin'}, - 'labels': {'name': 'value'} + 'labels': {'name': 'value'}, + 'history': { + 'created_by': 'some explanation here', + 'comment': 'some comment here', + 'author': 'tux' + } } """ def __init__(self, root_dir, custom_args=None): @@ -95,6 +100,12 @@ class ContainerImageOCI(object): 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): @@ -117,7 +128,7 @@ class ContainerImageOCI(object): image_tar = ArchiveTar(base_image) image_tar.extract(self.oci.container_dir) - self.oci.init_layout(base_image) + self.oci.init_layout(True if base_image else False) self.oci.unpack(self.oci_root_dir) oci_root = DataSync( @@ -133,7 +144,7 @@ class ContainerImageOCI(object): for tag in self.oci_config['additional_tags']: self.oci.add_tag(tag) - self.oci.set_config(self.oci_config) + self.oci.set_config(self.oci_config, True if base_image else False) self.oci.garbage_collect() diff --git a/kiwi/defaults.py b/kiwi/defaults.py index 125730cf..3edb7862 100644 --- a/kiwi/defaults.py +++ b/kiwi/defaults.py @@ -25,7 +25,10 @@ from pkg_resources import resource_filename # project from .path import Path -from .version import __githash__ +from .version import ( + __githash__, + __version__ +) class Defaults(object): @@ -1173,6 +1176,17 @@ class Defaults(object): """ return ['/bin/bash'] + @classmethod + def get_default_container_created_by(self): + """ + Provides the default 'created by' history entry for containers. + + :return: the specific kiwi version used for the build + + :rtype: str + """ + return 'KIWI {0}'.format(__version__) + @classmethod def set_python_default_encoding_to_utf8(self): """ diff --git a/kiwi/oci_tools/base.py b/kiwi/oci_tools/base.py index 0869d9b9..f5d654ef 100644 --- a/kiwi/oci_tools/base.py +++ b/kiwi/oci_tools/base.py @@ -17,6 +17,7 @@ # import os from tempfile import mkdtemp +from datetime import datetime # project from kiwi.path import Path @@ -51,6 +52,9 @@ class OCIBase(object): self.container_name = ':'.join( [self.container_dir, self.container_tag] ) + self.creation_date = datetime.utcnow().strftime( + '%Y-%m-%dT%H:%M:%S+00:00' + ) def init_layout(self, base_image=False): """ @@ -81,7 +85,6 @@ class OCIBase(object): Implementation in specialized tool class :param string oci_root_dir: root data directory - :param string container_name: custom container_dir:tag specifier """ raise NotImplementedError @@ -96,7 +99,7 @@ class OCIBase(object): """ raise NotImplementedError - def set_config(self, oci_config): + def set_config(self, oci_config, base_image=False): """ Set list of meta data information such as entry_point, maintainer, etc... to the container. The validation of diff --git a/kiwi/oci_tools/umoci.py b/kiwi/oci_tools/umoci.py index a0efb62f..10b0521d 100644 --- a/kiwi/oci_tools/umoci.py +++ b/kiwi/oci_tools/umoci.py @@ -15,7 +15,6 @@ # You should have received a copy of the GNU General Public License # along with kiwi. If not, see # -from datetime import datetime # project from kiwi.oci_tools.base import OCIBase @@ -36,16 +35,10 @@ class OCIUmoci(OCIBase): The import and unpack of the base image is not a responsibility of this class and done beforehead - :param string base_image: True|False + :param bool base_image: True|False """ if base_image: - Command.run( - [ - 'umoci', 'config', '--image', - '{0}:base_layer'.format(self.container_dir), - '--tag', self.container_tag - ] - ) + self.container_name = '{0}:base_layer'.format(self.container_dir) else: Command.run( ['umoci', 'init', '--layout', self.container_dir] @@ -87,24 +80,30 @@ class OCIUmoci(OCIBase): ] ) - def set_config(self, oci_config): + def set_config(self, oci_config, base_image=False): """ Set list of meta data information such as entry_point, maintainer, etc... to the container. :param list oci_config: meta data list + :param bool base_image: True|False """ config_args = self._process_oci_config_to_arguments(oci_config) Command.run( [ 'umoci', 'config' ] + config_args + [ + '--history.created', self.creation_date, '--image', self.container_name, - '--created', datetime.utcnow().strftime( - '%Y-%m-%dT%H:%M:%S+00:00' - ) + '--tag', self.container_tag, + '--created', self.creation_date ] ) + if base_image: + Command.run(['umoci', 'rm', '--image', self.container_name]) + self.container_name = self.container_name = ':'.join( + [self.container_dir, self.container_tag] + ) @classmethod # noqa:C091 def _process_oci_config_to_arguments(self, oci_config): @@ -168,8 +167,27 @@ class OCIUmoci(OCIBase): name, oci_config['labels'][name] )) + arguments.extend(self._process_oci_history_to_arguments(oci_config)) return arguments + @classmethod + def _process_oci_history_to_arguments(self, oci_config): + history_args = [] + if 'history' in oci_config: + if 'comment' in oci_config['history']: + history_args.append('--history.comment={0}'.format( + oci_config['history']['comment'] + )) + if 'created_by' in oci_config['history']: + history_args.append('--history.created_by={0}'.format( + oci_config['history']['created_by'] + )) + if 'author' in oci_config['history']: + history_args.append('--history.author={0}'.format( + oci_config['history']['author'] + )) + return history_args + def garbage_collect(self): """ Cleanup unused data from operations diff --git a/kiwi/schema/kiwi.rnc b/kiwi/schema/kiwi.rnc index 479fcc10..55ee246c 100644 --- a/kiwi/schema/kiwi.rnc +++ b/kiwi/schema/kiwi.rnc @@ -2207,7 +2207,8 @@ div { k.expose? & k.volumes? & k.environment? & - k.labels? + k.labels? & + k.history? } } @@ -2400,6 +2401,32 @@ div { } } +#========================================== +# main block: +# +div { + k.history.created_by.attribute = + ## Specifies the 'created by' history record. By default set to 'KIWI' + attribute created_by { text } + + k.history.author.attribute = + ## Specifies the 'author' history record. + attribute author { text } + + k.history.attlist = + k.history.created_by.attribute? & + k.history.author.attribute? + + k.history = + ## Provides details about the container history. Includes the + ## 'created by', 'author' as attributes and its content represents + ## the 'comment' entry. + element history { + k.history.attlist, + text + } +} + #========================================== # main block: # diff --git a/kiwi/schema/kiwi.rng b/kiwi/schema/kiwi.rng index 5575d9db..622cf741 100644 --- a/kiwi/schema/kiwi.rng +++ b/kiwi/schema/kiwi.rng @@ -3427,6 +3427,9 @@ section provides globally useful container information. + + + @@ -3699,6 +3702,42 @@ At least one label must be configured + +
+ + + Specifies the 'created by' history record. By default set to 'KIWI' + + + + + Specifies the 'author' history record. + + + + + + + + + + + + + + + Provides details about the container history. Includes the +'created by', 'author' as attributes and its content represents +the 'comment' entry. + + + + +