name: Packaging
on:
push:
branches:
- main
tags:
- v*
defaults:
run:
shell: bash --noprofile --norc -eo pipefail -x {0}
jobs:
pkg:
strategy:
matrix:
image: - "ubuntu:xenial" - "ubuntu:bionic" - "ubuntu:focal" - "debian:stretch" - "debian:buster" - "debian:bullseye" - 'centos:7'
- 'centos:8'
env:
CARGO_DEB_VER: 1.28.0
CARGO_GENERATE_RPM_VER: 0.4.0
NEXT_VER_LABEL: dev
name: pkg
runs-on: ubuntu-latest
container: ${{ matrix.image }}
steps:
- name: Set vars
id: setvars
shell: bash
run: |
# Get the operating system and release name (e.g. ubuntu and xenial) from
# the image name (e.g. ubuntu:xenial) by extracting only the parts before
# and after but not including the colon:
echo "OS_NAME=${MATRIX_IMAGE%:*}" >> $GITHUB_ENV
echo "OS_REL=${MATRIX_IMAGE#*:}" >> $GITHUB_ENV
env:
MATRIX_IMAGE: ${{ matrix.image }}
- name: Checkout repository
uses: actions/checkout@v1
- name: Install Rust
run: |
case ${OS_NAME} in
debian|ubuntu)
apt-get update
apt-get install -y curl
;;
centos)
yum update -y
;;
esac
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --profile minimal -y
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
env:
DEBIAN_FRONTEND: noninteractive
- name: Install compilation and other dependencies
run: |
case ${OS_NAME} in
debian|ubuntu)
apt-get install -y build-essential jq lintian pkg-config
;;
centos)
yum install epel-release -y
yum update -y
yum install -y jq rpmlint
yum groupinstall -y "Development Tools"
;;
esac
env:
DEBIAN_FRONTEND: noninteractive
- name: Cache Dot Cargo
uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ matrix.image }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Cache Cargo Deb if available
id: cache-cargo-deb
uses: actions/cache@v2
with:
path: ~/.cargo/bin/cargo-deb
key: ${{ matrix.image }}-cargo-deb-${{ env.CARGO_DEB_VER }}
- name: Cache Cargo Generate RPM if available
id: cache-cargo-generate-rpm
uses: actions/cache@v2
with:
path: ~/.cargo/bin/cargo-generate-rpm
key: ${{ matrix.image }}-cargo-generate-rpm-${{ env.CARGO_GENERATE_RPM_VER }}
- name: Install Cargo Deb if needed
if: steps.cache-cargo-deb.outputs.cache-hit != 'true'
run: |
case ${OS_NAME} in
debian|ubuntu)
cargo install cargo-deb --version ${CARGO_DEB_VER}
;;
esac
- name: Install Cargo Generate RPM if needed
if: steps.cache-cargo-generate-rpm.outputs.cache-hit != 'true'
run: |
case ${OS_NAME} in
centos)
# Temporary workaround for https://github.com/cat-in-136/cargo-generate-rpm/issues/21
rustup toolchain install 1.52.0
cargo +1.52.0 install cargo-generate-rpm --version ${CARGO_GENERATE_RPM_VER} --locked
;;
esac
- name: Create the package
run: |
# Debian
# =========================================================================================
# Packages for different distributions (e.g. Stretch, Buster) of the same
# O/S (e.g. Debian) when served from a single package repository MUST have
# unique package_ver_architecture triples. Cargo deb can vary the name based
# on the 'variant' config section in use, but doesn't do so according to
# Debian policy (as it modifies the package name, not the package version).
# Format: package_ver_architecture
# Where ver has format: [epoch:]upstream_version[-debian_revision]
# And debian_version should be of the form: 1<xxx>
# Where it is common to set <xxx> to the O/S name.
# See:
# - https://unix.stackexchange.com/a/190899
# - https://www.debian.org/doc/debian-policy/ch-controlfields.html#version
# Therefore we generate the version ourselves.
#
# In addition, Semantic Versioning and Debian version policy cannot
# express a pre-release label in the same way. For example 0.8.0-rc.1
# is a valid Cargo.toml [package].version value but when used as a
# Debian package version 0.8.0-rc.1 would be considered _NEWER_ than
# the final 0.8.0 release. To express this in a Debian compatible way we
# must replace the dash '-' with a tilda '~'.
#
# RPM
# ==============================================================================================================
# Handle the release candidate case where the version string needs to have
# dash replaced by tilda. The cargo build command won't work if the version
# key in Cargo.toml contains a tilda but we have to put the tilda there for
# when we run cargo generate-rpm so that it uses it.
#
# For background on RPM versioning see:
# https://docs.fedoraproject.org/en-US/packaging-guidelines/Versioning/
#
# COMMON
# ==============================================================================================================
# Finally, sometimes we want a version to be NEWER than the latest
# release but without having to decide what higher semver number to bump
# to. In this case we do NOT want dash '-' to become '~' because `-`
# is treated as higher and tilda is treated as lower.
ROUTINATOR_VER=$(cargo read-manifest | jq -r '.version' | tr '-' '~')
PKG_ROUTINATOR_VER=$(echo $ROUTINATOR_VER | sed -e "s/~$NEXT_VER_LABEL/-$NEXT_VER_LABEL/")
case ${OS_NAME} in
debian|ubuntu)
case ${OS_REL} in
xenial|bionic|stretch) VARIANT_NAME="minimal" ;;
*) VARIANT_NAME="" ;;
esac
case ${{ github.event_name }} in
pull_request) MAINTAINER="${{ github.actor }} <unknown@email.address>" ;;
push) MAINTAINER="${{ github.event.pusher.name }} <${{ github.event.pusher.email }}>" ;;
*) echo 2>&1 "ERROR: Unexpected GitHub Actions event"; exit 1 ;;
esac
# Generate the RFC 5322 format date by hand instead of using date --rfc-email
# because that option doesn't exist on Ubuntu 16.04 and Debian 9
RFC5322_TS=$(LC_TIME=en_US.UTF-8 date +'%a, %d %b %Y %H:%M:%S %z')
# Generate the changelog file that Debian packages are required to have.
# See: https://www.debian.org/doc/manuals/maint-guide/dreq.en.html#changelog
if [ ! -d target/debian ]; then
mkdir -p target/debian
fi
echo "routinator (${PKG_ROUTINATOR_VER}) unstable; urgency=medium" >target/debian/changelog
echo " * See: https://github.com/NLnetLabs/routinator/releases/tag/v${ROUTINATOR_VER}" >>target/debian/changelog
echo " -- maintainer ${MAINTAINER} ${RFC5322_TS}" >>target/debian/changelog
DEB_VER="${PKG_ROUTINATOR_VER}-1${OS_REL}"
if [[ "${VARIANT_NAME}" == "" ]]; then
cargo deb --deb-version ${DEB_VER} -v -- --locked
else
cargo deb --deb-version ${DEB_VER} --variant ${VARIANT_NAME} -v -- --locked
fi
;;
centos)
# Build and strip Routinator as cargo generate-rpm doesn't do this for us
cargo build --release --locked
strip -s target/release/routinator
# Fix the version string to be used for the RPM package
sed -i -e "s/$ROUTINATOR_VER/$PKG_ROUTINATOR_VER/" Cargo.toml
# Select the correct systemd service unit file for the target operating system
case ${MATRIX_IMAGE} in
centos:7)
SYSTEMD_SERVICE_UNIT_FILE="routinator-minimal.routinator.service"
;;
*)
SYSTEMD_SERVICE_UNIT_FILE="routinator.routinator.service"
;;
esac
# Copy the chosen systemd service unit file to where Cargo.toml expects it to be
mkdir -p target/rpm
cp pkg/common/${SYSTEMD_SERVICE_UNIT_FILE} target/rpm/routinator.service
cargo generate-rpm
;;
esac
env:
MATRIX_IMAGE: ${{ matrix.image }}
- name: Verify the DEB package
run: |
case ${OS_NAME} in
debian|ubuntu)
lintian -v target/debian/*.deb
;;
centos)
# cargo generate-rpm creates RPMs that rpmlint considers to have
# errors so don't use the rpmlint exit code otherwise we will always
# abort the workflow.
rpmlint target/generate-rpm/*.rpm || true
;;
esac
- name: Upload package
uses: actions/upload-artifact@v2
with:
name: ${{ env.OS_NAME }}_${{ env.OS_REL }}
path: |
target/debian/*.deb
target/generate-rpm/*.rpm
pkg-test:
name: pkg-test
needs: pkg
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
image: - "ubuntu:xenial" - "ubuntu:bionic" - "ubuntu:focal" - "debian:stretch" - "debian:buster" - "debian:bullseye" - "centos:7"
- "centos:8"
mode:
- 'fresh-install'
- 'upgrade-from-published'
steps:
- name: Set vars
id: setvars
shell: bash
run: |
# Get the operating system and release name (e.g. ubuntu and xenial) from
# the image name (e.g. ubuntu:xenial) by extracting only the parts before
# and after but not including the colon:
OS_NAME=${MATRIX_IMAGE%:*}
OS_REL=${MATRIX_IMAGE#*:}
echo "OS_NAME=${OS_NAME}" >> $GITHUB_ENV
echo "OS_REL=${OS_REL}" >> $GITHUB_ENV
echo "LXC_IMAGE=images:${OS_NAME}/${OS_REL}/cloud" >> $GITHUB_ENV
env:
MATRIX_IMAGE: ${{ matrix.image }}
- name: Download package
uses: actions/download-artifact@v2
with:
name: ${{ env.OS_NAME }}_${{ env.OS_REL }}
- name: Add current user to LXD group
run: |
sudo usermod --append --groups lxd $(whoami)
- name: Initialize LXD
run: |
sudo lxd init --auto
- name: Check LXD configuration
run: |
sg lxd -c "lxc info"
- name: Disable LXD assignment of IPv6 addresses
run: |
sg lxd -c "lxc network set lxdbr0 ipv6.address none"
- name: Launch LXC container
run: |
# security.nesting=true is needed to avoid error "Failed to set up mount
# namespacing: Permission denied" in a Debian 10 container.
sg lxd -c "lxc launch ${LXC_IMAGE} -c security.nesting=true testcon"
- name: Prepare container
shell: bash
run: |
echo "Waiting for cloud-init.."
while ! sudo lxc exec testcon -- ls -la /var/lib/cloud/data/result.json; do
sleep 1s
done
case ${OS_NAME} in
debian|ubuntu)
sg lxd -c "lxc exec testcon -- apt-get update"
sg lxd -c "lxc exec testcon -- apt-get install -y -o Dpkg::Options::=\"--force-confnew\" apt-transport-https ca-certificates man sudo wget"
;;
centos)
sg lxd -c "lxc exec testcon -- yum update -y"
sg lxd -c "lxc exec testcon -- yum install -y man"
;;
esac
- name: Copy package into LXC container
run: |
case ${OS_NAME} in
debian|ubuntu)
DEB_FILE=$(ls -1 debian/*.deb)
sg lxd -c "lxc file push ${DEB_FILE} testcon/tmp/"
echo "PKG_FILE=$(basename $DEB_FILE)" >> $GITHUB_ENV
;;
centos)
RPM_FILE=$(ls -1 generate-rpm/*.rpm)
sg lxd -c "lxc file push ${RPM_FILE} testcon/tmp/"
echo "PKG_FILE=$(basename $RPM_FILE)" >> $GITHUB_ENV
;;
esac
- name: Install previously published package
if: ${{ matrix.mode == 'upgrade-from-published' }}
run: |
case ${OS_NAME} in
debian|ubuntu)
echo "deb [arch=amd64] https://packages.nlnetlabs.nl/linux/${OS_NAME}/ ${OS_REL} main" >$HOME/nlnetlabs.list
sg lxd -c "lxc file push $HOME/nlnetlabs.list testcon/etc/apt/sources.list.d/"
sg lxd -c "lxc exec testcon -- wget -q https://packages.nlnetlabs.nl/aptkey.asc"
sg lxd -c "lxc exec testcon -- apt-key add ./aptkey.asc"
sg lxd -c "lxc exec testcon -- apt update"
sg lxd -c "lxc exec testcon -- apt install -y routinator"
;;
centos)
echo '[nlnetlabs]' >$HOME/nlnetlabs.repo
echo 'name=NLnet Labs' >>$HOME/nlnetlabs.repo
echo 'baseurl=https://packages.nlnetlabs.nl/linux/centos/$releasever/main/$basearch' >>$HOME/nlnetlabs.repo
echo 'enabled=1' >>$HOME/nlnetlabs.repo
sg lxd -c "lxc file push $HOME/nlnetlabs.repo testcon/etc/yum.repos.d/"
sg lxd -c "lxc exec testcon -- rpm --import https://packages.nlnetlabs.nl/aptkey.asc"
sg lxd -c "lxc exec testcon -- yum install -y routinator"
;;
esac
- name: Install new package
if: ${{ matrix.mode == 'fresh-install' }}
run: |
case ${OS_NAME} in
debian|ubuntu)
sg lxd -c "lxc exec testcon -- apt-get -y install /tmp/${PKG_FILE}"
;;
centos)
sg lxd -c "lxc exec testcon -- yum install -y /tmp/${PKG_FILE}"
;;
esac
- name: Test installed packages
run: |
echo -e "\nROUTINATOR VERSION:"
sg lxd -c "lxc exec testcon -- routinator --version"
echo -e "\nROUTINATOR CONF:"
sg lxd -c "lxc exec testcon -- cat /etc/routinator/routinator.conf"
echo -e "\nROUTINATOR DATA DIR:"
sg lxd -c "lxc exec testcon -- ls -la /var/lib/routinator"
echo -e "\nROUTINATOR SERVICE STATUS BEFORE ENABLE:"
sg lxd -c "lxc exec testcon -- systemctl status routinator || true"
echo -e "\nINIT ROUTINATOR:"
sg lxd -c "lxc exec testcon -- sudo routinator-init --accept-arin-rpa"
echo -e "\nROUTINATOR DATA DIR AFTER INIT:"
sg lxd -c "lxc exec testcon -- ls -la /var/lib/routinator"
echo -e "\nENABLE ROUTINATOR SERVICE:"
sg lxd -c "lxc exec testcon -- systemctl enable routinator"
echo -e "\nROUTINATOR SERVICE STATUS AFTER ENABLE:"
sg lxd -c "lxc exec testcon -- systemctl status routinator || true"
echo -e "\nSTART ROUTINATOR SERVICE:"
sg lxd -c "lxc exec testcon -- systemctl start routinator"
sleep 15s
echo -e "\nROUTINATOR LOGS AFTER START:"
sg lxd -c "lxc exec testcon -- journalctl --unit=routinator"
echo -e "\nROUTINATOR SERVICE STATUS AFTER START:"
sg lxd -c "lxc exec testcon -- systemctl status routinator"
echo -e "\nROUTINATOR MAN PAGE:"
sg lxd -c "lxc exec testcon -- man -P cat routinator"
echo -e "\nROUTINATOR TALS DIR:"
sg lxd -c "lxc exec testcon -- ls -la /var/lib/routinator/tals/"
echo -e "\nROUTINATOR RPKI CACHE DIR (first 20 lines of ls output only):"
sg lxd -c "lxc exec testcon -- ls -ltR /var/lib/routinator/rpki-cache/ | head -n 20"
- name: Install new package
if: ${{ matrix.mode == 'upgrade-from-published' }}
run: |
case ${OS_NAME} in
debian|ubuntu)
sg lxd -c "lxc exec testcon -- apt-get -y install /tmp/${PKG_FILE}"
;;
centos)
sg lxd -c "lxc exec testcon -- yum install -y /tmp/${PKG_FILE}"
;;
esac
- name: Test installed packages
if: ${{ matrix.mode == 'upgrade-from-published' }}
run: |
echo -e "\nROUTINATOR VERSION:"
sg lxd -c "lxc exec testcon -- routinator --version"
echo -e "\nROUTINATOR CONF:"
sg lxd -c "lxc exec testcon -- cat /etc/routinator/routinator.conf"
echo -e "\nROUTINATOR DATA DIR:"
sg lxd -c "lxc exec testcon -- ls -la /var/lib/routinator"
echo -e "\nROUTINATOR SERVICE STATUS:"
sg lxd -c "lxc exec testcon -- systemctl status routinator || true"
echo -e "\nROUTINATOR MAN PAGE:"
sg lxd -c "lxc exec testcon -- man -P cat routinator"
echo -e "\nROUTINATOR TALS DIR:"
sg lxd -c "lxc exec testcon -- ls -la /var/lib/routinator/tals/"
echo -e "\nROUTINATOR RPKI CACHE DIR (first 20 lines of ls output only):"
sg lxd -c "lxc exec testcon -- ls -ltR /var/lib/routinator/rpki-cache/ | head -n 20"