mirror of
https://github.com/containers/podman.git
synced 2025-07-04 10:10:32 +08:00
Add Rosetta support for Apple Silicon mac
Signed-off-by: Shion Tanaka <shtanaka@redhat.com>
This commit is contained in:
@ -74,6 +74,11 @@ func inspect(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rosetta, err := provider.GetRosetta(mc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
ii := machine.InspectInfo{
|
ii := machine.InspectInfo{
|
||||||
ConfigDir: *dirs.ConfigDir,
|
ConfigDir: *dirs.ConfigDir,
|
||||||
ConnectionInfo: machine.ConnectionConfig{
|
ConnectionInfo: machine.ConnectionConfig{
|
||||||
@ -88,6 +93,7 @@ func inspect(cmd *cobra.Command, args []string) error {
|
|||||||
State: state,
|
State: state,
|
||||||
UserModeNetworking: provider.UserModeNetworkEnabled(mc),
|
UserModeNetworking: provider.UserModeNetworkEnabled(mc),
|
||||||
Rootful: mc.HostUser.Rootful,
|
Rootful: mc.HostUser.Rootful,
|
||||||
|
Rosetta: rosetta,
|
||||||
}
|
}
|
||||||
|
|
||||||
vms = append(vms, ii)
|
vms = append(vms, ii)
|
||||||
|
@ -32,6 +32,7 @@ Print results with a Go template.
|
|||||||
| .Name | Name of the machine |
|
| .Name | Name of the machine |
|
||||||
| .Resources ... | Resources used by the machine |
|
| .Resources ... | Resources used by the machine |
|
||||||
| .Rootful | Whether the machine prefers rootful or rootless container execution |
|
| .Rootful | Whether the machine prefers rootful or rootless container execution |
|
||||||
|
| .Rosetta | Whether this machine uses Rosetta |
|
||||||
| .SSHConfig ... | SSH configuration info for communicating with machine |
|
| .SSHConfig ... | SSH configuration info for communicating with machine |
|
||||||
| .State | Machine state |
|
| .State | Machine state |
|
||||||
| .UserModeNetworking | Whether this machine uses user-mode networking |
|
| .UserModeNetworking | Whether this machine uses user-mode networking |
|
||||||
|
@ -42,6 +42,18 @@ func GetDefaultDevices(mc *vmconfigs.MachineConfig) ([]vfConfig.VirtioDevice, *d
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
devices = append(devices, disk, rng, serial, readyDevice)
|
devices = append(devices, disk, rng, serial, readyDevice)
|
||||||
|
|
||||||
|
rosettaCfg := mc.AppleHypervisor.Vfkit.Rosetta
|
||||||
|
if rosettaCfg {
|
||||||
|
rosetta := &vfConfig.RosettaShare{
|
||||||
|
DirectorySharingConfig: vfConfig.DirectorySharingConfig{
|
||||||
|
MountTag: define.MountTag,
|
||||||
|
},
|
||||||
|
InstallRosetta: true,
|
||||||
|
}
|
||||||
|
devices = append(devices, rosetta)
|
||||||
|
}
|
||||||
|
|
||||||
return devices, readySocket, nil
|
return devices, readySocket, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,4 +124,5 @@ type Helper struct {
|
|||||||
Endpoint string
|
Endpoint string
|
||||||
BinaryPath *define.VMFile
|
BinaryPath *define.VMFile
|
||||||
VirtualMachine *config.VirtualMachine
|
VirtualMachine *config.VirtualMachine
|
||||||
|
Rosetta bool
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,10 @@ package applehv
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/containers/common/pkg/config"
|
||||||
gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types"
|
gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types"
|
||||||
"github.com/containers/podman/v5/pkg/machine"
|
"github.com/containers/podman/v5/pkg/machine"
|
||||||
"github.com/containers/podman/v5/pkg/machine/apple"
|
"github.com/containers/podman/v5/pkg/machine/apple"
|
||||||
@ -65,6 +67,16 @@ func (a AppleHVStubber) CreateVM(opts define.CreateVMOpts, mc *vmconfigs.Machine
|
|||||||
}
|
}
|
||||||
ignBuilder.WithUnit(virtIOIgnitionMounts...)
|
ignBuilder.WithUnit(virtIOIgnitionMounts...)
|
||||||
|
|
||||||
|
cfg, err := config.Default()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rosetta := cfg.Machine.Rosetta
|
||||||
|
if runtime.GOARCH != "arm64" {
|
||||||
|
rosetta = false
|
||||||
|
}
|
||||||
|
mc.AppleHypervisor.Vfkit.Rosetta = rosetta
|
||||||
|
|
||||||
return apple.ResizeDisk(mc, mc.Resources.DiskSize)
|
return apple.ResizeDisk(mc, mc.Resources.DiskSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,6 +116,18 @@ func (a AppleHVStubber) StartVM(mc *vmconfigs.MachineConfig) (func() error, func
|
|||||||
return nil, nil, fmt.Errorf("unable to determine boot loader for this machine")
|
return nil, nil, fmt.Errorf("unable to determine boot loader for this machine")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg, err := config.Default()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
rosetta := cfg.Machine.Rosetta
|
||||||
|
rosettaNew := rosetta
|
||||||
|
if runtime.GOARCH == "arm64" {
|
||||||
|
rosettaMC := mc.AppleHypervisor.Vfkit.Rosetta
|
||||||
|
if rosettaMC != rosettaNew {
|
||||||
|
mc.AppleHypervisor.Vfkit.Rosetta = rosettaNew
|
||||||
|
}
|
||||||
|
}
|
||||||
return apple.StartGenericAppleVM(mc, vfkitCommand, bl, mc.AppleHypervisor.Vfkit.Endpoint)
|
return apple.StartGenericAppleVM(mc, vfkitCommand, bl, mc.AppleHypervisor.Vfkit.Endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,3 +155,8 @@ func (a AppleHVStubber) PostStartNetworking(mc *vmconfigs.MachineConfig, noInfo
|
|||||||
func (a AppleHVStubber) GetDisk(userInputPath string, dirs *define.MachineDirs, mc *vmconfigs.MachineConfig) error {
|
func (a AppleHVStubber) GetDisk(userInputPath string, dirs *define.MachineDirs, mc *vmconfigs.MachineConfig) error {
|
||||||
return diskpull.GetDisk(userInputPath, dirs, mc.ImagePath, a.VMType(), mc.Name)
|
return diskpull.GetDisk(userInputPath, dirs, mc.ImagePath, a.VMType(), mc.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *AppleHVStubber) GetRosetta(mc *vmconfigs.MachineConfig) (bool, error) {
|
||||||
|
rosetta := mc.AppleHypervisor.Vfkit.Rosetta
|
||||||
|
return rosetta, nil
|
||||||
|
}
|
||||||
|
@ -71,8 +71,9 @@ type SSHOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type StartOptions struct {
|
type StartOptions struct {
|
||||||
NoInfo bool
|
NoInfo bool
|
||||||
Quiet bool
|
Quiet bool
|
||||||
|
Rosetta bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type StopOptions struct{}
|
type StopOptions struct{}
|
||||||
@ -117,6 +118,7 @@ type InspectInfo struct {
|
|||||||
State define.Status
|
State define.Status
|
||||||
UserModeNetworking bool
|
UserModeNetworking bool
|
||||||
Rootful bool
|
Rootful bool
|
||||||
|
Rosetta bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImageConfig describes the bootable image for the VM
|
// ImageConfig describes the bootable image for the VM
|
||||||
|
@ -5,6 +5,10 @@ import "os"
|
|||||||
const UserCertsTargetPath = "/etc/containers/certs.d"
|
const UserCertsTargetPath = "/etc/containers/certs.d"
|
||||||
const DefaultIdentityName = "machine"
|
const DefaultIdentityName = "machine"
|
||||||
|
|
||||||
|
// MountTag is an identifier to mount a VirtioFS file system tag on a mount point in the VM.
|
||||||
|
// Ref: https://developer.apple.com/documentation/virtualization/running_intel_binaries_in_linux_vms_with_rosetta
|
||||||
|
const MountTag = "rosetta"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DefaultFilePerm os.FileMode = 0644
|
DefaultFilePerm os.FileMode = 0644
|
||||||
)
|
)
|
||||||
|
@ -370,6 +370,100 @@ var _ = Describe("podman machine init", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(inspectShouldPass).To(Exit(0))
|
Expect(inspectShouldPass).To(Exit(0))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("machine init with rosetta=true", func() {
|
||||||
|
skipIfVmtype(define.QemuVirt, "Test is only for AppleHv")
|
||||||
|
skipIfVmtype(define.WSLVirt, "Test is only for AppleHv")
|
||||||
|
skipIfVmtype(define.HyperVVirt, "Test is only for AppleHv")
|
||||||
|
skipIfVmtype(define.LibKrun, "Test is only for AppleHv")
|
||||||
|
if runtime.GOARCH != "arm64" {
|
||||||
|
Skip("Test is only for AppleHv with arm64 architecture")
|
||||||
|
}
|
||||||
|
|
||||||
|
i := initMachine{}
|
||||||
|
name := randomString()
|
||||||
|
session, err := mb.setName(name).setCmd(i.withImage(mb.imagePath)).run()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(session).To(Exit(0))
|
||||||
|
|
||||||
|
s := startMachine{}
|
||||||
|
ssession, err := mb.setCmd(s).setTimeout(time.Minute * 10).run()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(ssession).Should(Exit(0))
|
||||||
|
|
||||||
|
inspect := new(inspectMachine)
|
||||||
|
inspect = inspect.withFormat("{{.Rosetta}}")
|
||||||
|
inspectSession, err := mb.setName(name).setCmd(inspect).run()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(inspectSession).To(Exit(0))
|
||||||
|
Expect(inspectSession.outputToString()).To(Equal("true"))
|
||||||
|
|
||||||
|
mnt := sshMachine{}
|
||||||
|
mntSession, err := mb.setName(name).setCmd(mnt.withSSHCommand([]string{"ls -d /mnt/rosetta"})).run()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(mntSession).To(Exit(0))
|
||||||
|
Expect(mntSession.outputToString()).To(ContainSubstring("/mnt/rosetta"))
|
||||||
|
|
||||||
|
proc := sshMachine{}
|
||||||
|
procSession, err := mb.setName(name).setCmd(proc.withSSHCommand([]string{"ls -d /proc/sys/fs/binfmt_misc/rosetta"})).run()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(procSession).To(Exit(0))
|
||||||
|
Expect(procSession.outputToString()).To(ContainSubstring("/proc/sys/fs/binfmt_misc/rosetta"))
|
||||||
|
|
||||||
|
proc2 := sshMachine{}
|
||||||
|
proc2Session, err := mb.setName(name).setCmd(proc2.withSSHCommand([]string{"ls -d /proc/sys/fs/binfmt_misc/qemu-x86_64"})).run()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(proc2Session.ExitCode()).To(Equal(2))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("machine init with rosetta=false", func() {
|
||||||
|
skipIfVmtype(define.QemuVirt, "Test is only for AppleHv")
|
||||||
|
skipIfVmtype(define.WSLVirt, "Test is only for AppleHv")
|
||||||
|
skipIfVmtype(define.HyperVVirt, "Test is only for AppleHv")
|
||||||
|
skipIfVmtype(define.LibKrun, "Test is only for AppleHv")
|
||||||
|
if runtime.GOARCH != "arm64" {
|
||||||
|
Skip("Test is only for AppleHv with arm64 architecture")
|
||||||
|
}
|
||||||
|
configDir := filepath.Join(testDir, ".config", "containers")
|
||||||
|
err := os.MkdirAll(configDir, 0755)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
err = os.WriteFile(filepath.Join(configDir, "containers.conf"), rosettaConfig, 0644)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
i := initMachine{}
|
||||||
|
name := randomString()
|
||||||
|
session, err := mb.setName(name).setCmd(i.withImage(mb.imagePath)).run()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(session).To(Exit(0))
|
||||||
|
|
||||||
|
s := startMachine{}
|
||||||
|
ssession, err := mb.setCmd(s).setTimeout(time.Minute * 10).run()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(ssession).Should(Exit(0))
|
||||||
|
|
||||||
|
inspect := new(inspectMachine)
|
||||||
|
inspect = inspect.withFormat("{{.Rosetta}}")
|
||||||
|
inspectSession, err := mb.setName(name).setCmd(inspect).run()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(inspectSession).To(Exit(0))
|
||||||
|
Expect(inspectSession.outputToString()).To(Equal("false"))
|
||||||
|
|
||||||
|
mnt := sshMachine{}
|
||||||
|
mntSession, err := mb.setName(name).setCmd(mnt.withSSHCommand([]string{"ls -d /mnt/rosetta"})).run()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(mntSession.ExitCode()).To(Equal(2))
|
||||||
|
|
||||||
|
proc := sshMachine{}
|
||||||
|
procSession, err := mb.setName(name).setCmd(proc.withSSHCommand([]string{"ls -d /proc/sys/fs/binfmt_misc/rosetta"})).run()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(procSession.ExitCode()).To(Equal(2))
|
||||||
|
|
||||||
|
proc2 := sshMachine{}
|
||||||
|
proc2Session, err := mb.setName(name).setCmd(proc2.withSSHCommand([]string{"ls -d /proc/sys/fs/binfmt_misc/qemu-x86_64"})).run()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(proc2Session.outputToString()).To(ContainSubstring("/proc/sys/fs/binfmt_misc/qemu-x86_64"))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
var p4Config = []byte(`{
|
var p4Config = []byte(`{
|
||||||
@ -455,3 +549,8 @@ var p4Config = []byte(`{
|
|||||||
"LastUp": "0001-01-01T00:00:00Z"
|
"LastUp": "0001-01-01T00:00:00Z"
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
|
|
||||||
|
var rosettaConfig = []byte(`
|
||||||
|
[machine]
|
||||||
|
rosetta=false
|
||||||
|
`)
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
@ -62,7 +63,13 @@ var _ = BeforeSuite(func() {
|
|||||||
if pullError != nil {
|
if pullError != nil {
|
||||||
Fail(fmt.Sprintf("failed to pull wsl disk: %q", pullError))
|
Fail(fmt.Sprintf("failed to pull wsl disk: %q", pullError))
|
||||||
}
|
}
|
||||||
|
if testProvider.VMType() == define.AppleHvVirt {
|
||||||
|
cmd := exec.Command("softwareupdate", "--install-rosetta", "--agree-to-license")
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
Fail(fmt.Sprintf("Command failed with error: %q", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
var _ = SynchronizedAfterSuite(func() {}, func() {})
|
var _ = SynchronizedAfterSuite(func() {}, func() {})
|
||||||
|
@ -557,3 +557,7 @@ func createNetworkUnit(netPort uint64) (string, error) {
|
|||||||
netUnit.Add("Install", "WantedBy", "multi-user.target")
|
netUnit.Add("Install", "WantedBy", "multi-user.target")
|
||||||
return netUnit.ToString()
|
return netUnit.ToString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h HyperVStubber) GetRosetta(mc *vmconfigs.MachineConfig) (bool, error) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
"github.com/containers/podman/v5/pkg/machine/define"
|
"github.com/containers/podman/v5/pkg/machine/define"
|
||||||
"github.com/containers/podman/v5/pkg/systemd/parser"
|
"github.com/containers/podman/v5/pkg/systemd/parser"
|
||||||
@ -65,6 +66,7 @@ type DynamicIgnition struct {
|
|||||||
Cfg Config
|
Cfg Config
|
||||||
Rootful bool
|
Rootful bool
|
||||||
NetRecover bool
|
NetRecover bool
|
||||||
|
Rosetta bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ign *DynamicIgnition) Write() error {
|
func (ign *DynamicIgnition) Write() error {
|
||||||
@ -239,6 +241,19 @@ func (ign *DynamicIgnition) GenerateIgnitionConfig() error {
|
|||||||
ignSystemd.Units = append(ignSystemd.Units, qemuUnit)
|
ignSystemd.Units = append(ignSystemd.Units, qemuUnit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only AppleHv with Apple Silicon can use Rosetta
|
||||||
|
if ign.VMType == define.AppleHvVirt && runtime.GOARCH == "arm64" {
|
||||||
|
rosettaUnit := Systemd{
|
||||||
|
Units: []Unit{
|
||||||
|
{
|
||||||
|
Enabled: BoolToPtr(true),
|
||||||
|
Name: "rosetta-activation.service",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ignSystemd.Units = append(ignSystemd.Units, rosettaUnit.Units...)
|
||||||
|
}
|
||||||
|
|
||||||
// Only after all checks are done
|
// Only after all checks are done
|
||||||
// it's ready create the ingConfig
|
// it's ready create the ingConfig
|
||||||
ign.Cfg = Config{
|
ign.Cfg = Config{
|
||||||
|
@ -139,3 +139,7 @@ func (l LibKrunStubber) RequireExclusiveActive() bool {
|
|||||||
func (l LibKrunStubber) UpdateSSHPort(mc *vmconfigs.MachineConfig, port int) error {
|
func (l LibKrunStubber) UpdateSSHPort(mc *vmconfigs.MachineConfig, port int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l LibKrunStubber) GetRosetta(mc *vmconfigs.MachineConfig) (bool, error) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
@ -360,3 +360,7 @@ func (q *QEMUStubber) UpdateSSHPort(mc *vmconfigs.MachineConfig, port int) error
|
|||||||
func (q *QEMUStubber) GetDisk(userInputPath string, dirs *define.MachineDirs, mc *vmconfigs.MachineConfig) error {
|
func (q *QEMUStubber) GetDisk(userInputPath string, dirs *define.MachineDirs, mc *vmconfigs.MachineConfig) error {
|
||||||
return diskpull.GetDisk(userInputPath, dirs, mc.ImagePath, q.VMType(), mc.Name)
|
return diskpull.GetDisk(userInputPath, dirs, mc.ImagePath, q.VMType(), mc.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *QEMUStubber) GetRosetta(mc *vmconfigs.MachineConfig) (bool, error) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
@ -51,6 +51,8 @@ type MachineConfig struct {
|
|||||||
|
|
||||||
// Starting is defined as "on" but not fully booted
|
// Starting is defined as "on" but not fully booted
|
||||||
Starting bool
|
Starting bool
|
||||||
|
|
||||||
|
Rosetta bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type machineImage interface { //nolint:unused
|
type machineImage interface { //nolint:unused
|
||||||
@ -99,6 +101,7 @@ type VMProvider interface { //nolint:interfacebloat
|
|||||||
UseProviderNetworkSetup() bool
|
UseProviderNetworkSetup() bool
|
||||||
RequireExclusiveActive() bool
|
RequireExclusiveActive() bool
|
||||||
UpdateSSHPort(mc *MachineConfig, port int) error
|
UpdateSSHPort(mc *MachineConfig, port int) error
|
||||||
|
GetRosetta(mc *MachineConfig) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HostUser describes the host user
|
// HostUser describes the host user
|
||||||
|
@ -342,3 +342,7 @@ func (w WSLStubber) GetDisk(userInputPath string, dirs *define.MachineDirs, mc *
|
|||||||
// pull if needed and decompress to image location
|
// pull if needed and decompress to image location
|
||||||
return myDisk.Get()
|
return myDisk.Get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w WSLStubber) GetRosetta(mc *vmconfigs.MachineConfig) (bool, error) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user