Skip to content

Commit

Permalink
Add systemd-sysext development install mode
Browse files Browse the repository at this point in the history
Now that we don't install any suid root stuff any more and use fully
dynamic system users, we can build our git tree straight into a
systemd-sysext [1]. With that we can test all parts of cockpit
(including tls, ws, session, bridge, the login page, and systemd units)
in a safe manner on the host system. Nothing ever hits the disk (it's
installed to /run/extensions) and allows fast iteration.

This is primarily aimed at our documented development workflow of
building in a cockpit/tasks toolbox, but written in a generic way so
that it should work on Fedora, CentOS/RHEL, Debian/Ubuntu, and Arch, and
also directly from the host system. Use the "extension-release"
declaration to ensure compatibility between the build and host systems.

[1] https://www.freedesktop.org/software/systemd/man/latest/systemd-sysext.html

https://issues.redhat.com/browse/COCKPIT-1208
  • Loading branch information
martinpitt committed Nov 27, 2024
1 parent bfd622b commit dcd64c2
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 2 deletions.
33 changes: 31 additions & 2 deletions HACKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,10 +296,39 @@ During fast iterative development, you can also choose to not run stylelint, by
running `./build.js` with the `-s`/`--no-stylelint` option. This speeds up the
build and avoids build failures due to ill-formatted CSS or other issues.

## Working on your local machine: systemd-sysext

If you want to safely test your local changes directly on it, Cockpit supports
installation as a [systemd-sysext](https://www.freedesktop.org/software/systemd/man/latest/systemd-sysext.html).
This covers all parts of Cockpit (ws, tls, session, bridge, login page, systemd
units, PAM configuration, and the session pages) except for the SELinux policy.
It gets installed into `/run/extensions/`, so nothing ever hits the disk and
this also works on read-only installations (CoreOS, OSTree, bootc).

Just run:

tools/make-sysext

This runs `./autogen.sh` if necessary, and then just re-`make`s your tree,
re-installs it into `/run/extensions`, and reloads the sysext in systemd.
Afterwards you can connect to http://localhost:9090 as usual.

To remove this, reboot or run

tools/make-sysext stop

**Attention**: This is not currently compatible with SELinux in enforcing mode.
If you have that, you need to disable it:

sudo setenforce 0

## Working on your local machine: Web server

To test changes to the login page or any other resources, you can bind-mount the
build tree's `dist/static/` directory over the system one:
If the above systemd-sysext approach does not work for you, you can also test
changes with some bind mounts.

To test changes to the login page, you can bind-mount the build tree's
`dist/static/` directory over the system one:

sudo mount -o bind dist/static/ /usr/share/cockpit/static/

Expand Down
95 changes: 95 additions & 0 deletions tools/make-sysext
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/bin/sh
# This file is part of Cockpit.
#
# Copyright (C) 2024 Red Hat, Inc.
#
# Cockpit is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Cockpit is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Cockpit; If not, see <https://www.gnu.org/licenses/>.

# Build and install tree as systemd-sysext.
# See ../HACKING.MD section "Working on your local machine: systemd-sysext"

set -eu

SYSEXT_NAME="cockpit-git"
SYSEXT_DIR="/run/extensions/$SYSEXT_NAME"

build() {
rm -rf tmp/sysext
if [ ! -e Makefile ]; then
./autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --enable-strict --enable-debug --disable-dependency-tracking
fi
make install DESTDIR=tmp/sysext
install -D -m 644 $PAMFILE tmp/sysext/usr/lib/pam.d/cockpit
install -d tmp/sysext/usr/lib/extension-release.d
printf "ID=$ID\nVERSION_ID=$VERSION_ID\n" > tmp/sysext/usr/lib/extension-release.d/"extension-release.$SYSEXT_NAME"
}

stop() {
if systemctl is-active --quiet cockpit.socket; then
systemctl stop cockpit.socket
fi
if systemctl is-enabled --quiet cockpit.socket; then
systemctl disable cockpit.socket
fi
if systemd-sysext --no-legend status | grep -qw "$SYSEXT_NAME"; then
systemd-sysext unmerge
fi
if [ -d $SYSEXT_DIR ]; then
rm -rf "$SYSEXT_DIR"
fi
}

if [ "${1:-}" = root-stop ]; then
stop
exit 0
fi

if [ "${1:-}" = install ]; then
stop
mkdir -p "$(dirname $SYSEXT_DIR)"
cp -r tmp/sysext "$SYSEXT_DIR"
systemd-sysext merge

echo
systemd-sysext status --no-pager

systemctl start cockpit.socket
exit 0
fi

. /etc/os-release

case "$ID" in
# rolling release, no $VERSION_ID
arch) PAMFILE=tools/arch/cockpit.pam; VERSION_ID=latest ;;
fedora|centos|rhel) PAMFILE=tools/cockpit.pam ;;
debian|ubuntu) PAMFILE=tools/cockpit.debian.pam ;;
*) echo "Unsupported distribution: $ID"; exit 1 ;;
esac

# build mode

# call ourselves in install mode
if [ "${1:-}" = "stop" ]; then
arg="root-stop"
else
build
arg="install"
fi

if systemd-detect-virt --quiet --container; then
flatpak-spawn --host sudo -S "$0" "$arg"
else
sudo "$0" "$arg"
fi

0 comments on commit dcd64c2

Please sign in to comment.