Skip to content

Commit 6d0ea1c

Browse files
authored
Add GitHub workflows for CI and packaging (#5)
1 parent 1d275a9 commit 6d0ea1c

File tree

12 files changed

+389
-6
lines changed

12 files changed

+389
-6
lines changed

.github/workflows/ci.yml

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: ci
2+
on:
3+
push:
4+
branches:
5+
- main
6+
- master
7+
pull_request:
8+
branches:
9+
- main
10+
- master
11+
jobs:
12+
test:
13+
name: test
14+
runs-on: ${{ matrix.os }}
15+
strategy:
16+
matrix:
17+
os: [ubuntu-latest]
18+
rust: [1.84.0, stable]
19+
steps:
20+
- name: Checkout repository
21+
uses: actions/checkout@v2
22+
- name: Install Rust
23+
uses: hecrj/setup-rust-action@v2
24+
with:
25+
rust-version: ${{ matrix.rust }}
26+
- if: matrix.rust == 'stable'
27+
run: rustup component add clippy
28+
- if: matrix.rust == 'stable'
29+
run: cargo clippy -- -D warnings
30+
- run: cargo build --verbose --locked
31+
- run: cargo test --verbose

.github/workflows/pkg.yml

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Packaging
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- master
8+
tags:
9+
- v*
10+
11+
# Triggering on PRs and arbitrary branch pushes is not enabled because most of the time only the CI build should be
12+
# triggered, not the packaging build. In cases where you want to test changes to this workflow this trigger enables
13+
# you to manually invoke this workflow on an arbitrary branch as needed.
14+
workflow_dispatch:
15+
16+
jobs:
17+
package:
18+
# See: https://github.com/NLnetLabs/ploutos
19+
uses: NLnetLabs/ploutos/.github/workflows/pkg-rust.yml@v7
20+
secrets:
21+
DOCKER_HUB_ID: ${{ vars.DOCKER_HUB_ID }}
22+
DOCKER_HUB_TOKEN: ${{ secrets.DOCKER_HUB_TOKEN }}
23+
with:
24+
cross_build_args:
25+
cross_max_wait_mins: 20
26+
27+
docker_org: nlnetlabs
28+
docker_repo: rrdpit
29+
docker_build_rules: pkg/rules/docker-images-to-build.yml
30+
docker_sanity_check_command: rrdpit --version
31+
32+
package_build_rules: pkg/rules/packages-to-build.yml
33+
package_test_rules: pkg/rules/packages-to-test.yml
34+
package_test_scripts_path: pkg/test-scripts/test-<package>.sh
35+
36+
deb_extra_build_packages: libssl-dev

Cargo.lock

+6-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+43
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,46 @@ hex = "^0.3"
1919
ring = "^0.17"
2020
uuid = { version = "^0.7", features = ["v4"] }
2121
xml-rs = "0.8.25"
22+
23+
# ------------------------------------------------------------------------------
24+
# START DEBIAN PACKAGING
25+
#
26+
# Configurations for the cargo-deb cargo plugin which builds Debian packages in
27+
# target/debian/ when invoked with: cargo deb.
28+
#
29+
# TODO:
30+
# - Build packages with GH Actions
31+
# - Add man page?
32+
# - Add changelog
33+
#
34+
# NOTE:
35+
# - There is a single binary only (no daemon yet)
36+
37+
[package.metadata.deb]
38+
name = "rrdpit"
39+
priority = "optional"
40+
section = "net"
41+
extended-description-file = "pkg/debian/description.txt"
42+
license-file = ["LICENSE", "0"]
43+
depends = ""
44+
maintainer-scripts = "pkg/debian/"
45+
changelog = "target/debian/changelog" # this will be generated by the pkg workflow
46+
copyright = "Copyright (c) 2025, NLnet Labs. All rights reserved."
47+
assets = [["target/release/rrdpit", "/usr/bin/rrdpit", "755"]]
48+
49+
# List target variants
50+
[package.metadata.deb.variants.ubuntu-focal]
51+
52+
[package.metadata.deb.variants.ubuntu-jammy]
53+
54+
[package.metadata.deb.variants.ubuntu-noble]
55+
56+
[package.metadata.deb.variants.debian-buster]
57+
58+
[package.metadata.deb.variants.debian-bullseye]
59+
60+
[package.metadata.deb.variants.debian-bookworm]
61+
62+
# END DEBIAN PACKAGING
63+
# ------------------------------------------------------------------------------
64+

Dockerfile

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# This is a multi-stage Dockerfile, with a selectable first stage. With this
2+
# approach we get:
3+
#
4+
# 1. Separation of dependencies needed to build our app in the 'build' stage
5+
# and those needed to run our app in the 'final' stage, as we don't want
6+
# the build-time dependencies to be included in the final Docker image.
7+
#
8+
# 2. Support for either building our app for the architecture of the base
9+
# image using MODE=build (the default) or for externally built app
10+
# binaries (e.g. cross-compiled) using MODE=copy.
11+
#
12+
# In total there are four stages consisting of:
13+
# - Two possible first stages: 'build' or 'copy'.
14+
# - A special 'source' stage which selects either 'build' or 'copy' as the
15+
# source of binaries to be used by ...
16+
# - The 'final' stage.
17+
18+
19+
###
20+
### ARG DEFINITIONS ###########################################################
21+
###
22+
23+
# This section defines arguments that can be overriden on the command line
24+
# when invoking `docker build` using the argument form:
25+
#
26+
# `--build-arg <ARGNAME>=<ARGVALUE>`.
27+
28+
# MODE
29+
# ====
30+
# Supported values: build (default), copy
31+
#
32+
# By default this Dockerfile will build our app from sources. If the sources
33+
# have already been (cross) compiled by some external process and you wish to
34+
# use the resulting binaries from that process, then:
35+
#
36+
# 1. Create a directory on the host called 'dockerbin/$TARGETPLATFORM'
37+
# containing the already compiled app binaries (where $TARGETPLATFORM
38+
# is a special variable set by Docker BuiltKit).
39+
# 2. Supply arguments `--build-arg MODE=copy` to `docker build`.
40+
ARG MODE=build
41+
42+
43+
# BASE_IMG
44+
# ========
45+
#
46+
# Only used when MODE=build.
47+
ARG BASE_IMG=alpine:3.21
48+
49+
50+
# CARGO_ARGS
51+
# ==========
52+
#
53+
# Only used when MODE=build.
54+
#
55+
# This ARG can be used to control the features enabled when compiling the app
56+
# or other compilation settings as necessary.
57+
ARG CARGO_ARGS
58+
59+
60+
###
61+
### BUILD STAGES ##############################################################
62+
###
63+
64+
65+
# -----------------------------------------------------------------------------
66+
# Docker stage: build
67+
# -----------------------------------------------------------------------------
68+
#
69+
# Builds our app binaries from sources.
70+
FROM ${BASE_IMG} AS build
71+
ARG CARGO_ARGS
72+
73+
RUN apk add --no-cache rust cargo openssl-dev
74+
75+
WORKDIR /tmp/build
76+
COPY . .
77+
78+
# `CARGO_HTTP_MULTIPLEXING` forces Cargo to use HTTP/1.1 without pipelining
79+
# instead of HTTP/2 with multiplexing. This seems to help with various
80+
# "spurious network error" warnings when Cargo attempts to fetch from crates.io
81+
# when building this image on Docker Hub and GitHub Actions build machines.
82+
#
83+
# `cargo install` is used instead of `cargo build` because it places just the
84+
# binaries we need into a predictable output directory. We can't control this
85+
# with arguments to cargo build as `--out-dir` is unstable and contentious and
86+
# `--target-dir` still requires us to know which profile and target the
87+
# binaries were built for. By using `cargo install` we can also avoid needing
88+
# to hard-code the set of binary names to copy so that if we add or remove
89+
# built binaries in future this will "just work". Note that `--root /tmp/out`
90+
# actually causes the binaries to be placed in `/tmp/out/bin/`. `cargo install`
91+
# will create the output directory for us.
92+
RUN CARGO_HTTP_MULTIPLEXING=false cargo install \
93+
--locked \
94+
--path . \
95+
--root /tmp/out/ \
96+
${CARGO_ARGS}
97+
98+
99+
# -----------------------------------------------------------------------------
100+
# Docker stage: copy
101+
# -----------------------------------------------------------------------------
102+
# Only used when MODE=copy.
103+
#
104+
# Copy binaries from the host directory 'dockerbin/$TARGETPLATFORM' directory
105+
# into this build stage to the same predictable location that binaries would be
106+
# in if MODE were 'build'.
107+
#
108+
# Requires that `docker build` be invoked with variable `DOCKER_BUILDKIT=1` set
109+
# in the environment. This is necessary so that Docker will skip the unused
110+
# 'build' stage and so that the magic $TARGETPLATFORM ARG will be set for us.
111+
FROM ${BASE_IMG} AS copy
112+
ARG TARGETPLATFORM
113+
ONBUILD COPY dockerbin/$TARGETPLATFORM /tmp/out/bin/
114+
115+
116+
# -----------------------------------------------------------------------------
117+
# Docker stage: source
118+
# -----------------------------------------------------------------------------
119+
# This is a "magic" build stage that "labels" a chosen prior build stage as the
120+
# one that the build stage after this one should copy application binaries
121+
# from. It also causes the ONBUILD COPY command from the 'copy' stage to be run
122+
# if needed. Finally, we ensure binaries have the executable flag set because
123+
# when copied in from outside they may not have the flag set, especially if
124+
# they were uploaded as a GH actions artifact then downloaded again which
125+
# causes file permissions to be lost.
126+
# See: https://github.com/actions/upload-artifact#permission-loss
127+
FROM ${MODE} AS source
128+
RUN chmod a+x /tmp/out/bin/*
129+
130+
131+
# -----------------------------------------------------------------------------
132+
# Docker stage: final
133+
# -----------------------------------------------------------------------------
134+
# Create an image containing just the binaries, configs & scripts needed to run
135+
# our app, and not the things needed to build it.
136+
#
137+
# The previous build stage from which binaries are copied is controlled by the
138+
# MODE ARG (see above).
139+
FROM ${BASE_IMG} AS final
140+
141+
# Copy binaries from the 'source' build stage into the image we are building
142+
COPY --from=source /tmp/out/bin/* /usr/local/bin/
143+
144+
# Build variables for uid and guid of user to run container
145+
ARG RUN_USER=rrdpit
146+
ARG RUN_USER_UID=1012
147+
ARG RUN_USER_GID=1012
148+
149+
# Install required runtime dependencies
150+
RUN apk add --no-cache bash libgcc openssl tini tzdata util-linux
151+
152+
# Create the user and group to run the application as
153+
RUN addgroup -g ${RUN_USER_GID} ${RUN_USER} && \
154+
adduser -D -u ${RUN_USER_UID} -G ${RUN_USER} ${RUN_USER}
155+
156+
# Create the data directories and create a volume for them
157+
VOLUME /data
158+
RUN mkdir -p /data/source /data/target && \
159+
chown -R ${RUN_USER_UID}:${RUN_USER_GID} /data
160+
161+
# Install a Docker entrypoint script that will be executed when the container
162+
# runs
163+
COPY docker/entrypoint.sh /opt/
164+
RUN chown ${RUN_USER}: /opt/entrypoint.sh
165+
166+
# Switch to our applications user
167+
USER ${RUN_USER}
168+
169+
# Use Tini to ensure that our application responds to CTRL-C when run in the
170+
# foreground without the Docker argument "--init" (which is actually another
171+
# way of activating Tini, but cannot be enabled from inside the Docker image).
172+
ENTRYPOINT ["/sbin/tini", "--", "/opt/entrypoint.sh"]

docker/entrypoint.sh

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
# run rrdpit with variable interpolation
3+
set -e
4+
DATA="${DATA:-/data}"
5+
SOURCE_DIR="${SOURCE_DIR:-$DATA/source}"
6+
TARGET_DIR="${TARGET_DIR:-$DATA/target}"
7+
RSYNC_URI="${RSYNC_URI:-rsync://example.org/test/}"
8+
HTTPS_URI="${HTTPS_URI:-https://example.org/}"
9+
10+
exec /usr/local/bin/rrdpit \
11+
--source ${SOURCE_DIR} \
12+
--target ${TARGET_DIR} \
13+
--rsync ${RSYNC_URI} \
14+
--https ${HTTPS_URI} \
15+
"$@"

pkg/debian/description.txt

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"rrdpit" is a small little tool that can be pointed at a directory on your
2+
system, and produce RPKI RRDP (RFC 8182) notification, snapshot, and
3+
delta files. You will need to use an http server of your preferred
4+
flavour to deliver these files to the world.
5+
6+
Read more here:
7+
https://github.com/NLnetLabs/rrdpit/

pkg/debian/postinst

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/sh
2+
set -e
3+
4+
KRILL_HOME="/var/lib/rrdpit/"
5+
KRILL_USER="rrdpit"
6+
7+
create_user() {
8+
if id ${KRILL_USER} > /dev/null 2>&1; then return; fi
9+
adduser --system --home "${KRILL_HOME}" --group ${KRILL_USER}
10+
}
11+
12+
case "$1" in
13+
configure)
14+
create_user
15+
;;
16+
esac
17+
18+
#DEBHELPER#

pkg/rules/docker-images-to-build.yml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# See: https://github.com/NLnetLabs/ploutos/blob/main/docs/docker_packaging.md#docker-build-rules
2+
---
3+
include:
4+
- platform: 'linux/amd64'
5+
shortname: 'amd64'
6+
mode: 'build'
7+
8+
- platform: 'linux/arm/v6'
9+
shortname: 'armv6'
10+
crosstarget: 'arm-unknown-linux-musleabihf'
11+
mode: 'copy'
12+
13+
- platform: 'linux/arm/v7'
14+
shortname: 'armv7'
15+
crosstarget: 'armv7-unknown-linux-musleabihf'
16+
mode: 'copy'
17+
18+
- platform: 'linux/arm64'
19+
shortname: 'arm64'
20+
crosstarget: 'aarch64-unknown-linux-musl'
21+
mode: 'copy'

0 commit comments

Comments
 (0)