Update schema for container setup

In preparation to support creation of native docker containers the
way docker likes it, the kiwi schema has to be adapted. So far there
was no way to specify additional metadata information for containers.
With this commit a new section called <containerconfig> is provided.
containerconfig is a subsection of the type and only allowed for
the docker image type. This constraint is checked via a schematron
rule. In addition an xslt stylesheet moves the currently existing
container attribute, which was used to set a name for the container,
into the new containerconfig section as name attribute
This commit is contained in:
Marcus Schäfer 2017-01-09 10:52:41 +01:00
parent 41a1f2f613
commit b7f7fa11eb
No known key found for this signature in database
GPG Key ID: AD11DD02B44996EF
6 changed files with 282 additions and 38 deletions

View File

@ -271,7 +271,7 @@ Parents:
These elements contain ``type``: :ref:`k.image.preferences`
Children:
The following elements occur in ``type``: :ref:`machine <k.image.preferences.type.machine>` `[?]`_, :ref:`oemconfig <k.image.preferences.type.oemconfig>` `[?]`_, :ref:`pxedeploy <k.image.preferences.type.pxedeploy>` `[?]`_, :ref:`size <k.image.preferences.type.size>` `[?]`_, :ref:`systemdisk <k.image.preferences.type.systemdisk>` `[?]`_, :ref:`vagrantconfig <k.image.preferences.type.vagrantconfig>` `[*]`_
The following elements occur in ``type``: :ref:`containerconfig <k.image.preferences.type.containerconfig>` `[?]`_, :ref:`machine <k.image.preferences.type.machine>` `[?]`_, :ref:`oemconfig <k.image.preferences.type.oemconfig>` `[?]`_, :ref:`pxedeploy <k.image.preferences.type.pxedeploy>` `[?]`_, :ref:`size <k.image.preferences.type.size>` `[?]`_, :ref:`systemdisk <k.image.preferences.type.systemdisk>` `[?]`_, :ref:`vagrantconfig <k.image.preferences.type.vagrantconfig>` `[*]`_
List of attributes for ``type``:
@ -290,7 +290,6 @@ List of attributes for ``type``:
* ``btrfs_root_is_readonly_snapshot`` `[?]`_: Tell kiwi to set the btrfs root filesystem snapshot read-only Once all data has been placed to the root filesystem snapshot it will be turned into read-only mode if this option is set to true. The option is only effective if btrfs_root_is_snapshot is also set to true. By default the root filesystem snapshot is writable
* ``checkprebuilt`` `[?]`_: Activates whether KIWI should search for a prebuild boot image or not. Obsolete attribute since KIWI v8
* ``compressed`` `[?]`_: Specifies whether the image output file should be compressed or not. This makes only sense for filesystem only images respectively for the pxe or cpio type
* ``container`` `[?]`_: Specifies a name for the container
* ``devicepersistency`` `[?]`_: Specifies which method to use in order to get persistent storage device names. By default by-uuid is used.
* ``editbootconfig`` `[?]`_: Specifies the path to a script which is called right before the bootloader is installed. The script runs relative to the directory which contains the image structure
* ``editbootinstall`` `[?]`_: Specifies the path to a script which is called right after the bootloader is installed. The script runs relative to the directory which contains the image structure
@ -328,6 +327,21 @@ List of attributes for ``type``:
* ``volid`` `[?]`_: for the iso type only: Specifies the volume ID (volume name or label) to be written into the master block. There is space for 32 characters.
* ``wwid_wait_timeout`` `[?]`_: Specifies the wait period in seconds after launching the multipath daemon to wait until all presented devices are available on the host. Default timeout is 3 seconds
.. _k.image.preferences.type.containerconfig:
containerconfig
,,,,,,,,,,,,,,,
Provides metadata information for containers
Parents:
These elements contain ``containerconfig``: :ref:`k.image.preferences.type`
List of attributes for ``containerconfig``:
* ``name`` : Specifies a name for the container. This is usually the the tag name of the container as read if the container image is imported via the docker load command
* ``entry_command`` `[?]`_: Specifies the default command to run if the container is called via the docker run command.
.. _k.image.preferences.type.machine:
machine

View File

@ -64,7 +64,7 @@ div {
attribute xsi:schemaLocation { xsd:anyURI }
k.image.schemaversion.attribute =
## The allowed Schema version (fixed value)
attribute schemaversion { "6.4" }
attribute schemaversion { "6.5" }
k.image.kiwirevision.attribute =
## A kiwi git revision number which is known to build
## a working image from this description. If the kiwi git
@ -1745,13 +1745,6 @@ div {
sch:param [ name = "attr" value = "compressed" ]
sch:param [ name = "types" value = "pxe" ]
]
k.type.container.attribute =
## Specifies a name for the container
attribute container { text }
>> sch:pattern [ id = "container" is-a = "image_type"
sch:param [ name = "attr" value = "container" ]
sch:param [ name = "types" value = "docker" ]
]
k.type.devicepersistency.attribute =
## Specifies which method to use in order to get persistent
## storage device names. By default by-uuid is used.
@ -2085,7 +2078,6 @@ div {
k.type.btrfs_root_is_readonly_snapshot? &
k.type.checkprebuilt.attribute? &
k.type.compressed.attribute? &
k.type.container.attribute? &
k.type.devicepersistency.attribute? &
k.type.editbootconfig.attribute? &
k.type.editbootinstall.attribute? &
@ -2126,6 +2118,7 @@ div {
## The Image Type of the Logical Extend
element type {
k.type.attlist &
k.containerconfig? &
k.machine? &
k.oemconfig? &
k.pxedeploy? &
@ -2804,6 +2797,59 @@ div {
}
}
#==========================================
# main block: <containerconfig>
#
div {
sch:pattern [
abstract = "true"
id = "container_type"
sch:rule [
context = "containerconfig"
sch:assert [
test = "contains('$types', ../@image)"
"containerconfig($attr) is only available for the following "~
"image types: $types"
]
]
]
k.containerconfig.name.attribute =
## Specifies a name for the container. This is usually the
## the tag name of the container as read if the container
## image is imported via the docker load command
attribute name { text }
>> sch:pattern [ id = "name" is-a = "container_type"
sch:param [ name = "attr" value = "name" ]
sch:param [ name = "types" value = "docker" ]
]
k.containerconfig.entry_command.attribute =
## Specifies the default command to run if the container is
## called via the docker run command.
attribute entry_command { text }
>> sch:pattern [ id = "entry_command" is-a = "container_type"
sch:param [ name = "attr" value = "entry_command" ]
sch:param [ name = "types" value = "docker" ]
]
k.containerconfig.attlist =
k.containerconfig.name.attribute &
k.containerconfig.entry_command.attribute?
k.containerconfig =
## Provides metadata information for containers
[
db:para [
"The containerconfig element provides metadata information"
"to setup a container in order to be prepared for use with"
"the container engine tool chain. container specific data"
"should be provided in an additional subsection whereas this"
"section provides globally useful container information"
]
]
element containerconfig {
k.containerconfig.attlist
}
}
#==========================================
# main block: <oemconfig>
#

View File

@ -101,7 +101,7 @@ second the location of the XSD Schema
<define name="k.image.schemaversion.attribute">
<attribute name="schemaversion">
<a:documentation>The allowed Schema version (fixed value)</a:documentation>
<value>6.4</value>
<value>6.5</value>
</attribute>
</define>
<define name="k.image.kiwirevision.attribute">
@ -2286,15 +2286,6 @@ only images respectively for the pxe or cpio type</a:documentation>
<sch:param name="types" value="pxe"/>
</sch:pattern>
</define>
<define name="k.type.container.attribute">
<attribute name="container">
<a:documentation>Specifies a name for the container</a:documentation>
</attribute>
<sch:pattern id="container" is-a="image_type">
<sch:param name="attr" value="container"/>
<sch:param name="types" value="docker"/>
</sch:pattern>
</define>
<define name="k.type.devicepersistency.attribute">
<attribute name="devicepersistency">
<a:documentation>Specifies which method to use in order to get persistent
@ -2806,9 +2797,6 @@ are available on the host. Default timeout is 3 seconds</a:documentation>
<optional>
<ref name="k.type.compressed.attribute"/>
</optional>
<optional>
<ref name="k.type.container.attribute"/>
</optional>
<optional>
<ref name="k.type.devicepersistency.attribute"/>
</optional>
@ -2922,6 +2910,9 @@ are available on the host. Default timeout is 3 seconds</a:documentation>
<a:documentation>The Image Type of the Logical Extend</a:documentation>
<interleave>
<ref name="k.type.attlist"/>
<optional>
<ref name="k.containerconfig"/>
</optional>
<optional>
<ref name="k.machine"/>
</optional>
@ -3906,6 +3897,54 @@ drivers on system installation with YaST.</db:para>
</element>
</define>
</div>
<!--
==========================================
main block: <containerconfig>
-->
<div>
<sch:pattern abstract="true" id="container_type">
<sch:rule context="containerconfig">
<sch:assert test="contains('$types', ../@image)">containerconfig($attr) is only available for the following image types: $types</sch:assert>
</sch:rule>
</sch:pattern>
<define name="k.containerconfig.name.attribute">
<attribute name="name">
<a:documentation>Specifies a name for the container. This is usually the
the tag name of the container as read if the container
image is imported via the docker load command</a:documentation>
</attribute>
<sch:pattern id="name" is-a="container_type">
<sch:param name="attr" value="name"/>
<sch:param name="types" value="docker"/>
</sch:pattern>
</define>
<define name="k.containerconfig.entry_command.attribute">
<attribute name="entry_command">
<a:documentation>Specifies the default command to run if the container is
called via the docker run command.</a:documentation>
</attribute>
<sch:pattern id="entry_command" is-a="container_type">
<sch:param name="attr" value="entry_command"/>
<sch:param name="types" value="docker"/>
</sch:pattern>
</define>
<define name="k.containerconfig.attlist">
<interleave>
<ref name="k.containerconfig.name.attribute"/>
<optional>
<ref name="k.containerconfig.entry_command.attribute"/>
</optional>
</interleave>
</define>
<define name="k.containerconfig">
<element name="containerconfig">
<a:documentation>Provides metadata information for containers</a:documentation>
<db:para>The containerconfig element provides metadata informationto setup a container in order to be prepared for use withthe container engine tool chain. container specific datashould be provided in an additional subsection whereas thissection provides globally useful container information</db:para>
<ref name="k.containerconfig.attlist"/>
</element>
</define>
</div>
<!--
==========================================
main block: <oemconfig>

View File

@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#
# Generated Thu Dec 8 15:13:19 2016 by generateDS.py version 2.24a.
# Generated Mon Jan 9 10:51:35 2017 by generateDS.py version 2.24a.
#
# Command line options:
# ('-f', '')
@ -2901,7 +2901,7 @@ class type_(GeneratedsSuper):
"""The Image Type of the Logical Extend"""
subclass = None
superclass = None
def __init__(self, boot=None, bootfilesystem=None, firmware=None, bootkernel=None, bootloader=None, bootloader_console=None, zipl_targettype=None, bootpartition=None, bootpartsize=None, bootprofile=None, boottimeout=None, btrfs_root_is_snapshot=None, btrfs_root_is_readonly_snapshot=None, checkprebuilt=None, compressed=None, container=None, devicepersistency=None, editbootconfig=None, editbootinstall=None, filesystem=None, flags=None, format=None, formatoptions=None, fsnocheck=None, fsmountoptions=None, gcelicense=None, hybrid=None, hybridpersistent=None, hybridpersistent_filesystem=None, gpt_hybrid_mbr=None, initrd_system=None, image=None, installboot=None, installprovidefailsafe=None, installiso=None, installstick=None, installpxe=None, kernelcmdline=None, luks=None, luksOS=None, mdraid=None, overlayroot=None, primary=None, ramonly=None, rootfs_label=None, target_blocksize=None, target_removable=None, vbootsize=None, vga=None, vhdfixedtag=None, volid=None, wwid_wait_timeout=None, machine=None, oemconfig=None, pxedeploy=None, size=None, systemdisk=None, vagrantconfig=None):
def __init__(self, boot=None, bootfilesystem=None, firmware=None, bootkernel=None, bootloader=None, bootloader_console=None, zipl_targettype=None, bootpartition=None, bootpartsize=None, bootprofile=None, boottimeout=None, btrfs_root_is_snapshot=None, btrfs_root_is_readonly_snapshot=None, checkprebuilt=None, compressed=None, devicepersistency=None, editbootconfig=None, editbootinstall=None, filesystem=None, flags=None, format=None, formatoptions=None, fsnocheck=None, fsmountoptions=None, gcelicense=None, hybrid=None, hybridpersistent=None, hybridpersistent_filesystem=None, gpt_hybrid_mbr=None, initrd_system=None, image=None, installboot=None, installprovidefailsafe=None, installiso=None, installstick=None, installpxe=None, kernelcmdline=None, luks=None, luksOS=None, mdraid=None, overlayroot=None, primary=None, ramonly=None, rootfs_label=None, target_blocksize=None, target_removable=None, vbootsize=None, vga=None, vhdfixedtag=None, volid=None, wwid_wait_timeout=None, containerconfig=None, machine=None, oemconfig=None, pxedeploy=None, size=None, systemdisk=None, vagrantconfig=None):
self.original_tagname_ = None
self.boot = _cast(None, boot)
self.bootfilesystem = _cast(None, bootfilesystem)
@ -2918,7 +2918,6 @@ class type_(GeneratedsSuper):
self.btrfs_root_is_readonly_snapshot = _cast(bool, btrfs_root_is_readonly_snapshot)
self.checkprebuilt = _cast(bool, checkprebuilt)
self.compressed = _cast(bool, compressed)
self.container = _cast(None, container)
self.devicepersistency = _cast(None, devicepersistency)
self.editbootconfig = _cast(None, editbootconfig)
self.editbootinstall = _cast(None, editbootinstall)
@ -2955,6 +2954,10 @@ class type_(GeneratedsSuper):
self.vhdfixedtag = _cast(None, vhdfixedtag)
self.volid = _cast(None, volid)
self.wwid_wait_timeout = _cast(int, wwid_wait_timeout)
if containerconfig is None:
self.containerconfig = []
else:
self.containerconfig = containerconfig
if machine is None:
self.machine = []
else:
@ -2990,6 +2993,11 @@ class type_(GeneratedsSuper):
else:
return type_(*args_, **kwargs_)
factory = staticmethod(factory)
def get_containerconfig(self): return self.containerconfig
def set_containerconfig(self, containerconfig): self.containerconfig = containerconfig
def add_containerconfig(self, value): self.containerconfig.append(value)
def insert_containerconfig_at(self, index, value): self.containerconfig.insert(index, value)
def replace_containerconfig_at(self, index, value): self.containerconfig[index] = value
def get_machine(self): return self.machine
def set_machine(self, machine): self.machine = machine
def add_machine(self, value): self.machine.append(value)
@ -3050,8 +3058,6 @@ class type_(GeneratedsSuper):
def set_checkprebuilt(self, checkprebuilt): self.checkprebuilt = checkprebuilt
def get_compressed(self): return self.compressed
def set_compressed(self, compressed): self.compressed = compressed
def get_container(self): return self.container
def set_container(self, container): self.container = container
def get_devicepersistency(self): return self.devicepersistency
def set_devicepersistency(self, devicepersistency): self.devicepersistency = devicepersistency
def get_editbootconfig(self): return self.editbootconfig
@ -3133,6 +3139,7 @@ class type_(GeneratedsSuper):
validate_vhd_tag_type_patterns_ = [['^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$']]
def hasContent_(self):
if (
self.containerconfig or
self.machine or
self.oemconfig or
self.pxedeploy or
@ -3207,9 +3214,6 @@ class type_(GeneratedsSuper):
if self.compressed is not None and 'compressed' not in already_processed:
already_processed.add('compressed')
outfile.write(' compressed="%s"' % self.gds_format_boolean(self.compressed, input_name='compressed'))
if self.container is not None and 'container' not in already_processed:
already_processed.add('container')
outfile.write(' container=%s' % (self.gds_encode(self.gds_format_string(quote_attrib(self.container), input_name='container')), ))
if self.devicepersistency is not None and 'devicepersistency' not in already_processed:
already_processed.add('devicepersistency')
outfile.write(' devicepersistency=%s' % (self.gds_encode(self.gds_format_string(quote_attrib(self.devicepersistency), input_name='devicepersistency')), ))
@ -3323,6 +3327,8 @@ class type_(GeneratedsSuper):
eol_ = '\n'
else:
eol_ = ''
for containerconfig_ in self.containerconfig:
containerconfig_.export(outfile, level, namespace_, name_='containerconfig', pretty_print=pretty_print)
for machine_ in self.machine:
machine_.export(outfile, level, namespace_, name_='machine', pretty_print=pretty_print)
for oemconfig_ in self.oemconfig:
@ -3443,10 +3449,6 @@ class type_(GeneratedsSuper):
self.compressed = False
else:
raise_parse_error(node, 'Bad boolean attribute')
value = find_attr_value_('container', node)
if value is not None and 'container' not in already_processed:
already_processed.add('container')
self.container = value
value = find_attr_value_('devicepersistency', node)
if value is not None and 'devicepersistency' not in already_processed:
already_processed.add('devicepersistency')
@ -3679,7 +3681,12 @@ class type_(GeneratedsSuper):
if self.wwid_wait_timeout < 0:
raise_parse_error(node, 'Invalid NonNegativeInteger')
def buildChildren(self, child_, node, nodeName_, fromsubclass_=False):
if nodeName_ == 'machine':
if nodeName_ == 'containerconfig':
obj_ = containerconfig.factory()
obj_.build(child_)
self.containerconfig.append(obj_)
obj_.original_tagname_ = 'containerconfig'
elif nodeName_ == 'machine':
obj_ = machine.factory()
obj_.build(child_)
self.machine.append(obj_)
@ -6244,6 +6251,83 @@ class instsys(GeneratedsSuper):
# end class instsys
class containerconfig(GeneratedsSuper):
"""Provides metadata information for containers"""
subclass = None
superclass = None
def __init__(self, name=None, entry_command=None):
self.original_tagname_ = None
self.name = _cast(None, name)
self.entry_command = _cast(None, entry_command)
def factory(*args_, **kwargs_):
if CurrentSubclassModule_ is not None:
subclass = getSubclassFromModule_(
CurrentSubclassModule_, containerconfig)
if subclass is not None:
return subclass(*args_, **kwargs_)
if containerconfig.subclass:
return containerconfig.subclass(*args_, **kwargs_)
else:
return containerconfig(*args_, **kwargs_)
factory = staticmethod(factory)
def get_name(self): return self.name
def set_name(self, name): self.name = name
def get_entry_command(self): return self.entry_command
def set_entry_command(self, entry_command): self.entry_command = entry_command
def hasContent_(self):
if (
):
return True
else:
return False
def export(self, outfile, level, namespace_='', name_='containerconfig', namespacedef_='', pretty_print=True):
if pretty_print:
eol_ = '\n'
else:
eol_ = ''
if self.original_tagname_ is not None:
name_ = self.original_tagname_
showIndent(outfile, level, pretty_print)
outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', ))
already_processed = set()
self.exportAttributes(outfile, level, already_processed, namespace_, name_='containerconfig')
if self.hasContent_():
outfile.write('>%s' % (eol_, ))
self.exportChildren(outfile, level + 1, namespace_='', name_='containerconfig', pretty_print=pretty_print)
outfile.write('</%s%s>%s' % (namespace_, name_, eol_))
else:
outfile.write('/>%s' % (eol_, ))
def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='containerconfig'):
if self.name is not None and 'name' not in already_processed:
already_processed.add('name')
outfile.write(' name=%s' % (self.gds_encode(self.gds_format_string(quote_attrib(self.name), input_name='name')), ))
if self.entry_command is not None and 'entry_command' not in already_processed:
already_processed.add('entry_command')
outfile.write(' entry_command=%s' % (self.gds_encode(self.gds_format_string(quote_attrib(self.entry_command), input_name='entry_command')), ))
def exportChildren(self, outfile, level, namespace_='', name_='containerconfig', fromsubclass_=False, pretty_print=True):
pass
def build(self, node):
already_processed = set()
self.buildAttributes(node, node.attrib, already_processed)
for child in node:
nodeName_ = Tag_pattern_.match(child.tag).groups()[-1]
self.buildChildren(child, node, nodeName_)
return self
def buildAttributes(self, node, attrs, already_processed):
value = find_attr_value_('name', node)
if value is not None and 'name' not in already_processed:
already_processed.add('name')
self.name = value
value = find_attr_value_('entry_command', node)
if value is not None and 'entry_command' not in already_processed:
already_processed.add('entry_command')
self.entry_command = value
def buildChildren(self, child_, node, nodeName_, fromsubclass_=False):
pass
# end class containerconfig
class oemconfig(GeneratedsSuper):
"""Specifies the OEM configuration section"""
subclass = None
@ -8082,6 +8166,7 @@ __all__ = [
"archive",
"chroot",
"configuration",
"containerconfig",
"description",
"drivers",
"driverupdate",

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"
indent="yes" omit-xml-declaration="no" encoding="utf-8"/>
<!-- default rule -->
<xsl:template match="*|processing-instruction()|comment()" mode="conv64to65">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates mode="conv64to65"/>
</xsl:copy>
</xsl:template>
<!-- version update -->
<!-- remove inherit attribute from image -->
<para xmlns="http://docbook.org/ns/docbook">
Changed attribute <tag class="attribute">schemaversion</tag>
to <tag class="attribute">schemaversion</tag> from
<literal>6.4</literal> to <literal>6.5</literal>.
</para>
<xsl:template match="image" mode="conv64to65">
<xsl:choose>
<!-- nothing to do if already at 6.5 -->
<xsl:when test="@schemaversion > 6.4">
<xsl:copy-of select="/"/>
</xsl:when>
<!-- otherwise apply templates -->
<xsl:otherwise>
<image schemaversion="6.5">
<xsl:copy-of select="@*[local-name() != 'schemaversion' and local-name() != 'inherit']"/>
<xsl:apply-templates mode="conv64to65"/>
</image>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<para xmlns="http://docbook.org/ns/docbook">
Move container attribute from type to containerconfig
</para>
<xsl:template match="type" mode="conv64to65">
<type>
<xsl:copy-of select="@*[not(local-name(.) = 'container')]"/>
<xsl:variable name="container_name" select="@container"/>
<xsl:if test="$container_name">
<containerconfig>
<xsl:attribute name="name">
<xsl:value-of select="$container_name"/>
</xsl:attribute>
</containerconfig>
</xsl:if>
<xsl:apply-templates mode="conv64to65"/>
</type>
</xsl:template>
</xsl:stylesheet>

View File

@ -35,6 +35,7 @@
<xsl:import href="convert61to62.xsl"/>
<xsl:import href="convert62to63.xsl"/>
<xsl:import href="convert63to64.xsl"/>
<xsl:import href="convert64to65.xsl"/>
<xsl:import href="pretty.xsl"/>
@ -161,8 +162,12 @@
<xsl:apply-templates select="exslt:node-set($v63)" mode="conv63to64"/>
</xsl:variable>
<xsl:variable name="v65">
<xsl:apply-templates select="exslt:node-set($v64)" mode="conv64to65"/>
</xsl:variable>
<xsl:apply-templates
select="exslt:node-set($v64)" mode="pretty"
select="exslt:node-set($v65)" mode="pretty"
/>
</xsl:template>