diff --git a/.gitignore b/.gitignore index 9565728d7..9f4a4b40d 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ debian/scst.dkms debian/scst/ debian/scstadmin/ debian/tmp/ +docker-rpmbuilddir/ dpkg/ fcst/build_mode iscsi-scst/conftest/*/result-*.txt @@ -58,6 +59,7 @@ nightly/old.verbose nightly/sendmail.log qla2x00t/in-tree-patches/ qla2x00t/qla2xxx-orig/ +rpm-artifacts/ rpmbuilddir/ scst.spec scst/build_mode diff --git a/Makefile b/Makefile index 707ca1e02..08bcfc688 100644 --- a/Makefile +++ b/Makefile @@ -93,6 +93,23 @@ VERSION := $(RELEASE_VERSION).$(REVISION) DEBIAN_REVISION := 1.1 RPMTOPDIR ?= $(shell if [ $$(id -u) = 0 ]; then echo /usr/src/packages;\ else echo $$PWD/rpmbuilddir; fi) +DOCKER ?= docker +DOCKER_RPM_TARGET ?= rocky-10.2 +DOCKER_RPM_CONTEXT ?= docker/rpm +DOCKER_RPM_DOCKERFILE ?= $(DOCKER_RPM_CONTEXT)/Dockerfile +DOCKER_RPM_IMAGE ?= scst-rpm-builder:$(DOCKER_RPM_TARGET) +DOCKER_RPM_OUTPUT ?= $(CURDIR)/docker-rpmbuilddir/$(DOCKER_RPM_TARGET) +DOCKER_RPM_BASE_IMAGE ?= $(shell bash scripts/kernel-matrix rpm-field \ + "$(DOCKER_RPM_TARGET)" base_image) +DOCKER_RPM_KERNEL_PACKAGE ?= $(shell bash scripts/kernel-matrix rpm-field \ + "$(DOCKER_RPM_TARGET)" kernel_package) +DOCKER_RPM_KERNEL_VERSION ?= $(shell bash scripts/kernel-matrix rpm-field \ + "$(DOCKER_RPM_TARGET)" kernel_version) +DOCKER_RPM_KERNEL_REPOSITORY ?= $(shell bash scripts/kernel-matrix rpm-field \ + "$(DOCKER_RPM_TARGET)" kernel_repository) +RPM_ARTIFACT_SOURCE_DIR ?= $(CURDIR) +RPM_ARTIFACT_OUTPUT_DIR ?= $(CURDIR)/rpm-artifacts +RPM_ARTIFACT_KERNEL_DEVEL_PACKAGE ?= kernel-devel SCST_SOURCE_FILES = $(shell if [ -e scripts/list-source-files ]; then \ scripts/list-source-files; \ else \ @@ -173,6 +190,9 @@ help: @echo " scstadm-rpm : make scstadmin RPM packages" @echo " rpm : make both SCST and scstadmin RPM packages" @echo " rpm-dkms : make both SCST DKMS and scstadmin RPM packages" + @echo " rpm-artifacts : build verified RPM artifacts" + @echo " docker-rpm-image : build the RPM builder Docker image" + @echo " docker-rpm : build RPM packages in Docker" @echo "" @echo " dpkg : make SCST dpkg packages" @echo "" @@ -432,6 +452,41 @@ rpm-dkms: find -name '*.rpm'; \ fi +rpm-artifacts: + mkdir -p "$(RPM_ARTIFACT_OUTPUT_DIR)" + RPM_ARTIFACT_SOURCE_DIR="$(RPM_ARTIFACT_SOURCE_DIR)" \ + RPM_ARTIFACT_OUTPUT_DIR="$(RPM_ARTIFACT_OUTPUT_DIR)" \ + RPM_ARTIFACT_KERNEL_DEVEL_PACKAGE="$(RPM_ARTIFACT_KERNEL_DEVEL_PACKAGE)" \ + bash "$(CURDIR)/scripts/build-rpm-artifacts" + +docker-rpm-image: + test -n "$(DOCKER_RPM_BASE_IMAGE)" + test -n "$(DOCKER_RPM_KERNEL_PACKAGE)" + test -n "$(DOCKER_RPM_KERNEL_VERSION)" + $(DOCKER) build --file "$(DOCKER_RPM_DOCKERFILE)" \ + --build-arg "BASE_IMAGE=$(DOCKER_RPM_BASE_IMAGE)" \ + --build-arg "KERNEL_PACKAGE=$(DOCKER_RPM_KERNEL_PACKAGE)" \ + --build-arg "KERNEL_VERSION=$(DOCKER_RPM_KERNEL_VERSION)" \ + --build-arg \ + "KERNEL_REPOSITORY=$(DOCKER_RPM_KERNEL_REPOSITORY)" \ + --tag "$(DOCKER_RPM_IMAGE)" "$(DOCKER_RPM_CONTEXT)" + +docker-rpm: docker-rpm-image + mkdir -p "$(DOCKER_RPM_OUTPUT)" + git_common_dir="$$(git rev-parse --path-format=absolute \ + --git-common-dir)" && \ + $(DOCKER) run --rm \ + --user "$$(id -u):$$(id -g)" \ + --env HOME=/tmp \ + --mount "type=bind,source=$(CURDIR),target=/source,readonly" \ + --mount "type=bind,source=$${git_common_dir},target=$${git_common_dir},readonly" \ + --mount "type=bind,source=$(DOCKER_RPM_OUTPUT),target=/output" \ + "$(DOCKER_RPM_IMAGE)" \ + make -C /source rpm-artifacts \ + RPM_ARTIFACT_SOURCE_DIR=/source \ + RPM_ARTIFACT_OUTPUT_DIR=/output \ + RPM_ARTIFACT_KERNEL_DEVEL_PACKAGE="$(DOCKER_RPM_KERNEL_PACKAGE)-devel" + debian/changelog: debian/changelog.in sed 's/%{scst_version}/$(VERSION)-$(DEBIAN_REVISION)/' \ debian/changelog @@ -528,5 +583,6 @@ multiple-release-archives: fcst fcst_clean fcst_extraclean fcst_install fcst_uninstall \ scst_local scst_local_clean scst_local_extraclean scst_local_install scst_local_uninstall \ usr usr_clean usr_extraclean usr_install usr_uninstall \ - scst-rpm scst-dkms-rpm scstadm-rpm rpm rpm-dkms dpkg \ + scst-rpm scst-dkms-rpm scstadm-rpm rpm rpm-dkms rpm-artifacts \ + docker-rpm-image docker-rpm dpkg \ 2perf 2release 2debug diff --git a/docker/rpm/Dockerfile b/docker/rpm/Dockerfile new file mode 100644 index 000000000..91988a2a5 --- /dev/null +++ b/docker/rpm/Dockerfile @@ -0,0 +1,43 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} + +SHELL ["/bin/bash", "-euxo", "pipefail", "-c"] + +ARG KERNEL_PACKAGE=kernel +ARG KERNEL_VERSION +ARG KERNEL_REPOSITORY= + +ENV LANG=C \ + LC_ALL=C + +RUN : "${KERNEL_PACKAGE:?KERNEL_PACKAGE is required}" \ + && : "${KERNEL_VERSION:?KERNEL_VERSION is required}" \ + && repo_args=() \ + && if [[ -n "${KERNEL_REPOSITORY}" ]]; then \ + repo_args+=(--enablerepo="${KERNEL_REPOSITORY}"); \ + fi \ + && dnf -y install \ + bzip2 \ + elfutils-libelf-devel \ + findutils \ + gcc \ + git \ + kmod \ + make \ + openssl \ + perl \ + perl-Data-Dumper \ + perl-devel \ + perl-ExtUtils-MakeMaker \ + redhat-rpm-config \ + rpm-build \ + systemd-rpm-macros \ + tar \ + which \ + && dnf -y "${repo_args[@]}" install \ + "${KERNEL_PACKAGE}-${KERNEL_VERSION}" \ + "${KERNEL_PACKAGE}-devel-${KERNEL_VERSION}" \ + && dnf clean all \ + && rm -rf /var/cache/dnf + +CMD ["/bin/bash"] diff --git a/scripts/build-rpm-artifacts b/scripts/build-rpm-artifacts new file mode 100644 index 000000000..0b4a9152c --- /dev/null +++ b/scripts/build-rpm-artifacts @@ -0,0 +1,96 @@ +#!/bin/bash + +set -euo pipefail + +readonly source_dir="${RPM_ARTIFACT_SOURCE_DIR:-$PWD}" +readonly output_dir="${RPM_ARTIFACT_OUTPUT_DIR:-$PWD/rpm-artifacts}" +readonly kernel_devel_package="${RPM_ARTIFACT_KERNEL_DEVEL_PACKAGE:-kernel-devel}" + +if ! git -C "${source_dir}" rev-parse --is-inside-work-tree >/dev/null 2>&1; then + echo "Error: ${source_dir} is not an SCST Git worktree." >&2 + exit 1 +fi + +if [[ ! -d "${output_dir}" || ! -w "${output_dir}" ]]; then + echo "Error: ${output_dir} is not a writable output directory." >&2 + exit 1 +fi + +mapfile -t kernel_releases < <( + rpm -q --qf '%{VERSION}-%{RELEASE}.%{ARCH}\n' \ + "${kernel_devel_package}" 2>/dev/null | sort -V +) +if [[ ${#kernel_releases[@]} -ne 1 ]]; then + echo "Error: expected exactly one ${kernel_devel_package} package." >&2 + printf 'Found kernel releases: %s\n' "${kernel_releases[*]:-none}" >&2 + exit 1 +fi + +readonly kernel_release="${kernel_releases[0]}" +readonly kernel_dir="/usr/src/kernels/${kernel_release}" +if [[ ! -d "${kernel_dir}" ]]; then + echo "Error: kernel build directory ${kernel_dir} does not exist." >&2 + exit 1 +fi + +tmp_dir="$(mktemp -d)" +readonly tmp_dir +artifact_stage="" +cleanup() { + rm -rf -- "${tmp_dir}" + if [[ -n "${artifact_stage}" ]]; then + rm -rf -- "${artifact_stage}" + fi +} +trap cleanup EXIT + +readonly build_dir="${tmp_dir}/scst" +readonly rpm_topdir="${tmp_dir}/rpmbuild" +mkdir -p "${build_dir}" "${rpm_topdir}" + +git -C "${source_dir}" ls-files -z -- | + tar --directory="${source_dir}" --null --files-from=- --create --file=- | + tar --directory="${build_dir}" --extract --file=- + +git_commit="${GIT_COMMIT:-$(git -C "${source_dir}" rev-parse --short=12 HEAD)}" +build_number="${BUILD_NUMBER:-$(git -C "${source_dir}" rev-list --count HEAD)}" +revision="${REVISION:-${build_number}.${git_commit}}" +readonly git_commit build_number revision + +make -C "${build_dir}" \ + BUILD_NUMBER="${build_number}" \ + GIT_COMMIT="${git_commit}" \ + REVISION="${revision}" \ + KDIR="${kernel_dir}" \ + KVER="${kernel_release}" \ + RPMTOPDIR="${rpm_topdir}" \ + rpm + +mapfile -d '' -t rpm_files < <( + find "${rpm_topdir}/RPMS" "${rpm_topdir}/SRPMS" \ + -type f -name '*.rpm' -print0 | sort -z +) +if [[ ${#rpm_files[@]} -eq 0 ]]; then + echo "Error: the RPM build produced no packages." >&2 + exit 1 +fi +rpm --checksig --nosignature "${rpm_files[@]}" + +artifact_stage="$(mktemp -d "${output_dir}/.scst-rpm.XXXXXX")" +cp -a "${rpm_topdir}/RPMS" "${rpm_topdir}/SRPMS" "${artifact_stage}/" +( + cd "${artifact_stage}" + find RPMS SRPMS -type f -name '*.rpm' -print0 | + sort -z | xargs -0 sha256sum >SHA256SUMS +) + +rm -rf -- "${output_dir}/RPMS" "${output_dir}/SRPMS" +rm -f -- "${output_dir}/SHA256SUMS" +mv "${artifact_stage}/RPMS" "${artifact_stage}/SRPMS" \ + "${artifact_stage}/SHA256SUMS" "${output_dir}/" +rmdir "${artifact_stage}" +artifact_stage="" + +echo "Built SCST RPM packages for kernel ${kernel_release}:" +find "${output_dir}/RPMS" "${output_dir}/SRPMS" \ + -type f -name '*.rpm' -print | sort diff --git a/scst.spec.in b/scst.spec.in index e59ddceab..080dea8de 100644 --- a/scst.spec.in +++ b/scst.spec.in @@ -59,6 +59,10 @@ # UEK 7 %define kernel_devel_rpm kernel-uek-devel %else +%if %([ %{kernel_rpm} = kernel-uek-modules-core ]; echo $((1-$?))) +# UEK 8 +%define kernel_devel_rpm kernel-uek-devel +%else # Other Linux distros %define kernel_devel_rpm %{kernel_rpm}-devel %endif @@ -66,6 +70,7 @@ %endif %endif %endif +%endif %{echo:kernel_devel_rpm=%{kernel_devel_rpm} } %endif