From 7cb148d7536ac72ae56e835fc66ce84276266399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dirk=20M=C3=BCller?= Date: Fri, 19 Jul 2024 10:00:16 +0200 Subject: [PATCH] Add a Registry abstraction This removes a bit of if() condition wars in the BaseContainerImage and delegates it into its own class hierarchy, which allows to build a python container for appcol without having to do more subclasses. --- src/bci_build/package/__init__.py | 56 ++++++++++---------- src/bci_build/package/apache_tomcat.py | 17 +++--- src/bci_build/package/appcollection.py | 53 ------------------- src/bci_build/package/postfix.py | 9 ++-- src/bci_build/package/python.py | 8 ++- src/bci_build/registry.py | 73 ++++++++++++++++++++++++++ src/bci_build/templates.py | 6 +-- 7 files changed, 126 insertions(+), 96 deletions(-) delete mode 100644 src/bci_build/package/appcollection.py create mode 100644 src/bci_build/registry.py diff --git a/src/bci_build/package/__init__.py b/src/bci_build/package/__init__.py index 37daea403..28c10f1d9 100644 --- a/src/bci_build/package/__init__.py +++ b/src/bci_build/package/__init__.py @@ -16,6 +16,9 @@ import jinja2 from packaging import version +from bci_build.registry import ApplicationCollectionRegistry +from bci_build.registry import RegistryABC +from bci_build.registry import get_registry from bci_build.templates import DOCKERFILE_TEMPLATE from bci_build.templates import INFOHEADER_TEMPLATE from bci_build.templates import KIWI_TEMPLATE @@ -370,7 +373,6 @@ def __post_init__(self) -> None: source package. """ - if self.file_name and "readme" in self.file_name.lower(): raise ValueError(f"Cannot replace variables in {self.file_name}!") @@ -552,6 +554,13 @@ class BaseContainerImage(abc.ABC): #: webui sorting) _min_release_counter: int | None = None + #: The registry implementation for which this container is being built. + _publish_registry: RegistryABC | None = None + + @property + def publish_registry(self): + return self._publish_registry + def __post_init__(self) -> None: self.pretty_name = self.pretty_name.strip() @@ -577,6 +586,16 @@ def __post_init__(self) -> None: if self.os_version.is_tumbleweed else "SUSE LLC (https://www.suse.com/)" ) + if not self._publish_registry: + self._publish_registry = get_registry(self) + + # AppCollection preferences + if isinstance(self._publish_registry, ApplicationCollectionRegistry): + # Limit to aarch64 and x86_64 + if not self.exclusive_arch: + self.exclusive_arch = [Arch.AARCH64, Arch.X86_64] + # Disable maintainer listing + self.maintainer = None # limit to tech preview for beta releases if ( @@ -673,36 +692,17 @@ def url(self) -> str: ``org.opencontainers.image.url`` label """ - if self.os_version.is_tumbleweed: - return "https://www.opensuse.org" - if self.os_version.is_ltss: - return "https://www.suse.com/products/long-term-service-pack-support/" - - return "https://www.suse.com/products/base-container-images/" - - @property - def vendor(self) -> str: - """The vendor that is put into the ``org.opencontainers.image.vendor`` - label - - """ - if self.os_version.is_tumbleweed: - return "openSUSE Project" - return "SUSE LLC" + return self._publish_registry.url(container=self) @property def base_image_registry(self) -> str: """The registry where the base image is available on.""" - if self.os_version.is_tumbleweed: - return "registry.opensuse.org" - return "registry.suse.com" + return get_registry(self).registry @property def registry(self) -> str: """The registry where the image is available on.""" - if self.os_version.is_tumbleweed: - return "registry.opensuse.org" - return "registry.suse.com" + return self._publish_registry.registry @property def dockerfile_custom_end(self) -> str: @@ -1410,9 +1410,7 @@ def prepare_template(self) -> None: @property def registry_prefix(self) -> str: - if self.os_version.is_tumbleweed: - return "opensuse/bci" - return "bci" + return self._publish_registry.registry_prefix(is_application=False) @property def image_type(self) -> ImageType: @@ -1535,9 +1533,7 @@ def __post_init__(self) -> None: @property def registry_prefix(self) -> str: - if self.os_version.is_tumbleweed: - return "opensuse" - return "suse" + return self._publish_registry.registry_prefix(is_application=True) @property def image_type(self) -> ImageType: @@ -1545,6 +1541,8 @@ def image_type(self) -> ImageType: @property def title(self) -> str: + if isinstance(self._publish_registry, ApplicationCollectionRegistry): + return self.pretty_name return f"{self.os_version.distribution_base_name} {self.pretty_name}" @property diff --git a/src/bci_build/package/apache_tomcat.py b/src/bci_build/package/apache_tomcat.py index 62dfd81be..af6b93c33 100644 --- a/src/bci_build/package/apache_tomcat.py +++ b/src/bci_build/package/apache_tomcat.py @@ -4,14 +4,14 @@ from bci_build.package import CAN_BE_LATEST_OS_VERSION from bci_build.package import DOCKERFILE_RUN +from bci_build.package import ApplicationStackContainer from bci_build.package import OsContainer from bci_build.package import OsVersion from bci_build.package import Package from bci_build.package import PackageType from bci_build.package import Replacement from bci_build.package import _build_tag_prefix - -from .appcollection import ApplicationCollectionContainer +from bci_build.registry import ApplicationCollectionRegistry # last version needs to be the newest _TOMCAT_VERSIONS: list[str] = ["9", "10.1"] @@ -50,11 +50,16 @@ def _get_sac_supported_until( TOMCAT_CONTAINERS = [ - ApplicationCollectionContainer( + ApplicationStackContainer( name="apache-tomcat", - package_name=f"apache-tomcat-{tomcat_ver.partition('.')[0]}-java-{jre_version}-image" - if os_version.is_tumbleweed - else f"sac-apache-tomcat-{tomcat_ver.partition('.')[0]}-java{jre_version}-image", + package_name=( + f"apache-tomcat-{tomcat_ver.partition('.')[0]}-java-{jre_version}-image" + if os_version.is_tumbleweed + else f"sac-apache-tomcat-{tomcat_ver.partition('.')[0]}-java{jre_version}-image" + ), + _publish_registry=( + None if os_version.is_tumbleweed else ApplicationCollectionRegistry() + ), pretty_name="Apache Tomcat", custom_description=( "Apache Tomcat is a free and open-source implementation of the Jakarta Servlet, " diff --git a/src/bci_build/package/appcollection.py b/src/bci_build/package/appcollection.py deleted file mode 100644 index 9b0c5ad2a..000000000 --- a/src/bci_build/package/appcollection.py +++ /dev/null @@ -1,53 +0,0 @@ -"""Application Collection Containers that are generated with the BCI tooling""" - -from dataclasses import dataclass - -from bci_build.package import ApplicationStackContainer -from bci_build.package import Arch -from bci_build.package import OsVersion - - -@dataclass -class ApplicationCollectionContainer(ApplicationStackContainer): - """Containers for the Rancher Application Collection Distribution Platform.""" - - @property - def registry_prefix(self) -> str: - if self.os_version.is_tumbleweed: - return super().registry_prefix - return "containers" - - @property - def registry(self) -> str: - if self.os_version.is_tumbleweed: - return super().registry - return "dp.apps.rancher.io" - - @property - def url(self) -> str: - if self.os_version.is_tumbleweed: - return super().url - return f"https://apps.rancher.io/applications/{self.name}" - - @property - def title(self) -> str: - if self.os_version.is_tumbleweed: - return super().title - return self.pretty_name - - @property - def _from_image(self) -> str | None: - if self.os_version.is_tumbleweed or self.os_version == OsVersion.SLE16_0: - return super()._from_image - - return f"bci/bci-base:15.{self.os_version}" - - def __post_init__(self) -> None: - super().__post_init__() - # Limit Appcollection stuff to aarch64 and x86_64 - if not self.os_version.is_tumbleweed and not self.exclusive_arch: - self.exclusive_arch = [Arch.AARCH64, Arch.X86_64] - - # Disable maintainer listing for SLE - if not self.os_version.is_tumbleweed: - self.maintainer = None diff --git a/src/bci_build/package/postfix.py b/src/bci_build/package/postfix.py index d45f987ec..b87aaa034 100644 --- a/src/bci_build/package/postfix.py +++ b/src/bci_build/package/postfix.py @@ -5,12 +5,12 @@ from bci_build.package import ALL_NONBASE_OS_VERSIONS from bci_build.package import CAN_BE_LATEST_OS_VERSION from bci_build.package import DOCKERFILE_RUN +from bci_build.package import ApplicationStackContainer from bci_build.package import OsVersion from bci_build.package import ParseVersion from bci_build.package import Replacement from bci_build.package import SupportLevel - -from .appcollection import ApplicationCollectionContainer +from bci_build.registry import ApplicationCollectionRegistry _POSTFIX_FILES = {} for filename in ( @@ -34,9 +34,12 @@ POSTFIX_CONTAINERS = [ - ApplicationCollectionContainer( + ApplicationStackContainer( name="postfix", package_name=None if os_version.is_tumbleweed else "sac-postfix-image", + _publish_registry=( + None if os_version.is_tumbleweed else ApplicationCollectionRegistry() + ), pretty_name="Postfix", custom_description="Postfix container is fast and secure mail server, {based_on_container}.", os_version=os_version, diff --git a/src/bci_build/package/python.py b/src/bci_build/package/python.py index b814b23cf..4902c2725 100644 --- a/src/bci_build/package/python.py +++ b/src/bci_build/package/python.py @@ -10,6 +10,7 @@ from bci_build.package import OsVersion from bci_build.package import Replacement from bci_build.package import SupportLevel +from bci_build.registry import ApplicationCollectionRegistry _PYTHON_VERSIONS = Literal["3.6", "3.9", "3.10", "3.11", "3.12"] @@ -49,11 +50,11 @@ def _get_python_kwargs(py3_ver: _PYTHON_VERSIONS, os_version: OsVersion): # Tumbleweed rocks has_pipx = has_wheel = True elif os_version.is_sle15: - if py3_ver != "3.6": + if py3_ver not in ("3.6", "3.9"): # Enabled only for Python 3.11+ on SLE15 (jsc#PED-5573) has_pipx = True # py3.12 pending discussion - if py3_ver not in ("3.12",): + if py3_ver not in ("3.12", "3.9"): has_wheel = True kwargs = { @@ -112,6 +113,9 @@ def _get_python_kwargs(py3_ver: _PYTHON_VERSIONS, os_version: OsVersion): PythonDevelopmentContainer( **_get_python_kwargs("3.9", os_version), package_name="sac-python-3.9-image", + _publish_registry=( + None if os_version.is_tumbleweed else ApplicationCollectionRegistry() + ), ) for os_version in (OsVersion.SP6,) ) diff --git a/src/bci_build/registry.py b/src/bci_build/registry.py new file mode 100644 index 000000000..b2019a964 --- /dev/null +++ b/src/bci_build/registry.py @@ -0,0 +1,73 @@ +"""Registry classes for container images.""" + +import dataclasses +from abc import ABC +from abc import abstractmethod +from dataclasses import dataclass + + +@dataclass(frozen=True, kw_only=True) +class RegistryABC(ABC): + """Abstract Base Class for defining Registry specific content.""" + + _: dataclasses.KW_ONLY + """The base hostname for this registry instance""" + registry: str + """The vendor that is put into the ``org.opencontainers.image.vendor`` label""" + vendor: str + + @abstractmethod + def url(self, container) -> str: + pass + + @abstractmethod + def registry_prefix(self, *, is_application) -> str: + pass + + +class ApplicationCollectionRegistry(RegistryABC): + """Registry for the Rancher Application Collection Distribution Platform.""" + + def __init__(self): + super().__init__(registry="dp.apps.rancher.io", vendor="SUSE LLC") + + def url(self, container) -> str: + return f"https://apps.rancher.io/applications/{container.name}" + + def registry_prefix(self, *, is_application) -> str: + return "containers" + + +class SUSERegistry(RegistryABC): + """Registry for the SUSE Registry.""" + + def __init__(self): + super().__init__(registry="registry.suse.com", vendor="SUSE LLC") + + def url(self, container) -> str: + if container.os_version.is_ltss: + return "https://www.suse.com/products/long-term-service-pack-support/" + return "https://www.suse.com/products/base-container-images/" + + def registry_prefix(self, *, is_application) -> str: + return "suse" if is_application else "bci" + + +class openSUSERegistry(RegistryABC): + """Registry for the openSUSE registry.""" + + def __init__(self): + super().__init__(registry="registry.opensuse.org", vendor="openSUSE Project") + + def url(self, container) -> str: + return "https://www.opensuse.org" + + def registry_prefix(self, *, is_application) -> str: + return "opensuse" if is_application else "opensuse/bci" + + +def get_registry(container) -> RegistryABC: + """Return the appropriate registry for the container.""" + if container.os_version.is_tumbleweed: + return openSUSERegistry() + return SUSERegistry() diff --git a/src/bci_build/templates.py b/src/bci_build/templates.py index 42ce416c0..906320de4 100644 --- a/src/bci_build/templates.py +++ b/src/bci_build/templates.py @@ -63,7 +63,7 @@ LABEL org.opencontainers.image.version="{{ image.oci_version }}" LABEL org.opencontainers.image.url="{{ image.url }}" LABEL org.opencontainers.image.created="%BUILDTIME%" -LABEL org.opencontainers.image.vendor="{{ image.vendor }}" +LABEL org.opencontainers.image.vendor="{{ image.publish_registry.vendor }}" LABEL org.opencontainers.image.source="%SOURCEURL%" LABEL org.opencontainers.image.ref.name="{{ image.image_ref_name }}" LABEL org.opensuse.reference="{{ image.reference }}" @@ -120,7 +120,7 @@ - {{ image.vendor }} + {{ image.publish_registry.vendor }} https://www.suse.com/ {{ image.title }} Container Image @@ -145,7 +145,7 @@