From: Daan De Meyer Date: Tue, 10 Oct 2023 09:48:01 +0000 (+0200) Subject: Add RHEL support X-Git-Tag: v19~87^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=35148c8b606bcc45c9e9755184a73bce2ab573a0;p=thirdparty%2Fmkosi.git Add RHEL support To make RHEL work, we have to look up the necessary certificates and add them to the generated repo files. This requires the image build to be done from a system with a RHEL subscription. --- diff --git a/mkosi/distributions/__init__.py b/mkosi/distributions/__init__.py index 839d6ec13..858e093b7 100644 --- a/mkosi/distributions/__init__.py +++ b/mkosi/distributions/__init__.py @@ -81,6 +81,7 @@ class Distribution(StrEnum): opensuse = enum.auto() mageia = enum.auto() centos = enum.auto() + rhel = enum.auto() rhel_ubi = enum.auto() openmandriva = enum.auto() rocky = enum.auto() @@ -96,6 +97,7 @@ class Distribution(StrEnum): Distribution.fedora, Distribution.mageia, Distribution.centos, + Distribution.rhel, Distribution.rhel_ubi, Distribution.openmandriva, Distribution.rocky, diff --git a/mkosi/distributions/rhel.py b/mkosi/distributions/rhel.py new file mode 100644 index 000000000..cfcd568cb --- /dev/null +++ b/mkosi/distributions/rhel.py @@ -0,0 +1,107 @@ +# SPDX-License-Identifier: LGPL-2.1+ + +from collections.abc import Iterable +from pathlib import Path +from typing import Any, Optional + +from mkosi.distributions import centos +from mkosi.installer.dnf import Repo +from mkosi.log import die +from mkosi.state import MkosiState + + +class Installer(centos.Installer): + @classmethod + def pretty_name(cls) -> str: + return "RHEL" + + @staticmethod + def gpgurls(state: MkosiState) -> tuple[str, ...]: + return ("https://access.redhat.com/security/data/fd431d51.txt",) + + @staticmethod + def sslcacert(state: MkosiState) -> Optional[Path]: + if state.config.mirror: + return None + + p = Path("etc/rhsm/ca/redhat-uep.pem") + if (state.pkgmngr / p).exists(): + p = state.pkgmngr / p + elif (Path("/") / p).exists(): + p = Path("/") / p + else: + die("redhat-uep.pem certificate not found in host system or package manager tree") + + return p + + @staticmethod + def sslclientkey(state: MkosiState) -> Optional[Path]: + if state.config.mirror: + return None + + pattern = "etc/pki/entitlement/*-key.pem" + + p = next((p for p in sorted(state.pkgmngr.glob(pattern))), None) + if not p: + p = next((p for p in Path("/").glob(pattern)), None) + if not p: + die("Entitlement key not found in host system or package manager tree") + + return p + + @staticmethod + def sslclientcert(state: MkosiState) -> Optional[Path]: + if state.config.mirror: + return None + + pattern = "etc/pki/entitlement/*.pem" + + p = next((p for p in sorted(state.pkgmngr.glob(pattern)) if "key" not in p.name), None) + if not p: + p = next((p for p in sorted(Path("/").glob(pattern)) if "key" not in p.name), None) + if not p: + die("Entitlement certificate not found in host system or package manager tree") + + return p + + @classmethod + def repository_variants(cls, state: MkosiState, repo: str) -> Iterable[Repo]: + if state.config.local_mirror: + yield Repo(repo, f"baseurl={state.config.local_mirror}", cls.gpgurls(state)) + else: + mirror = state.config.mirror or "https://cdn.redhat.com/content/dist/" + + common: dict[str, Any] = dict( + gpgurls=cls.gpgurls(state), + sslcacert=cls.sslcacert(state), + sslclientcert=cls.sslclientcert(state), + sslclientkey=cls.sslclientkey(state), + ) + + v = state.config.release + major = int(float(v)) + yield Repo( + f"rhel-{v}-{repo}-rpms", + f"baseurl={centos.join_mirror(mirror, f'rhel{major}/{v}/$basearch/{repo}/os')}", + enabled=True, + **common, + ) + yield Repo( + f"rhel-{v}-{repo}-debug-rpms", + f"baseurl={centos.join_mirror(mirror, f'rhel{major}/{v}/$basearch/{repo}/debug')}", + enabled=False, + **common, + ) + yield Repo( + f"rhel-{v}-{repo}-source", + f"baseurl={centos.join_mirror(mirror, f'rhel{major}/{v}/$basearch/{repo}/source')}", + enabled=False, + **common, + ) + + @classmethod + def repositories(cls, state: MkosiState, release: int) -> Iterable[Repo]: + yield from cls.repository_variants(state, "baseos") + yield from cls.repository_variants(state, "appstream") + yield from cls.repository_variants(state, "codeready-builder") + yield from cls.epel_repositories(state) diff --git a/mkosi/distributions/rhel_ubi.py b/mkosi/distributions/rhel_ubi.py index 95af16175..ce81e401e 100644 --- a/mkosi/distributions/rhel_ubi.py +++ b/mkosi/distributions/rhel_ubi.py @@ -47,3 +47,4 @@ class Installer(centos.Installer): yield from cls.repository_variants(state, "baseos") yield from cls.repository_variants(state, "appstream") yield from cls.repository_variants(state, "codeready-builder") + yield from cls.epel_repositories(state) diff --git a/mkosi/installer/dnf.py b/mkosi/installer/dnf.py index b760c5c28..963e21775 100644 --- a/mkosi/installer/dnf.py +++ b/mkosi/installer/dnf.py @@ -4,7 +4,7 @@ import shutil import textwrap from collections.abc import Iterable from pathlib import Path -from typing import NamedTuple +from typing import NamedTuple, Optional from mkosi.run import apivfs_cmd, bwrap from mkosi.state import MkosiState @@ -18,6 +18,9 @@ class Repo(NamedTuple): url: str gpgurls: tuple[str, ...] enabled: bool = True + sslcacert: Optional[Path] = None + sslclientkey: Optional[Path] = None + sslclientcert: Optional[Path] = None def dnf_executable(state: MkosiState) -> str: @@ -68,6 +71,13 @@ def setup_dnf(state: MkosiState, repos: Iterable[Repo], filelists: bool = True) ) ) + if repo.sslcacert: + f.write(f"sslcacert={repo.sslcacert}\n") + if repo.sslclientcert: + f.write(f"sslclientcert={repo.sslclientcert}\n") + if repo.sslclientkey: + f.write(f"sslclientkey={repo.sslclientkey}\n") + for i, url in enumerate(repo.gpgurls): f.write("gpgkey=" if i == 0 else len("gpgkey=") * " ") f.write(f"{url}\n") diff --git a/mkosi/resources/mkosi.md b/mkosi/resources/mkosi.md index 7d934679e..936140738 100644 --- a/mkosi/resources/mkosi.md +++ b/mkosi/resources/mkosi.md @@ -395,9 +395,10 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, : The distribution to install in the image. Takes one of the following arguments: `fedora`, `debian`, `ubuntu`, `arch`, `opensuse`, `mageia`, - `centos`, `rhel-ubi`, `openmandriva`, `rocky`, `alma`, `custom`. - If not specified, defaults to the distribution of the host or `custom` - if the distribution of the host is not a supported distribution. + `centos`, `rhel`, `rhel-ubi`, `openmandriva`, `rocky`, `alma`, + `custom`. If not specified, defaults to the distribution of the host + or `custom` if the distribution of the host is not a supported + distribution. `Release=`, `--release=`, `-r` @@ -1321,6 +1322,8 @@ distributions: * *CentOS* +* *RHEL* + * *RHEL UBI* * *OpenMandriva* @@ -1350,6 +1353,10 @@ combination of base trees, skeleton trees, and prepare scripts. Currently, *Fedora Linux* packages all relevant tools as of Fedora 28. +Note that when not using a custom mirror, `RHEL` images can only be +built from a host system with a `RHEL` subscription (established using +e.g. `subscription-manager`). + # Execution Flow Execution flow for `mkosi build`. Default values/calls are shown in parentheses.