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

podman machine init: add a --with-foreign-arch flag #13667

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cmd/podman/machine/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ func init() {

rootfulFlagName := "rootful"
flags.BoolVar(&initOpts.Rootful, rootfulFlagName, false, "Whether this machine should prefer rootful container execution")

flags.BoolVar(
&initOpts.QemuStatic,
"with-foreign-arch", false,
Copy link
Member

Choose a reason for hiding this comment

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

I am not sure whether the naming was debated already. But other commands just use --arch (e.g., podman run), so I'd prefer to keep the naming consistent and rename it to --arch.

Copy link
Member

Choose a reason for hiding this comment

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

This is a bool and does not take a value so it would not be consistent with --arch. But I also do not like the name, maybe --emulation would fit better?

Copy link
Author

Choose a reason for hiding this comment

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

I agree it's out of step with the style in which the rest of the options are named.
I am listing below some possibilities I can think of. How do you [plural] feel about them?

  • --cross
  • --cross-arch
  • --non-native
  • --emulation
  • --emulate

FWIW, the two that start with --cross are my favourite (evocative of cross-compilation).

Incidentally, do you [plural] know off the top of your head if spf13/cobra does "unique prefix" option matching (i.e., if there's an option spelled --foobar, and no other option starts with --foo, will it accept just --foo in place of --foobar?)

"Enable running binaries from \"foreign\" CPUs (e.g., run x86_64 on Apple M1 silicon).")
}

// TODO should we allow for a users to append to the qemu cmdline?
Expand Down
7 changes: 7 additions & 0 deletions docs/source/markdown/podman-machine-init.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ so mounts must be created under the /mnt directory.

Driver to use for mounting volumes from the host, such as `virtfs`.

#### **--with-foreign-arch**

Enable running binaries compiled for "foreign" CPUs (e.g., run x86_64 binaries on
Apple M1 silicon). This option only works for Qemu machines. It works by installing
qemu-static and qemu-binfmt packages on the machine. The initialization process will
Copy link
Member

Choose a reason for hiding this comment

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

'packages on the machine.' I think you mean packages on the Qemu machine. Suggested change to remove the concern about installing it on the host machine instead.

likely take longer if this option is enabled.

## EXAMPLES

```
Expand Down
3 changes: 2 additions & 1 deletion pkg/machine/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ type InitOptions struct {
ReExec bool
Rootful bool
// The numerical userid of the user that called machine
UID string
UID string
QemuStatic bool
}

type QemuMachineStatus = string
Expand Down
53 changes: 47 additions & 6 deletions pkg/machine/ignition.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"net/url"
"os"
"path/filepath"
"regexp"

"github.com/containers/common/pkg/config"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -49,12 +50,13 @@ func getNodeGrp(grpName string) NodeGroup {
}

type DynamicIgnition struct {
Name string
Key string
TimeZone string
UID int
VMName string
WritePath string
Name string
Key string
TimeZone string
UID int
VMName string
WritePath string
QemuStatic bool
}

// NewIgnitionFile
Expand Down Expand Up @@ -184,6 +186,40 @@ ExecStartPost=/usr/bin/systemctl daemon-reload
[Install]
WantedBy=sysinit.target
`
qemuStatic := `[Unit]
Description=Layer qemu-user-static & Co with rpm-ostree
Wants=network-online.target
After=network-online.target
After=remove-moby.service
# We run before 'zincati.service' to avoid conflicting with rpm-ostree
# transactions.
Before=zincati.service
ConditionPathExists=!/var/lib/%N.stamp

[Service]
Type=oneshot
RemainAfterExit=yes
# '--allow-inactive' ensures that rpm-ostree does not return an error
# if the package is already installed. This is useful if the package is
# added to the root image in a future Fedora CoreOS release as it will
# prevent the service from failing.
ExecStart=/usr/bin/rpm-ostree install --apply-live --allow-inactive qemu qemu-user-static qemu-user-binfmt
Copy link
Member

Choose a reason for hiding this comment

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

@dustymabe what happens with ^^ when an FCOS update is downloaded and applied on a reboot?

Copy link
Author

Choose a reason for hiding this comment

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

I'll have to wait until an FCOS update is out, but my semi-educated guess is that /lib/binfmt.d will become empty following an FCOS update, so the installation will be triggered following an update, due to the Condition* clauses in the [Install] section. I can report that this does only run once for a given FCOS version, due to those same Condition* clauses (once the packages are installed /lib/binfmt.d is no longer emtpy).

Copy link
Contributor

Choose a reason for hiding this comment

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

An update should be handled without an issue. You want to make sure this only runs once. Our docs use ConditionPathExists=!/var/lib/%N.stamp and ExecStart=/bin/touch /var/lib/%N.stamp for this.

Copy link
Member

Choose a reason for hiding this comment

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

@dustymabe when this runs during boot up, does the entire boot sequence pause and wait for the install to complete? Or can the user begin interacting with the FCOS VM while the install occurs?

Copy link
Contributor

Choose a reason for hiding this comment

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

Should be able to go ahead and start interacting with the machine.

Copy link
Author

Choose a reason for hiding this comment

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

+1 I have set up FCOS VMs with a similar systemd unit "by hand", and I am able to ssh to the machine, and interact with it while the installation is running. Once I ssh to the machine, I can use systemctl status install-qemu-static.service to check on how the installation is progressing. (Obviously, I need to wait for the installation to finish before I can run "foreign" binaries).

# The 'systetmd-binfmt.service' unit _will_ do this, but it has long completed by the time this service is starting
# So just run the command to enable the extra formats right away.
ExecStart=/usr/lib/systemd/systemd-binfmt
ExecStartPost=/bin/touch /var/lib/%N.stamp

[Install]
WantedBy=multi-user.target
`

if ign.QemuStatic {
Copy link
Member

Choose a reason for hiding this comment

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

Please add a comment on what the regex is intended to do. Ideally, move it into a separate function with unit tests.

Copy link
Author

Choose a reason for hiding this comment

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

I have added a comment. I think a separate function would be overkill.

// Make the `ready` service wait until `install-qemu-static` has run to completion.
pat := regexp.MustCompile(`(?m)^(After=.*sshd\.service)$`)
r := pat.ReplaceAllString(ready, `$1 install-qemu-static.service`)
ready = r
}

_ = ready
ignSystemd := Systemd{
Units: []Unit{
Expand Down Expand Up @@ -216,6 +252,11 @@ WantedBy=sysinit.target
Name: "envset-fwcfg.service",
Contents: &envset,
},
{
Enabled: &ign.QemuStatic,
Name: "install-qemu-static.service",
Contents: &qemuStatic,
},
}}
ignConfig := Config{
Ignition: ignVersion,
Expand Down
13 changes: 7 additions & 6 deletions pkg/machine/qemu/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,12 +408,13 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
}
// Write the ignition file
ign := machine.DynamicIgnition{
Name: opts.Username,
Key: key,
VMName: v.Name,
TimeZone: opts.TimeZone,
WritePath: v.IgnitionFilePath,
UID: v.UID,
Name: opts.Username,
Key: key,
VMName: v.Name,
TimeZone: opts.TimeZone,
WritePath: v.IgnitionFilePath,
UID: v.UID,
QemuStatic: opts.QemuStatic,
}
err = machine.NewIgnitionFile(ign)
return err == nil, err
Expand Down