containers/ws: Enable beibooting and install standard cockpit pages

This provides similar functionality as the Client, so that the ws
bastion container can connect to machines which don't have any Cockpit
packages installed.

Install cockpit-system and cockpit-networkmanager into the container
(we'll likely expand this in the future, but let's start small). Take
care to only unpack the RPMs, to avoid installing e.g. NetworkManager
and other big dependencies into the container -- they are useless there.

Update the documentation accordingly. While at it, add an introduction
paragraph what Cockpit is.

https://issues.redhat.com/browse/COCKPIT-954
This commit is contained in:
Martin Pitt 2023-08-28 12:21:49 +02:00 committed by Martin Pitt
parent dc2085e951
commit ab36148467
5 changed files with 76 additions and 29 deletions

View file

@ -1,25 +1,37 @@
# Cockpit on Fedora CoreOS or other container hosts
# Cockpit webserver container
The standard Fedora and Red Hat Enterprise Linux CoreOS images does not contain
Cockpit packages.
[Cockpit](https://cockpit-project.org/) is a web-based graphical interface for Linux servers.
It is [packaged in most major Linux distributions](https://cockpit-project.org/running.html).
1. Install Cockpit packages as overlay RPMs:
```
rpm-ostree install cockpit-system cockpit-ostree cockpit-podman
```
This container image provides Cockpit's web server and a subset of available pages (like the cockpit-system package)
for deployment on container hosts such as Fedora CoreOS or Kubernetes, where installing rpms is difficult or impossible.
Depending on your configuration, you may want to use
[other extensions](https://apps.fedoraproject.org/packages/s/cockpit-) as
well, such as `cockpit-kdump` or `cockpit-networkmanager`.
## Usage on container host distributions
If you have a custom-built OSTree, simply include the same packages in your build.
The standard Fedora and Red Hat Enterprise Linux CoreOS images do not contain Cockpit packages. The
`cockpit/ws` container includes a minimal set of builtin Cockpit pages which are being used when connecting to
such a machine, i.e. a host which doesn't have the `cockpit-bridge` package installed.
2. Reboot
If these builtin pages are not enough for your use cases, you can install desired Cockpit packages
as overlay RPMs. For example:
Steps 1 and 2 are enough when the CoreOS machine is only connected to through another host running Cockpit.
```
rpm-ostree install cockpit-system cockpit-ostree cockpit-podman
reboot
```
If you want to also run a web server to log in directly on the CoreOS host, you
can use this container in two modes.
Depending on your configuration, you may want to use
[other extensions](https://packages.fedoraproject.org/search?query=cockpit-) as
well, such as `cockpit-podman` or `cockpit-networkmanager`.
If you have a custom-built OSTree, simply include the same packages in your build.
These packages are enough when the CoreOS machine is only connected to through another host running Cockpit.
You also need to run a Cockpit web server somewhere, as the "entry point" for browsers. That can
then connect to the local host or any remote machine via ssh to get a Cockpit UI for that machine.
This web server can be deployed as container. It has two modes, which are described below.
## Privileged ws container

View file

@ -188,9 +188,7 @@ def main(args):
{"password": "denied"})
return
# for the time being, we only support running an installed cockpit-bridge on the remote,
# and leave beibooting to the flatpak
os.execlpe("python3", "python3", "-m", "cockpit.beiboot", "--remote-bridge=always", host, os.environ)
os.execlpe("python3", "python3", "-m", "cockpit.beiboot", host, os.environ)
if __name__ == '__main__':

View file

@ -3,18 +3,33 @@
set -ex
OSVER=$(. /etc/os-release && echo "$VERSION_ID")
INSTALLROOT=/build
INSTALL="dnf install -y --installroot=$INSTALLROOT --releasever=$OSVER --setopt=install_weak_deps=False"
INSTALL="dnf install -y --installroot=/build --releasever=$OSVER --setopt=install_weak_deps=False"
dnf install -y 'dnf-command(download)' cpio
$INSTALL coreutils-single util-linux-core sed sscg python3 openssh-clients
arch=`uname -p`
rpm=$(ls /container/rpms/cockpit-ws-*$OSVER.*$arch.rpm /container/rpms/cockpit-bridge-*$OSVER.*$arch.rpm || true)
unpack() {
rpm2cpio "$1" | cpio -i --make-directories --directory=$INSTALLROOT
}
# If there are rpm files in the current directory we'll install those
# -system and -networkmanager are only for beibooting; don't install their dependencies
if [ -n "$rpm" ]; then
$INSTALL /container/rpms/cockpit-ws-*$OSVER.*$arch.rpm /container/rpms/cockpit-bridge-*$OSVER.*$arch.rpm
for rpm in /container/rpms/cockpit-system-*$OSVER.*$arch.rpm \
/container/rpms/cockpit-networkmanager-*$OSVER.*$arch.rpm; do
unpack $rpm
done
else
$INSTALL cockpit-ws cockpit-bridge
dnf download cockpit-networkmanager cockpit-system
for rpm in cockpit-networkmanager*.rpm cockpit-system*.rpm; do
unpack $rpm
done
fi
rm -rf /build/var/cache/dnf /build/var/lib/dnf /build/var/lib/rpm* /build/var/log/*

View file

@ -1,15 +1,19 @@
#!/bin/sh
set -eu
# install/upgrade RPMs that apply to OSTree
# Note: cockpit-selinux would be desirable, but needs setroubleshoot-server which isn't installed
cd /var/tmp/
# install/upgrade RPMs that apply to OSTree
# Note: cockpit-selinux would be desirable, but needs setroubleshoot-server which isn't installed
rpm-ostree install --cache-only cockpit-bridge-*.rpm \
cockpit-networkmanager-*.rpm cockpit-system-*.rpm cockpit-tests-*.rpm
# update cockpit-ws and install scripts in the container
for rpm in /var/tmp/cockpit-ws-*.rpm /var/tmp/cockpit-bridge-*.rpm; do
# update cockpit packages and install scripts in the container
for rpm in /var/tmp/cockpit-ws-*.rpm \
/var/tmp/cockpit-bridge-*.rpm \
/var/tmp/cockpit-networkmanager-*.rpm \
/var/tmp/cockpit-system-*.rpm \
/var/tmp/cockpit-tests-*.rpm; do
rpm2cpio "$rpm" | cpio -i --make-directories --directory=/var/tmp/install
done
podman run --name build-cockpit -i \

View file

@ -70,21 +70,27 @@ class TestWsBastionContainer(testlib.MachineCase):
b.wait_visible('#content')
b.wait_text('#current-username', 'admin')
# runs the ssh target's bridge (no beiboot)
m.execute("pgrep -f /usr/bin/[c]ockpit-bridge")
b.logout()
# remembers the last host via URL, server field should be pre-filled
self.assertEqual(b.eval_js("window.location.pathname"), f"/={HOST}/system")
# FIXME: login page does not really set this in the DOM? DOM has empty value, but browser shows the value
# b.wait_text("#server-field", host)
# this is only for Cockpit Client
b.wait_not_visible("#recent-hosts")
b.set_val("#login-user-input", "admin")
b.set_val("#login-password-input", "foobar")
# second time SSH key is known
b.click("#login-button")
b.try_login()
b.wait_visible('#content')
b.logout()
# disable target bridge, should use beiboot
m.execute("mount -o bind /dev/null /usr/bin/cockpit-bridge")
self.addCleanup(m.execute, "umount /usr/bin/cockpit-bridge")
b.try_login()
b.wait_visible('#content')
m.execute("pgrep -f '[p]ython3 -ic # cockpit-bridge'")
b.logout()
def testKnownHosts(self):
m = self.machine
b = self.browser
@ -203,6 +209,8 @@ class TestWsBastionContainer(testlib.MachineCase):
b.set_val("#login-password-input", KEY_PASSWORD)
b.click("#login-button")
b.wait_visible('#content')
# runs the ssh target's bridge (no beiboot)
m.execute("pgrep -f /usr/bin/[c]ockpit-bridge")
b.logout()
# now test with current OpenSSH format
@ -213,8 +221,18 @@ class TestWsBastionContainer(testlib.MachineCase):
b.set_val("#login-password-input", KEY_PASSWORD)
b.click("#login-button")
b.wait_visible('#content')
b.logout()
# disable target bridge, should use beiboot
m.execute("mount -o bind /dev/null /usr/bin/cockpit-bridge")
try:
b.try_login(password=KEY_PASSWORD)
b.wait_visible('#content')
m.execute("pgrep -f '[p]ython3 -ic # cockpit-bridge'")
finally:
m.execute("umount /usr/bin/cockpit-bridge")
b.logout()
m.execute("podman rm -f -t0 cockpit-bastion")
m.execute("rm /home/admin/.ssh/authorized_keys")