-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add systemd mode for full VM experience #50
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
base: main
Are you sure you want to change the base?
Conversation
Replace shell-based init script with Go binary that supports two modes: ## Exec Mode (existing behavior) - Go init runs as PID 1 - Starts guest-agent in background - Runs container entrypoint as child process - Used for standard Docker images (nginx, python, etc.) ## Systemd Mode (new) - Auto-detected when image CMD is /sbin/init or /lib/systemd/systemd - Go init sets up rootfs, then chroots and execs systemd - Systemd becomes PID 1 and manages the full system - guest-agent runs as a systemd service (hypeman-agent.service) - Enables EC2-like experience: ssh, systemctl, journalctl all work ## Key changes: - lib/system/init/: New Go-based init binary with modular boot phases - lib/images/systemd.go: IsSystemdImage() auto-detection from CMD - lib/instances/configdisk.go: Passes INIT_MODE to guest - lib/system/init/init.sh: Shell wrapper to mount /proc /sys /dev before Go runtime (Go requires these during initialization) - integration/systemd_test.go: Full E2E test verifying: - systemd is PID 1 - hypeman-agent.service is active - journalctl works for viewing logs ## Boot flow: 1. Kernel loads initrd with busybox + Go init + guest-agent 2. init.sh mounts /proc, /sys, /dev (Go runtime needs these) 3. init.sh execs Go init binary 4. Go init mounts overlay rootfs, configures network, copies agent 5. Based on INIT_MODE: exec mode (run entrypoint) or systemd mode (chroot + exec /sbin/init)
| // - Any path ending in /init | ||
| func IsSystemdImage(entrypoint, cmd []string) bool { | ||
| // Combine to get the actual command that will run | ||
| effective := append(entrypoint, cmd...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slice append may corrupt caller's entrypoint data
The IsSystemdImage function uses append(entrypoint, cmd...) to combine slices, which is a classic Go pitfall. If the entrypoint slice has spare capacity in its backing array, append will write cmd elements directly into that capacity instead of allocating a new array. This can corrupt memory that belongs to the caller's slice. The function is called with imageInfo.Entrypoint and imageInfo.Cmd which are then reused for metadata generation. The safe pattern is append([]string(nil), entrypoint...) followed by appending cmd, which always creates a new backing array.
By default, waits up to 30 seconds for the guest agent to become ready. This prevents immediate failures when the VM is still booting. Use --wait-for-agent=0 to fail immediately (old behavior). Depends on: onkernel/hypeman#50
| @@ -0,0 +1,418 @@ | |||
| --- | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will remove before merge
| } | ||
|
|
||
| // dropToShell drops to an interactive shell for debugging when boot fails | ||
| func dropToShell() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure if this is actually useful... opus tooks some liberties
|
|
||
|
|
||
|
|
||
| ``` No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plan document should be removed before merge
This planning document was explicitly marked for removal in the PR discussion with "@rgarcia: 'will remove before merge'". The .cursor/plans/ directory containing development planning notes is being committed to the repository but isn't in .gitignore. This file contains internal development documentation and TODO tracking that shouldn't be part of the production codebase.
Summary
This PR adds support for running systemd-based OCI images, enabling a VM experience where systemd is PID 1 and manages the full system.
Motivation
Previously, hypeman only supported "exec mode" where the Go init binary runs as PID 1 and executes the container entrypoint directly. This works great for Docker-style single-process containers, but doesn't support images designed to run a full init system.
With this change, you can now run images like
jrei/systemd-ubuntu:22.04and get a full Linux system experience:systemctlworksjournalctlworksHow it works
Auto-detection
The mode is auto-detected from the image's CMD:
/sbin/init,/lib/systemd/systemd, or similar → systemd modeBoot Flow
Guest Agent
In systemd mode, the guest-agent is installed as a systemd service (
hypeman-agent.service) that starts automatically. This enableshypeman exec,hypeman cp, and other remote operations.Key Changes
lib/system/init/*.golib/system/init/init.shlib/images/systemd.goIsSystemdImage()auto-detection from CMDlib/instances/configdisk.goINIT_MODEto guest via config diskintegration/systemd_test.goTesting
The test:
jrei/systemd-ubuntu:22.04IsSystemdImage()detects it correctlysystemd/opt/hypeman/guest-agentexistshypeman-agent.serviceis activejournalctl -u hypeman-agentworksDemo
Note
Enables full systemd VMs while preserving existing exec mode, and replaces the shell init with a modular Go init embedded in initrd.
lib/system/init/*Go init (mounts, config, network, GPU, volumes) withmode_execandmode_systemd(injectshypeman-agent.service, chroot, exec/sbin/init)images.IsSystemdImage();configdisk.gowritesINIT_MODEaccordinglyinit.binandinit.shwrapper; updates staleness hash; Makefile builds and embedsguest-agentandinitwait_for_agent(seconds) inExecRequest; guest client adds retryable vsock dial andWaitForAgentoptionintegration/systemd_test.go, unit tests for detection, updated exec tests/log assertions; docs updated inlib/system/README.mdWritten by Cursor Bugbot for commit d79a403. This will update automatically on new commits. Configure here.