Skip to content

Commit

Permalink
Build the apache-tomcat containers as build_flavors
Browse files Browse the repository at this point in the history
This allows to sync the -RELEASE tag between multiple flavors, which
is a requirement for appcollection.

For that, BaseContainerImages can be optionally grouped into a
ContainerCrate, which takes care of collecting build_flavors for
proper _multibuild and _service generation.
  • Loading branch information
dirkmueller committed Sep 27, 2024
1 parent 6ada056 commit f7c2d46
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 25 deletions.
40 changes: 40 additions & 0 deletions src/bci_build/containercrate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Crate to handle multibuild containers in the generator."""


class ContainerCrate:
"""ContainerCrate is combining multiple container build flavors.
This provides package-central functions like generating _service and
_multibuild files.
"""

def __init__(self, containers: list):
"""Assign the crate for every container."""
self._all_build_flavors: dict[tuple, set] = {}
for container in containers:
if container.build_flavor:
self._all_build_flavors.setdefault(
(container.os_version, container.package_name), set()
).add(container.build_flavor)

for container in containers:
if container.crate is not None:
raise ValueError("Container is already part of a ContainerCrate")
container.crate = self
container.all_build_flavors = self.all_build_flavors(container)

def all_build_flavors(self, container):
"""Return all build flavors for this container in the crate"""
return sorted(
self._all_build_flavors.get(
(container.os_version, container.package_name), [""]
)
)

def multibuild(self, container):
"""Return the _multibuild file string to write for this ContainerCrate."""
flavors: str = "\n".join(
" " * 4 + f"<package>{pkg}</package>"
for pkg in sorted(self.all_build_flavors(container))
)
return f"<multibuild>\n{flavors}\n</multibuild>"
38 changes: 32 additions & 6 deletions src/bci_build/package/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import jinja2
from packaging import version

from bci_build.containercrate import ContainerCrate
from bci_build.templates import DOCKERFILE_TEMPLATE
from bci_build.templates import INFOHEADER_TEMPLATE
from bci_build.templates import KIWI_TEMPLATE
Expand Down Expand Up @@ -458,6 +459,12 @@ class BaseContainerImage(abc.ABC):
default_factory=dict
)

#: build flavors to produce for this container variant
build_flavor: str | None = None

#: create that this container is part of
crate: ContainerCrate = None

#: Add any replacements via `obs-service-replace_using_package_version
#: <https://github.com/openSUSE/obs-service-replace_using_package_version>`_
#: that are used in this image into this list.
Expand Down Expand Up @@ -1137,9 +1144,13 @@ def title(self) -> str:
"""
return f"{self.os_version.distribution_base_name} BCI {self.pretty_name}"

@property
def readme_name(self) -> str:
return f"README.{self.build_flavor}.md" if self.build_flavor else "README.md"

@property
def readme_path(self) -> str:
return f"{self.package_name}/README.md"
return f"{self.package_name}/{self.readme_name}"

@property
def readme_url(self) -> str:
Expand All @@ -1150,7 +1161,7 @@ def readme_url(self) -> str:
if self.os_version.is_tumbleweed:
return f"https://raw.githubusercontent.com/SUSE/BCI-dockerfile-generator/{self.os_version.deployment_branch_name}/{self.readme_path}"

return "%SOURCEURL%/README.md"
return f"%SOURCEURL%/{self.readme_name}"

@property
def readme(self) -> str:
Expand Down Expand Up @@ -1278,14 +1289,17 @@ async def write_file_to_dest(fname: str, contents: str | bytes) -> None:
await write_to_file(os.path.join(dest, fname), contents)

if self.build_recipe_type == BuildType.DOCKER:
fname = "Dockerfile"
infoheader = textwrap.indent(INFOHEADER_TEMPLATE, "# ")
fname = (
f"Dockerfile.{self.build_flavor}" if self.build_flavor else "Dockerfile"
)

dockerfile = DOCKERFILE_TEMPLATE.render(
image=self,
INFOHEADER=infoheader,
DOCKERFILE_RUN=DOCKERFILE_RUN,
LOG_CLEAN=LOG_CLEAN,
BUILD_FLAVOR=self.build_flavor,
)
if dockerfile[-1] != "\n":
dockerfile += "\n"
Expand Down Expand Up @@ -1320,9 +1334,21 @@ async def write_file_to_dest(fname: str, contents: str | bytes) -> None:
False
), f"got an unexpected build_recipe_type: '{self.build_recipe_type}'"

if self.build_flavor:
mname = "_multibuild"
tasks.append(
asyncio.ensure_future(
write_file_to_dest(mname, self.crate.multibuild(self))
)
)
files.append(mname)

tasks.append(
asyncio.ensure_future(
write_file_to_dest("_service", SERVICE_TEMPLATE.render(image=self))
write_file_to_dest(
"_service",
SERVICE_TEMPLATE.render(image=self),
)
)
)

Expand Down Expand Up @@ -1361,8 +1387,8 @@ async def write_file_to_dest(fname: str, contents: str | bytes) -> None:
tasks.append(write_file_to_dest(fname, contents))

if "README.md" not in self.extra_files:
files.append("README.md")
tasks.append(write_file_to_dest("README.md", self.readme))
files.append(self.readme_name)
tasks.append(write_file_to_dest(self.readme_name, self.readme))

await asyncio.gather(*tasks)

Expand Down
9 changes: 7 additions & 2 deletions src/bci_build/package/apache_tomcat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import datetime

from bci_build.containercrate import ContainerCrate
from bci_build.package import CAN_BE_LATEST_OS_VERSION
from bci_build.package import DOCKERFILE_RUN
from bci_build.package import OsContainer
Expand Down Expand Up @@ -52,9 +53,9 @@ def _get_sac_supported_until(
TOMCAT_CONTAINERS = [
ApplicationCollectionContainer(
name="apache-tomcat",
package_name=f"apache-tomcat-{tomcat_ver.partition('.')[0]}-java-{jre_version}-image"
package_name=f"apache-tomcat-{tomcat_ver.partition('.')[0]}-image"
if os_version.is_tumbleweed
else f"sac-apache-tomcat-{tomcat_ver.partition('.')[0]}-java{jre_version}-image",
else f"sac-apache-tomcat-{tomcat_ver.partition('.')[0]}-image",
pretty_name="Apache Tomcat",
custom_description=(
"Apache Tomcat is a free and open-source implementation of the Jakarta Servlet, "
Expand All @@ -73,6 +74,7 @@ def _get_sac_supported_until(
supported_until=_get_sac_supported_until(
os_version=os_version, tomcat_ver=tomcat_ver, jre_major=jre_version
),
build_flavor=f"openjdk{jre_version}",
additional_versions=[f"%%tomcat_version%%-openjdk{jre_version}"],
from_target_image=f"{_build_tag_prefix(os_version)}/bci-micro:{OsContainer.version_to_container_os_version(os_version)}",
package_list=[
Expand Down Expand Up @@ -124,6 +126,9 @@ def _get_sac_supported_until(
("10.1", OsVersion.TUMBLEWEED, 17),
("9", OsVersion.TUMBLEWEED, 17),
("10.1", OsVersion.SP6, 21),
("10.1", OsVersion.SP6, 17),
# (10.1, OsVersion.SP7, 21),
)
]

TOMCAT_CRATE = ContainerCrate(TOMCAT_CONTAINERS)
15 changes: 13 additions & 2 deletions src/bci_build/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,13 +194,24 @@
"""<services>
<service mode="buildtime" name="{{ image.build_recipe_type }}_label_helper"/>
<service mode="buildtime" name="kiwi_metainfo_helper"/>
{%- set all_build_flavors = [""] %}
{%- if image.crate and image.build_flavor %}
{%- set all_build_flavors = image.crate.all_build_flavors(image) %}
{%- endif %}
{%- for flavor in all_build_flavors %}
{%- for replacement in image.replacements_via_service %}
<service name="replace_using_package_version" mode="buildtime">
<param name="file">{% if replacement.file_name != None %}{{replacement.file_name}}{% elif (image.build_recipe_type|string) == "docker" %}Dockerfile{% else %}{{ image.package_name }}.kiwi{% endif %}</param>
<param name="file">
{%- if replacement.file_name != None %}{{replacement.file_name}}
{%- elif (image.build_recipe_type|string) == "docker" %}{% if flavor %}Dockerfile.{{ flavor }}{% else %}Dockerfile{% endif %}
{%- else %}{{ image.package_name }}.kiwi
{%- endif %}</param>
<param name="regex">{{ replacement.regex_in_build_description }}</param>
<param name="package">{{ replacement.package_name }}</param>{% if replacement.parse_version %}
<param name="parse-version">{{ replacement.parse_version }}</param>{% endif %}
</service>{% endfor %}
</service>
{%- endfor -%}
{% endfor %}
</services>
"""
)
25 changes: 10 additions & 15 deletions src/staging/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -759,23 +759,18 @@ async def write_pkg_configs(
will be added
"""
tasks = [
self._write_pkg_meta(
bci,
git_branch_name=git_branch_name,
target_obs_project=target_obs_project,
)
for bci in packages
]

tasks = []
pkg_metas_to_generate = set()
for bci in packages:
tasks.append(
self._write_pkg_meta(
bci,
git_branch_name=git_branch_name,
target_obs_project=target_obs_project,
if bci.package_name not in pkg_metas_to_generate:
pkg_metas_to_generate.add(bci.package_name)
tasks.append(
self._write_pkg_meta(
bci,
git_branch_name=git_branch_name,
target_obs_project=target_obs_project,
)
)
)

await asyncio.gather(*tasks)

Expand Down
36 changes: 36 additions & 0 deletions tests/test_service.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from bci_build.containercrate import ContainerCrate
from bci_build.package import BuildType
from bci_build.package import DevelopmentContainer
from bci_build.package import OsVersion
Expand Down Expand Up @@ -108,3 +109,38 @@ def test_service_with_replacement_docker():
</service>
</services>"""
)


def test_service_with_multi_flavor_docker():
containers = [
DevelopmentContainer(
**_BASE_KWARGS,
build_recipe_type=BuildType.DOCKER,
build_flavor=flavor,
replacements_via_service=[
Replacement(regex_in_build_description="%%my_ver%%", package_name="sh"),
],
)
for flavor in ("flavor1", "flavor2")
]
containercrate = ContainerCrate(containers)

assert (
SERVICE_TEMPLATE.render(
image=containers[0],
)
== """<services>
<service mode="buildtime" name="docker_label_helper"/>
<service mode="buildtime" name="kiwi_metainfo_helper"/>
<service name="replace_using_package_version" mode="buildtime">
<param name="file">Dockerfile.flavor1</param>
<param name="regex">%%my_ver%%</param>
<param name="package">sh</param>
</service>
<service name="replace_using_package_version" mode="buildtime">
<param name="file">Dockerfile.flavor2</param>
<param name="regex">%%my_ver%%</param>
<param name="package">sh</param>
</service>
</services>"""
)

0 comments on commit f7c2d46

Please sign in to comment.