Files
NetworkManager/tools/nm-in-container
Jan Vaclav a5333f14b5 nm-in-container: create conf.d file instead of modifying journald.conf
Currently, the Dockerfile expects /etc/systemd/journald.conf to exist on the base container,
but sometimes this may not be the case, for example on Fedora 40, which causes
the build process to fail if the host machine is also running Fedora 40.

Update the dockerfile to create a conf.d file instead, which has higher precedence.

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1972
2024-06-19 11:47:51 +00:00

522 lines
13 KiB
Bash
Executable File

#!/bin/bash
set -e
###############################################################################
# Script to create a podman container for testing NetworkManager.
#
# Commands:
# - build: build a new image, named "$CONTAINER_NAME_REPOSITORY:$CONTAINER_NAME_TAG" ("nm:nm").
# - run: start the container and tag it "$CONTAINER_NAME_NAME" ("nm").
# - exec: run bash inside the container (this is the default).
# - journal|j: print the journal from inside the container.
# - stop: stop the container.
# - reset: stop and delete the container.
# - clean: stop and delete the container and the image.
#
# Options:
# --no-cleanup: don't delete the CONTAINERFILE and other artifacts
# --stop: only has effect with "run". It will stop the container afterwards.
# -- [EXTRA_ARGS]:
# - with command "exec", provide a command and arguments to run in the container.
# Defaults to "bash".
# - with command "journal", additional arguments that are passed to journalctl.
#
# It bind mounts the current working directory inside the container.
# You can run `make install` and run tests.
# There is a script nm-env-prepare.sh to generate a net1 interface for testing.
#
# This will bind-mount the NetworkManager working tree inside the container (and symlink
# from /NetworkManager). Create a file ".git/nm-in-container-host" to bind mount the host's
# "/" to "/Host".
#
# Create a symlink ./.git/NetworkManager-ci, to also bind-mount the CI directory.
# Create additional symlinks ./.git/nm-guest-link-*, to bind mount additional
# directories.
#
# Currently NM-ci requires a working eth1.
# Hence call `nm-env-prepare.sh --prefix eth -i 1 && sleep 1 && nmcli device connect eth1` before
# running a CI test.
###############################################################################
if [ -z "$BASE_IMAGE" ]; then
if grep -q "^ID=fedora$" /etc/os-release 2>/dev/null ; then
BASE_IMAGE="$(sed -n 's/^VERSION_ID=\([0-9]\+\)$/fedora:\1/p' /etc/os-release)"
fi
fi
if [ -z "$BASE_IMAGE" ]; then
BASE_IMAGE=fedora:latest
fi
BASEDIR_NM="$(readlink -f "$(dirname "$(readlink -f "$0")")/..")"
BASEDIR_DATA="$BASEDIR_NM/tools/nm-guest-data"
SYMLINK_NAME=()
SYMLINK_TARGET=()
for d in $(ls -1d "$BASEDIR_NM/.git/NetworkManager-ci" "$BASEDIR_NM/.git/nm-guest-link-"* 2>/dev/null) ; do
NAME="${d##*/}"
NAME="${NAME##nm-guest-link-}"
TARGET="$(readlink -f "$d")"
test -e "$TARGET"
SYMLINK_NAME+=("$NAME")
SYMLINK_TARGET+=("$TARGET")
done
CONTAINER_NAME_REPOSITORY=${CONTAINER_NAME_REPOSITORY:-nm}
CONTAINER_NAME_TAG=${CONTAINER_NAME_TAG:-nm}
CONTAINER_NAME_NAME=${CONTAINER_NAME_NAME:-nm}
EXEC_ENV=()
###############################################################################
usage() {
cat <<EOF
$0: build|run|exec|stop|reset|reexec|clean|journal [--no-cleanup] [--stop] [-- EXTRA_ARGS]
EOF
echo
awk '/^####*$/{ if(on) exit; on=1} { if (on) { if (on==2) print(substr($0,3)); on=2; } }' "$BASH_SOURCE"
echo
}
###############################################################################
die() {
(
echo -n -e "\033[31m"
printf "%s" "$*"
echo -e "\033[0m"
) >&2
exit 1
}
###############################################################################
CLEANUP_FILES=()
DO_CLEANUP=1
cleanup() {
test "$DO_CLEANUP" = 1 || return 0
for f in "${CLEANUP_FILES[@]}" ; do
rm -rf "$f"
done
}
trap cleanup EXIT
###############################################################################
tmp_file() {
cat > "$1"
CLEANUP_FILES+=( "$1" )
test -z "$2" || chmod "$2" "$1"
}
gen_file() {
local PERMS
[[ $1 =~ bin-* ]] && PERMS=755 || PERMS=644
sed "s|{{BASEDIR_NM}}|$BASEDIR_NM|g" "$BASEDIR_DATA/$1.in" \
| tmp_file "$BASEDIR_DATA/data-$1" $PERMS
}
bind_files() {
VARIABLE_NAME="$1"
ARR=()
H=~
ARR+=( -v "$BASEDIR_NM:$BASEDIR_NM" )
if [ -e "$BASEDIR_NM/.git/nm-in-container-host" ] ; then
ARR+=( -v /:/Host )
fi
for i in $(seq 1 ${#SYMLINK_TARGET[@]}) ; do
j=$((i - 1))
ARR+=( -v "${SYMLINK_TARGET[$j]}:${SYMLINK_TARGET[$j]}" )
done
for f in ~/.gitconfig* ~/.vim* ; do
test -e "$f" || continue
f2="${f#$H/}"
[[ "$f2" = .viminf* ]] && continue
[[ "$f2" = *.tmp ]] && continue
[[ "$f2" = *~ ]] && continue
f2="/root/$f2"
ARR+=( -v "$f:$f2" )
done
eval "$VARIABLE_NAME=( \"\${ARR[@]}\" )"
}
create_dockerfile() {
local CONTAINERFILE="$1"
local BASE_IMAGE="$2"
local GEN_FILES="bin-nm-env-prepare.sh bin-nm-deploy.sh bin-_nm-in-container-setup.sh
etc-rc.local etc-motd-container etc-bashrc.my etc-bashrc-motd.my nm-90-my.conf
nm-95-user.conf home-bash_history home-gdbinit home-gdb_history home-behaverc
systemd-20-nm.override"
cp "$BASEDIR_NM/contrib/scripts/NM-log" "$BASEDIR_DATA/data-bin-NM-log"
CLEANUP_FILES+=( "$BASEDIR_DATA/data-NM-log" )
for f in $GEN_FILES; do
gen_file "$f"
done
chmod 755 "$BASEDIR_DATA/data-etc-rc.local"
RUN_LN_BASEDIR_NM=
if [ -n "$BASEDIR_NM" -a "$BASEDIR_NM" != "/NetworkManager" ] ; then
RUN_LN_BASEDIR_NM="RUN ln -snf \"$BASEDIR_NM\" /NetworkManager"
fi
RUN_LN_SYMLINK_CMDS=""
for i in $(seq 1 ${#SYMLINK_NAME[@]}) ; do
j=$((i - 1))
if [ -d "${SYMLINK_TARGET[$j]}" ] ; then
RUN_LN_SYMLINK_CMDS="$RUN_LN_SYMLINK_CMDS"$'\n'"RUN ln -snf \"${SYMLINK_TARGET[$j]}\" \"/${SYMLINK_NAME[$j]}\""
fi
done
cat <<EOF | tmp_file "$CONTAINERFILE"
FROM $BASE_IMAGE
ENTRYPOINT ["/sbin/init"]
RUN sed -i 's/^tsflags=.*/tsflags=/' /etc/dnf/dnf.conf
RUN dnf install -y \\
--skip-broken \\
\\
/usr/bin/python \\
/usr/sbin/ausearch \\
ModemManager-devel \\
ModemManager-glib-devel \\
NetworkManager \\
audit-libs-devel \\
bash-completion \\
bind-utils \\
black \\
bluez-libs-devel \\
ccache \\
clang \\
clang-tools-extra \\
cscope \\
dbus-devel \\
dbus-x11 \\
dhclient \\
dnsmasq \\
firewalld-filesystem \\
gcc-c++ \\
gdb \\
gettext-devel \\
git \\
glib2-doc \\
glibc-langpack-pl \\
gnutls-devel \\
gobject-introspection-devel \\
gtk-doc \\
intltool \\
iproute \\
iproute-tc \\
iptables \\
jansson-devel \\
libasan \\
libcurl-devel \\
libndp-devel \\
libpsl-devel \\
libselinux-devel \\
libtool \\
libubsan \\
libuuid-devel \\
make \\
meson \\
mlocate \\
mobile-broadband-provider-info-devel \\
newt-devel \\
nispor \\
nmstate \\
nss-devel \\
polkit-devel \\
ppp \\
ppp-devel \\
procps \\
python3-behave \\
python3-black \\
python3-dbus \\
python3-devel \\
python3-gobject \\
python3-pexpect \\
python3-pip \\
python3-pyte \\
python3-pyyaml \\
qt-devel \\
radvd \\
readline-devel \\
rp-pppoe \\
rpm-build \\
strace \\
systemd \\
systemd-devel \\
tcpdump \\
teamd-devel \\
vala \\
vala-devel \\
valgrind \\
vim \\
which \\
\\
'dbus*' \\
'openvswitch2*' \\
/usr/bin/pytest \\
/usr/bin/debuginfo-install \\
NetworkManager-openvpn \\
NetworkManager-pptp \\
NetworkManager-strongswan \\
NetworkManager-vpnc \\
NetworkManager-ovs \\
NetworkManager-wifi \\
NetworkManager-team \\
NetworkManager-ppp \\
cryptsetup \\
dhcp-client \\
dhcp-relay \\
dhcp-server \\
dnsmasq \\
dracut-network \\
ethtool \\
firewalld \\
gcc \\
git \\
hostapd \\
iproute-tc \\
ipsec-tools \\
iputils \\
iscsi-initiator-utils \\
iw \\
ldns \\
libreswan \\
libselinux-utils \\
libyaml-devel \\
logrotate \\
lvm2 \\
mdadm \\
net-tools \\
nfs-utils \\
nmap-ncat \\
nss-tools \\
openvpn \\
perl-IO-Pty-Easy \\
perl-IO-Tty \\
psmisc \\
python3-dbus \\
python3-gobject \\
python3-netaddr \\
qemu-kvm \\
radvd \\
rp-pppoe \\
scsi-target-utils \\
tcpdump \\
tcpreplay \\
tuned \\
wireguard-tools \\
wireshark-cli
RUN dnf debuginfo-install --skip-broken NetworkManager \$(ldd /usr/sbin/NetworkManager | sed -n 's/.* => \\(.*\\) (0x[0-9A-Fa-f]*)$/\1/p' | xargs -n1 readlink -f) -y
RUN dnf clean all
RUN pip3 install --user behave_html_formatter || true
RUN mkdir -p /etc/systemd/system/NetworkManager.service.d
COPY data-bin-NM-log "/usr/bin/NM-log"
COPY data-bin-nm-env-prepare.sh "/usr/bin/nm-env-prepare.sh"
COPY data-bin-nm-deploy.sh "/usr/bin/nm-deploy.sh"
COPY data-bin-_nm-in-container-setup.sh "/usr/bin/_nm-in-container-setup.sh"
COPY data-etc-rc.local "/etc/rc.d/rc.local"
COPY data-etc-motd-container /etc/motd
COPY data-etc-bashrc.my /etc/bashrc.my
COPY data-etc-bashrc-motd.my /etc/bashrc-motd.my
COPY data-nm-90-my.conf /etc/NetworkManager/conf.d/90-my.conf
COPY data-nm-95-user.conf /etc/NetworkManager/conf.d/95-user.conf
COPY data-home-bash_history /root/.bash_history
COPY data-home-gdbinit /root/.gdbinit
COPY data-home-gdb_history /root/.gdb_history
COPY data-home-behaverc /root/.behaverc
COPY data-systemd-20-nm.override /etc/systemd/system/NetworkManager.service.d/20-nm.override
RUN systemctl enable NetworkManager
# Generate a stable machine id.
RUN echo "10001000100010001000100010001000" > /etc/machine-id
RUN echo -e "# Default from the container image\nnameserver 8.8.8.8" > /etc/resolv.conf
# Generate a fixed (version 1) secret key.
RUN mkdir -p /var/lib/NetworkManager
RUN chmod 700 /var/lib/NetworkManager
RUN echo -n "nm-in-container-secret-key" > /var/lib/NetworkManager/secret_key
RUN chmod 600 /var/lib/NetworkManager/secret_key
RUN mkdir -p /etc/systemd/journald.conf.d/ && \
echo "RateLimitBurst=0" > /etc/systemd/journald.conf.d/no-rate-limit.conf
$RUN_LN_BASEDIR_NM
$RUN_LN_SYMLINK_CMDS
RUN rm -rf /etc/NetworkManager/system-connections/*
RUN echo -e '\n. /etc/bashrc.my\n' >> /etc/bashrc
RUN echo -e '\n. /etc/bashrc-motd.my\n' >> /etc/bashrc
RUN updatedb
EOF
}
###############################################################################
container_image_exists() {
podman image exists "$1" || return 1
}
container_exists() {
podman container exists "$1" || return 1
}
container_is_running() {
test "$(podman ps --format "{{.ID}} {{.Names}}" | sed -n "s/ $1\$/\0/p")" != "" || return 1
}
###############################################################################
do_reset() {
podman stop "$CONTAINER_NAME_NAME" || :
podman rm "$CONTAINER_NAME_NAME" || :
}
do_clean() {
do_reset
podman rmi "$CONTAINER_NAME_REPOSITORY:$CONTAINER_NAME_TAG" || :
}
do_build() {
container_image_exists "$CONTAINER_NAME_REPOSITORY:$CONTAINER_NAME_TAG" && return 0
CONTAINERFILE="$BASEDIR_DATA/containerfile"
create_dockerfile "$CONTAINERFILE" "$BASE_IMAGE"
podman build --squash-all --tag "$CONTAINER_NAME_REPOSITORY:$CONTAINER_NAME_TAG" -f "$CONTAINERFILE"
}
do_run() {
do_build
if container_is_running "$CONTAINER_NAME_NAME" ; then
return 0
fi
if container_exists "$CONTAINER_NAME_NAME" ; then
podman start "$CONTAINER_NAME_NAME"
return 0
fi
bind_files BIND_FILES
podman run --privileged \
--name "$CONTAINER_NAME_NAME" \
--dns=none \
--no-hosts \
-d \
"${BIND_FILES[@]}" \
"$CONTAINER_NAME_REPOSITORY:$CONTAINER_NAME_TAG"
}
do_exec() {
do_run
local e
local EXTRA_ARGS=("$@")
if [ "${#EXTRA_ARGS[@]}" = 0 ]; then
EXTRA_ARGS=('bash')
fi
local ENV=()
for e in "${EXEC_ENV[@]}" ; do
ENV+=(-e "$e")
done
podman exec "${ENV[@]}" --workdir "$BASEDIR_NM" -it "$CONTAINER_NAME_NAME" "${EXTRA_ARGS[@]}"
if [ "$DO_STOP" = 1 ]; then
do_stop
fi
}
do_reexec() {
do_reset
do_exec "$@"
}
do_journal() {
EXEC_ENV+=( "SYSTEMD_COLORS=0" )
do_exec "journalctl" --no-pager "$@"
}
do_stop() {
container_is_running "$CONTAINER_NAME_NAME" || return 0
podman stop "$CONTAINER_NAME_NAME"
}
###############################################################################
DO_STOP=0
CMD=exec
EXTRA_ARGS=()
for (( i=1 ; i<="$#" ; )) ; do
c="${@:$i:1}"
i=$((i+1))
case "$c" in
--no-cleanup)
DO_CLEANUP=0
;;
--stop)
DO_STOP=1
;;
j)
CMD=journal
;;
build|run|exec|stop|reset|reexec|clean|journal)
CMD=$c
;;
--)
EXTRA_ARGS=( "${@:$i}" )
break
;;
-h|--help)
usage
exit 0
;;
*)
if [ "$CMD" = "journal" ]; then
EXTRA_ARGS=( "${@:$((i-1))}" )
break;
else
usage
die "invalid argument: $c"
fi
;;
esac
done
###############################################################################
test "$UID" != 0 || die "cannot run as root"
if test "$CMD" != exec -a "$CMD" != journal -a "$CMD" != reexec -a "${#EXTRA_ARGS[@]}" != 0 ; then
die "Extra arguments are only allowed with exec|journal|reexec command"
fi
###############################################################################
do_$CMD "${EXTRA_ARGS[@]}"