Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

machine_core: Add Machine nspawn clone API #6974

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft

Conversation

martinpitt
Copy link
Member

@martinpitt martinpitt commented Oct 10, 2024

There are tests which require two independent machines in terms of networking, services, packages, and file systems -- this can cover e.g. the shell's host switching, or cockpit-machine's VM migration or remote terminal functionality.

Previously we used destructive tests with provisioning multiple VMs; but this is expensive and prevents us from running these tests in tmt. But for the above tests which don't require kernel modules/functionality, we would be quite happy with the auxiliary machines being a container.

systemd-nspawn supports booting its own parent OS/file system with a transient overlay. Wrap that functionality into a convenient Machine.clone_container() API which returns a new Machine (NspawnMachine subclass) with the usual methods. Teach SSHConnection about a jump host (using ProxyCommand) to directly connect from the outside test to the inner nspawn container.

This first version only supports one cloned container at a time. Supporting multiple would be nice, but requires some reengineering of the SSHConnection master.


I tested this locally, and also sent a Cockpit PR to exercise this: cockpit-project/cockpit#21105

@martinpitt
Copy link
Member Author

martinpitt commented Oct 10, 2024

So there are several problems with this -- RHEL does not have networkd, and many/most OSes don't have a snapshot-capable file system, e.g. debian-stable. There, systemd-nspawn --ephemeral basically copies the entire file system and kills the VM. So we can't use that, but have to do something with --overlay, --volatile, etc. However,

# systemd-nspawn --machine=cockpit1 --volatile=overlay --network-veth --directory=/ --boot --bind /home
Spawning container on root directory is not supported. Consider using --ephemeral, --volatile=yes or --volatile=state.

--volatile=yes isn't supported properly by Debian (or any distro to date really), and state doesn't work either. The documentation of --overlay also says that this isn't supported with full OS.

On debian-stable I've had some success with creating overlay delta directories and doing

mkdir -p /tmp/overlay/{etc,var,usr}
systemd-nspawn --machine=cockpit1 --volatile=yes --network-veth --directory=/ --boot --bind /home --overlay /var:/tmp/overlay/var:/var --overlay /etc:/tmp/overlay/etc:/etc --overlay /usr:/tmp/overlay/usr:/usr

However, machinectl list shows the wrong IP. machinectl shell cockpit1 /bin/ip --json a show dev host0 works though.

There are tests which require two independent machines in terms of
networking, services, packages, and file systems -- this can cover e.g.
the shell's host switching, or cockpit-machine's VM migration or remote
terminal functionality.

Previously we used destructive tests with `provision`ing multiple VMs;
but this is expensive and prevents us from running these tests in tmt.
But for the above tests which don't require kernel
modules/functionality, we would be quite happy with the auxiliary
machines being a container.

Use systemd-nspawn to boot its own parent OS/file system with transient
overlays. Unfortunately we can't use the convenient `--ephemeral`: that
makes a snapshot of the entire fs, which only works efficiently on
btrfs. But we can use `--volatile` and set up a bunch of overlays
ourselves.

Wrap that functionality into a convenient `Machine.clone_container()`
API which returns a new Machine (NspawnMachine subclass) with the usual
methods. Teach `SSHConnection` about a jump host (using `ProxyCommand`)
to directly connect from the outside test to the inner nspawn container.

This first version only supports one cloned container at a time.
Supporting multiple would be nice, but requires some reengineering of
the SSHConnection master.
@martinpitt
Copy link
Member Author

Next step -- more legwork with manual overlays, which should work fine on ext4 now. I triggered another round of testing. Remaining big issue is that neither RHEL nor CoreOS have systemd-networkd, which makes configuring the inner and outer veth awkward. Need to find a way to do this with NM or other tools.

parent.execute(f"until timeout 1 nc -z {address} 22; do sleep 1; done")

super().__init__(
address, parent.image, verbose, parent.label + "-" + label,
Copy link
Member

@mvollmer mvollmer Oct 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like self.verbose and maybe others should be initialized earlier, in case the code above throws an error.

@martinpitt
Copy link
Member Author

FTR: I played around with --port, but that is completely not working. It doesn't redirect on localhost (systemd/systemd#6106), and on the public IP it redirects the host's port 22, instead of the container's. I asked in that issue, but I'm afraid this isn't practical right now.

@martinpitt
Copy link
Member Author

Some more ideas:

  • Unfortunately ssh still cannot connect to a Unix socket. But we could play some tricks with socat to forward container port 22 to a host port via stdin/out or a unix socket?
  • Re-attempt to set up the veth pair manually with ip and a static IP, and figure out why the guest OS removes the IP. NM shouldn't touch veths.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants