diff --git a/.github/workflows/cd-rockylinux9-rpm-builder.yaml b/.github/workflows/cd-rockylinux9-rpm-builder.yaml new file mode 100644 index 0000000..baee4be --- /dev/null +++ b/.github/workflows/cd-rockylinux9-rpm-builder.yaml @@ -0,0 +1,47 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: CD for rockylinux9-rpm-builder + +on: + push: + branches: ['main'] + paths: ['rockylinux9-rpm-builder/**', '!**/*.md'] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: urbdyn/rockylinux9-rpm-builder + +jobs: + build-and-push-image: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: ./rockylinux9-rpm-builder + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/ci-rockylinux9-rpm-builder.yaml b/.github/workflows/ci-rockylinux9-rpm-builder.yaml new file mode 100644 index 0000000..6339622 --- /dev/null +++ b/.github/workflows/ci-rockylinux9-rpm-builder.yaml @@ -0,0 +1,47 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: CI for rockylinux9-rpm-builder + +on: + pull_request: + branches: ['main'] + paths: ['rockylinux9-rpm-builder/**', '!**/*.md'] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: urbdyn/rockylinux9-rpm-builder + +jobs: + build-image: + runs-on: ubuntu-latest + permissions: + contents: read + packages: read + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Build Docker image + uses: docker/build-push-action@v6 + with: + context: ./rockylinux9-rpm-builder + push: false + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/README.md b/README.md index b7e4cb6..4972b33 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,4 @@ This repo is a collection of utilities for building software as used by Urban Dy 2. [centos7-rpm-builder](./centos7-rpm-builder/) 3. [rockylinux8-rpm-builder](./rockylinux8-rpm-builder/) 4. [rockylinux9-builder](./rockylinux9-builder/) +5. [rockylinux9-rpm-builder](./rockylinux9-rpm-builder/) diff --git a/rockylinux9-rpm-builder/Dockerfile b/rockylinux9-rpm-builder/Dockerfile new file mode 100644 index 0000000..c69376e --- /dev/null +++ b/rockylinux9-rpm-builder/Dockerfile @@ -0,0 +1,15 @@ +# This file builds an RPM build image for Rocky Linux 9 + +# Using Rock Linux 9 as base image to support rpmbuild +FROM rockylinux:9 + +# Installing tools needed for rpmbuild +RUN dnf install -y rpm-build rpmlint rpmdevtools systemd sudo selinux-policy-devel && \ + dnf clean all + +# Copy over helper scripts +COPY setup_rpm_users /usr/bin/setup_rpm_users +COPY build_rpm_from_env_vars /usr/bin/build_rpm_from_env_vars + +# Setup commend to run by default +CMD build_rpm_from_env_vars run diff --git a/rockylinux9-rpm-builder/README.md b/rockylinux9-rpm-builder/README.md new file mode 100644 index 0000000..7b767eb --- /dev/null +++ b/rockylinux9-rpm-builder/README.md @@ -0,0 +1,47 @@ +# urbdyn/rockylinux9-rpm-builder + +This is a Docker container for building Rocky Linux 9 RPM packages. + +It has the benefit of providing all the needed boiler plate and avoiding the long waits in CI needed to install the full build toolchain in a clean container. + +Our recommended use of it is to build your own container with it to ensure the user/group of the person running the container matches that of the internal container user. +This means you can easily copy files and mount directories between the host and container without issue. + +## Creating container with this container + +```Dockerfile +FROM urbdyn/rockylinux9-rpm-builder:latest + +# Accept user input when building container with fallback to common Linux user pattern +ARG _USER_ID +ARG _GROUP_ID +ENV _USER_ID ${_USER_ID:-1001} +ENV _GROUP_ID ${_GROUP_ID:-1002} + +# Run script to create users and declare new user as default +RUN setup_rpm_users +USER $_USER_ID:$_GROUP_ID + +# Install any needed packages here +# ... +``` + +## Running container + +```bash +docker create -it \ + --user "$_uid:$_gid" \ + --name "$container_builder_container" \ + -v "$build_dir/:/home/builder/rpmbuild/" \ + -e SPEC_FILE_NAMES="foobar.spec" \ + -e PACKAGE_NAME="foobar" \ + -e PACKAGE_VERSION="1.2.3" \ + -e PACKAGE_LICENSE="MY LICENSE" \ + -e PACKAGE_SOURCE="foobar.tar.gz" \ + "$container_builder_image" +``` + + +## Change Log + +TODO: Add this after initial PR is merged. diff --git a/rockylinux9-rpm-builder/build_rpm_from_env_vars b/rockylinux9-rpm-builder/build_rpm_from_env_vars new file mode 100755 index 0000000..859085d --- /dev/null +++ b/rockylinux9-rpm-builder/build_rpm_from_env_vars @@ -0,0 +1,87 @@ +#!/usr/bin/env bash + +set -e + +help_text=" +build_rpm_from_env_args [COMMAND] + + When run, this script will run 'rpm-setuptree' followed by 'rpmbuild' + with all given environmental variables. See below for details and print + out of current variables detected. + +COMMANDS: + run - Do the build (details above) + help - Print this help menu + +ENV VARIABLES: + SPEC_FILE_NAMES - File names of '.spec' file in ~/rpmbuild/SPECS/ used (REQUIRED, comma delimited) + PACKAGE_NAME - Provided to 'rpmbuild' as variable: package_name + PACKAGE_VERSION - Provided to 'rpmbuild' as variable: package_version + PACKAGE_LICENSE - Provided to 'rpmbuild' as variable: package_license + PACKAGE_SOURCE - Provided to 'rpmbuild' as variable: package_source + +DETECTED VARIABLE VALUES: + SPEC_FILE_NAMES - $SPEC_FILE_NAMES + PACKAGE_NAME - $PACKAGE_NAME + PACKAGE_VERSION - $PACKAGE_VERSION + PACKAGE_LICENSE - $PACKAGE_LICENSE + PACKAGE_SOURCE - $PACKAGE_SOURCE +" + +function detect_env_var() { + var_name="$1" + var_value="${!var_name}" + required="$2" + + if [[ "$required" = "true" ]] && [[ "$var_value" = "" ]]; then + echo "Required variable '$var_name' not detected! Exiting." + exit 1 + elif [[ "$var_value" = "" ]]; then + echo "No value detected for variable '$var_name'" + else + echo "Value detected for variable '$var_name' = $var_value" + fi +} + +function do_run() { + detect_env_var "SPEC_FILE_NAMES" true + detect_env_var "PACKAGE_NAME" + detect_env_var "PACKAGE_VERSION" + detect_env_var "PACKAGE_LICENSE" + detect_env_var "PACKAGE_SOURCE" + + echo -e "\Running rpmdev-setuptree:" + sudo rpmdev-setuptree + + # Split SPEC_FILE_NAMES by ',' for loop + for SPEC_FILE_NAME in ${SPEC_FILE_NAMES//,/ }; do + echo -e "\nBuilding rpm file for $SPEC_FILE_NAME:" + rpmbuild -ba \ + --define "package_version $PACKAGE_VERSION" \ + --define "package_name $PACKAGE_NAME" \ + --define "package_license $PACKAGE_LICENSE" \ + --define "package_source $PACKAGE_SOURCE" \ + ~/rpmbuild/SPECS/"$SPEC_FILE_NAME" + + echo -e "\n\nBuild code: $?\n" + done +} + +function main() { + case "$1" in + "run") + do_run + exit 0 + ;; + ""|"help"|"--help"|"-h") + echo "$help_text" + exit 0 + ;; + *) + echo "Command not recognized: $1" + exit 1 + ;; + esac +} + +main $@ diff --git a/rockylinux9-rpm-builder/setup_rpm_users b/rockylinux9-rpm-builder/setup_rpm_users new file mode 100755 index 0000000..5478491 --- /dev/null +++ b/rockylinux9-rpm-builder/setup_rpm_users @@ -0,0 +1,92 @@ +#!/usr/bin/env bash + +set -e + +help_text=" +setup_rpm_user + + Takes two environmental variables (_USER_ID and _GROUP_ID) and creates + a new user with which is added so the sudo'er list through membership + in 'builder' group. + +COMMANDS: + run - Do the build (details above) + help - Print this help menu + +ENV VARIABLES: + _USER_ID - Name of new user to run script for (REQUIRED) + _GROUP_ID - Name of new group to run script for (REQUIRED) + +DETECTED VARIABLE VALUES: + _USER_ID - $_USER_ID + _GROUP_ID - $_GROUP_ID +" + +function detect_env_var() { + var_name="$1" + var_value="${!var_name}" + required="$2" + + if [[ "$required" = "true" ]] && [[ "$var_value" = "" ]]; then + echo "Required variable '$var_name' not detected! Exiting." + exit 1 + elif [[ "$var_value" = "" ]]; then + echo "No value detected for variable '$var_name'" + else + echo "Value detected for variable '$var_name' = $var_value" + fi +} + +function do_run() { + detect_env_var "_USER_ID" true + detect_env_var "_GROUP_ID" true + + echo "Adding builder user/group ($_USER_ID:$_GROUP_ID) ..." + # Detecting existing user and group + set +e + existing_group_name="$(getent group "$_GROUP_ID" | cut -d: -f1)" + existing_user_name="$(getent passwd "$_USER_ID" | cut -d: -f1)" + set -e + # Group creation + if [ "$existing_group_name" != "" ]; then + echo "Skipping creating builder group as group with desired ID $_GROUP_ID already exists: $existing_group_name" + else + echo "Creating builder group ..." + groupadd -g "$_GROUP_ID" builder + fi + final_group_name="$(getent group "$_GROUP_ID" | cut -d: -f1)" + # User creation + if [ "$existing_user_name" != "" ]; then + echo "Skipping creating builder user as user with desired ID $_USER_ID already exists: $existing_user_name" + echo "Attempting to add existing user to group $final_group_name ($_GROUP_ID) ..." + usermod -a -G "$final_group_name" "$existing_user_name" + else + echo "Creating builder user ..." + useradd -u "$_USER_ID" -g "$_GROUP_ID" builder + fi + # Add to sudoers + final_user_name="$(getent passwd "$_USER_ID" | cut -d: -f1)" + echo "$final_user_name ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers + + echo "Id for container user:" + id "$_USER_ID" +} + +function main() { + case "$1" in + "run") + do_run + exit 0 + ;; + ""|"help"|"--help"|"-h") + echo "$help_text" + exit 0 + ;; + *) + echo "Command not recognized: $1" + exit 1 + ;; + esac +} + +main $@