Skip to content

Commit

Permalink
Merge pull request #1883 from SUSE/expose-port-dataclass
Browse files Browse the repository at this point in the history
Refactor expose ports to a list of ints or NetworkPort instances
  • Loading branch information
dirkmueller authored Oct 30, 2024
2 parents 8d36f63 + 08546b9 commit c283575
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 29 deletions.
36 changes: 36 additions & 0 deletions src/bci_build/container_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"""

import enum
from dataclasses import dataclass


@enum.unique
Expand Down Expand Up @@ -89,3 +90,38 @@ class PackageType(enum.Enum):

def __str__(self) -> str:
return self.value


@enum.unique
class NetworkProtocol(enum.Enum):
TCP = "tcp"
UDP = "udp"

def __str__(self) -> str:
return self.value


@dataclass(frozen=True)
class NetworkPort:
"""Representation of a port to expose from a container."""

#: the port number
number: int

#: the network protocol
protocol: NetworkProtocol = NetworkProtocol.TCP

def __post_init__(self) -> None:
if self.number < 1 or self.number > 65535:
raise ValueError(f"Invalid port number: {self.number}")

def __str__(self) -> str:
return f"{self.number}/{self.protocol}"


def TCP(port_number: int) -> NetworkPort:
return NetworkPort(port_number, protocol=NetworkProtocol.TCP)


def UDP(port_number: int) -> NetworkPort:
return NetworkPort(port_number, protocol=NetworkProtocol.UDP)
16 changes: 9 additions & 7 deletions src/bci_build/package/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from bci_build.container_attributes import Arch
from bci_build.container_attributes import BuildType
from bci_build.container_attributes import ImageType
from bci_build.container_attributes import NetworkPort
from bci_build.container_attributes import PackageType
from bci_build.container_attributes import ReleaseStage
from bci_build.container_attributes import SupportLevel
Expand Down Expand Up @@ -199,8 +200,8 @@ class BaseContainerImage(abc.ABC):
#: An optional list of volumes, it is omitted if empty or ``None``
volumes: list[str] | None = None

#: An optional list of port exposes, it is omitted if empty or ``None``
exposes_ports: list[str] | None = None
#: An optional list of port exposes, it is omitted if empty or ``None``.
exposes_ports: list[NetworkPort] | None = None

#: Extra environment variables to be set in the container
env: dict[str, str | int] | dict[str, str] | dict[str, int] = field(
Expand Down Expand Up @@ -683,14 +684,14 @@ def _kiwi_volumes_expose(
self,
main_element: Literal["expose"],
entry_element: Literal["port number"],
entries: list[int] | None,
entries: list[NetworkPort] | None,
) -> str: ...

def _kiwi_volumes_expose(
self,
main_element: Literal["volumes", "expose"],
entry_element: Literal["volume name", "port number"],
entries: list[int] | list[str] | None,
entries: list[NetworkPort] | list[str] | None,
) -> str:
if not entries:
return ""
Expand Down Expand Up @@ -720,7 +721,7 @@ def exposes_kiwi(self) -> str:
def _dockerfile_volume_expose(
self,
instruction: Literal["EXPOSE"],
entries: list[str] | None,
entries: list[NetworkPort] | None,
) -> str: ...

@overload
Expand All @@ -733,11 +734,12 @@ def _dockerfile_volume_expose(
def _dockerfile_volume_expose(
self,
instruction: Literal["EXPOSE", "VOLUME"],
entries: list[str] | list[str] | None,
entries: list[NetworkPort] | list[str] | None,
):
if not entries:
return ""
return "\n" + f"{instruction} " + " ".join(e for e in entries)

return "\n" + f"{instruction} " + " ".join(str(e) for e in entries)

@property
def volume_dockerfile(self) -> str:
Expand Down
3 changes: 2 additions & 1 deletion 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.container_attributes import TCP
from bci_build.container_attributes import PackageType
from bci_build.containercrate import ContainerCrate
from bci_build.os_version import CAN_BE_LATEST_OS_VERSION
Expand Down Expand Up @@ -103,7 +104,7 @@ def _get_sac_supported_until(
f"/usr/{'libexec' if os_version in (OsVersion.TUMBLEWEED, OsVersion.SLE16_0) else 'lib'}/tomcat/server",
"start",
],
exposes_ports=["8080"],
exposes_ports=[TCP(8080)],
env={
"TOMCAT_MAJOR": int(tomcat_ver.partition(".")[0]),
"TOMCAT_VERSION": "%%tomcat_version%%",
Expand Down
17 changes: 9 additions & 8 deletions src/bci_build/package/appcontainers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from pathlib import Path

from bci_build.container_attributes import TCP
from bci_build.container_attributes import BuildType
from bci_build.container_attributes import PackageType
from bci_build.container_attributes import SupportLevel
Expand Down Expand Up @@ -73,7 +74,7 @@ def _envsubst_pkg_name(os_version: OsVersion) -> str:
build_recipe_type=BuildType.DOCKER,
extra_files=_PCP_FILES,
volumes=["/var/log/pcp/pmlogger"],
exposes_ports=["44321", "44322", "44323"],
exposes_ports=[TCP(44321), TCP(44322), TCP(44323)],
custom_end=f"""
{DOCKERFILE_RUN} mkdir -p /usr/share/container-scripts/pcp; mkdir -p /etc/sysconfig
COPY container-entrypoint healthcheck /usr/local/bin/
Expand Down Expand Up @@ -117,7 +118,7 @@ def _envsubst_pkg_name(os_version: OsVersion) -> str:
parse_version=ParseVersion.MINOR,
)
],
exposes_ports=["3389", "3636"],
exposes_ports=[TCP(3389), TCP(3636)],
volumes=["/data"],
custom_end=rf"""
COPY nsswitch.conf /etc/nsswitch.conf
Expand Down Expand Up @@ -169,7 +170,7 @@ def _generate_prometheus_family_healthcheck(port: int) -> str:
for level in (ParseVersion.MAJOR, ParseVersion.MINOR, ParseVersion.PATCH)
],
volumes=["/var/lib/prometheus"],
exposes_ports=[str(_PROMETHEUS_PORT)],
exposes_ports=[TCP(_PROMETHEUS_PORT)],
custom_end=_generate_prometheus_family_healthcheck(_PROMETHEUS_PORT),
)
for os_version in ALL_NONBASE_OS_VERSIONS
Expand Down Expand Up @@ -197,7 +198,7 @@ def _generate_prometheus_family_healthcheck(port: int) -> str:
for level in (ParseVersion.MINOR, ParseVersion.PATCH)
],
volumes=["/var/lib/prometheus/alertmanager"],
exposes_ports=[str(_ALERTMANAGER_PORT)],
exposes_ports=[TCP(_ALERTMANAGER_PORT)],
custom_end=_generate_prometheus_family_healthcheck(_ALERTMANAGER_PORT),
)
for os_version in ALL_NONBASE_OS_VERSIONS
Expand Down Expand Up @@ -225,7 +226,7 @@ def _generate_prometheus_family_healthcheck(port: int) -> str:
)
for level in (ParseVersion.MINOR, ParseVersion.PATCH)
],
exposes_ports=[str(_BLACKBOX_PORT)],
exposes_ports=[TCP(_BLACKBOX_PORT)],
custom_end=_generate_prometheus_family_healthcheck(_BLACKBOX_PORT),
)
for os_version in ALL_NONBASE_OS_VERSIONS
Expand Down Expand Up @@ -267,7 +268,7 @@ def _generate_prometheus_family_healthcheck(port: int) -> str:
for level in (ParseVersion.MAJOR, ParseVersion.MINOR, ParseVersion.PATCH)
],
volumes=["/var/lib/grafana"],
exposes_ports=["3000"],
exposes_ports=[TCP(3000)],
custom_end=f"""COPY run.sh /run.sh
{DOCKERFILE_RUN} chmod +x /run.sh
""",
Expand Down Expand Up @@ -309,7 +310,7 @@ def _get_nginx_kwargs(os_version: OsVersion):
"build_recipe_type": BuildType.DOCKER,
"extra_files": _NGINX_FILES,
"support_level": SupportLevel.L3,
"exposes_ports": ["80"],
"exposes_ports": [TCP(80)],
"custom_end": f"""{ version_check_lines }
{DOCKERFILE_RUN} mkdir /docker-entrypoint.d
COPY [1-3]0-*.sh /docker-entrypoint.d/
Expand Down Expand Up @@ -421,7 +422,7 @@ def _get_nginx_kwargs(os_version: OsVersion):
cmd=["serve", "/etc/registry/config.yml"],
build_recipe_type=BuildType.KIWI,
volumes=["/var/lib/docker-registry"],
exposes_ports=["5000"],
exposes_ports=[TCP(5000)],
support_level=SupportLevel.L3,
)
for os_version in ALL_NONBASE_OS_VERSIONS
Expand Down
3 changes: 2 additions & 1 deletion src/bci_build/package/mariadb.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import re
from pathlib import Path

from bci_build.container_attributes import TCP
from bci_build.container_attributes import BuildType
from bci_build.container_attributes import SupportLevel
from bci_build.os_version import ALL_NONBASE_OS_VERSIONS
Expand Down Expand Up @@ -112,7 +113,7 @@
build_recipe_type=BuildType.DOCKER,
cmd=["mariadbd"],
volumes=["/var/lib/mysql"],
exposes_ports=["3306"],
exposes_ports=[TCP(3306)],
custom_end=rf"""{version_check_lines}
{DOCKERFILE_RUN} mkdir /docker-entrypoint-initdb.d
Expand Down
3 changes: 2 additions & 1 deletion src/bci_build/package/postfix.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from pathlib import Path

from bci_build.container_attributes import TCP
from bci_build.container_attributes import SupportLevel
from bci_build.os_version import ALL_NONBASE_OS_VERSIONS
from bci_build.os_version import CAN_BE_LATEST_OS_VERSION
Expand Down Expand Up @@ -92,7 +93,7 @@
license="(EPL-2.0 OR IPL-1.0) AND MIT",
extra_files=_POSTFIX_FILES,
support_level=SupportLevel.TECHPREVIEW,
exposes_ports=["25", "465", "587"],
exposes_ports=[TCP(25), TCP(465), TCP(587)],
volumes=["/var/spool/postfix", "/var/spool/vmail", "/etc/pki"],
custom_end=f"""{DOCKERFILE_RUN} mkdir -p /entrypoint/ldap
COPY {"entrypoint.sh" if os_version == OsVersion.TUMBLEWEED else "entrypoint.sles.sh"} /entrypoint/entrypoint.sh
Expand Down
5 changes: 3 additions & 2 deletions src/bci_build/package/postgres.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from pathlib import Path

from bci_build.container_attributes import TCP
from bci_build.container_attributes import SupportLevel
from bci_build.os_version import OsVersion
from bci_build.package import DOCKERFILE_RUN
Expand All @@ -27,7 +28,7 @@
support_level=SupportLevel.ACC,
package_list=["libpq5", f"postgresql{ver}-server", "findutils"],
version="%%pg_patch_version%%",
tag_version=ver,
tag_version=str(ver),
additional_versions=["%%pg_minor_version%%"],
entrypoint=["/usr/local/bin/docker-entrypoint.sh"],
cmd=["postgres"],
Expand Down Expand Up @@ -57,7 +58,7 @@
),
],
volumes=["$PGDATA"],
exposes_ports=["5432"],
exposes_ports=[TCP(5432)],
custom_end=rf"""COPY docker-entrypoint.sh /usr/local/bin/
{DOCKERFILE_RUN} chmod +x /usr/local/bin/docker-entrypoint.sh; \
sed -i -e 's/exec gosu postgres "/exec setpriv --reuid=postgres --regid=postgres --clear-groups -- "/g' /usr/local/bin/docker-entrypoint.sh; \
Expand Down
9 changes: 5 additions & 4 deletions tests/test_build_recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import pytest

from bci_build.container_attributes import TCP
from bci_build.container_attributes import Arch
from bci_build.container_attributes import BuildType
from bci_build.container_attributes import PackageType
Expand Down Expand Up @@ -398,7 +399,7 @@
ENTRYPOINT ["/usr/bin/emacs"]
CMD ["/usr/bin/gcc"]
EXPOSE 22 1111
EXPOSE 22/tcp 1111/tcp
RUN emacs -Q --batch
VOLUME /bin/ /usr/bin/""",
"""<?xml version="1.0" encoding="utf-8"?>
Expand Down Expand Up @@ -450,8 +451,8 @@
<volume name="/usr/bin/" />
</volumes>
<expose>
<port number="22" />
<port number="1111" />
<port number="22/tcp" />
<port number="1111/tcp" />
</expose>
<environment>
<env name="EMACS_VERSION" value="28"/>
Expand Down Expand Up @@ -490,7 +491,7 @@
volumes=["/bin/", "/usr/bin/"],
# does nothing on TW
supported_until=date(2024, 2, 1),
exposes_ports=["22", "1111"],
exposes_ports=[TCP(22), TCP(1111)],
license="BSD",
version="28.2",
additional_names=["emacs"],
Expand Down
12 changes: 7 additions & 5 deletions tests/test_package.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from bci_build.container_attributes import TCP
from bci_build.container_attributes import UDP
from tests.conftest import BCI_FIXTURE_RET_T


Expand Down Expand Up @@ -96,11 +98,11 @@ def test_expose_port_kiwi(bci: BCI_FIXTURE_RET_T):
cls, kwargs = bci

assert (
cls(**kwargs, exposes_ports=["443", "80"]).exposes_kiwi
cls(**kwargs, exposes_ports=[TCP(443), TCP(80)]).exposes_kiwi
== """
<expose>
<port number="443" />
<port number="80" />
<port number="443/tcp" />
<port number="80/tcp" />
</expose>"""
)

Expand All @@ -117,8 +119,8 @@ def test_expose_dockerfile(bci: BCI_FIXTURE_RET_T):
cls, kwargs = bci

assert (
cls(**kwargs, exposes_ports=["80", "443", "67/udp"]).expose_dockerfile
== "\nEXPOSE 80 443 67/udp"
cls(**kwargs, exposes_ports=[TCP(80), TCP(443), UDP(67)]).expose_dockerfile
== "\nEXPOSE 80/tcp 443/tcp 67/udp"
)


Expand Down

0 comments on commit c283575

Please sign in to comment.