Skip to content

Commit

Permalink
vm: add support for macOS Virtualization.Framework (#504)
Browse files Browse the repository at this point in the history
* vm: add support for virtualization.framework

* vm: add support for Rosetta on m1 devices

* vm: manually enable rosetta, fixes #494

* vm: enable reachable address for VZ driver

* vm: disable qemu when rosetta is enabled

* vm: fix dns error for ip address

* misc: minor refactor - network address

* cli: add vm driver to status command

* vm: fix default mount type for qemu driver

* chore: rename driver to vmType in config

* k3s: update to v1.25.4+k3s1

* cli: fix broken flag due to refactor
ci: use Go version 1.19

* cli: fix broken flag due to refactor

* ci: use go 1.19 and macOS 12
  • Loading branch information
abiosoft authored Dec 13, 2022
1 parent 1c742bc commit 40bf7bf
Show file tree
Hide file tree
Showing 20 changed files with 217 additions and 986 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.19

- name: Build
run: go build -v ./...
Expand All @@ -41,7 +41,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.19

- name: generate macOS binaries
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/golang-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.19
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
Expand Down
24 changes: 12 additions & 12 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ on:
- "**/*.lock"
jobs:
kubernetes-docker:
runs-on: macos-11
runs-on: macos-12
steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.19

- name: Install CLI deps
run: |
Expand All @@ -45,14 +45,14 @@ jobs:
run: colima delete -f

kubernetes-containerd:
runs-on: macos-11
runs-on: macos-12
steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.19

- name: Install CLI deps
run: |
Expand All @@ -74,14 +74,14 @@ jobs:
run: colima delete -f

docker:
runs-on: macos-11
runs-on: macos-12
steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.19

- name: Install CLI deps
run: |
Expand Down Expand Up @@ -124,14 +124,14 @@ jobs:
run: colima delete -f

docker-aarch64:
runs-on: macos-11
runs-on: macos-12
steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.19

- name: Install CLI deps
run: |
Expand Down Expand Up @@ -174,14 +174,14 @@ jobs:
run: colima delete -f

containerd:
runs-on: macos-11
runs-on: macos-12
steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.19

- name: Install CLI deps
run: |
Expand Down Expand Up @@ -221,14 +221,14 @@ jobs:
run: colima delete -f

containerd-aarch64:
runs-on: macos-11
runs-on: macos-12
steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.19

- name: Install CLI deps
run: |
Expand Down
10 changes: 8 additions & 2 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,10 +306,16 @@ func (c colimaApp) Status() error {
return err
}

log.Println(config.CurrentProfile().DisplayName, "is running")
driver := "QEMU"
conf, _ := limautil.InstanceConfig()
if !conf.Empty() {
driver = conf.DriverLabel()
}

log.Println(config.CurrentProfile().DisplayName, "is running using", driver)
log.Println("arch:", c.guest.Arch())
log.Println("runtime:", currentRuntime)
if conf, err := limautil.InstanceConfig(); err == nil {
if conf.MountType != "" {
log.Println("mountType:", conf.MountType)
}

Expand Down
93 changes: 1 addition & 92 deletions cmd/colima/main.go
Original file line number Diff line number Diff line change
@@ -1,104 +1,13 @@
package main

import (
"fmt"
"net"
"os"
"os/exec"
"path/filepath"
"strconv"

_ "github.com/abiosoft/colima/cmd" // for other commands
_ "github.com/abiosoft/colima/cmd/daemon" // for vmnet daemon
_ "github.com/abiosoft/colima/embedded" // for embedded assets

"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/daemon/process/gvproxy"
"github.com/abiosoft/colima/daemon/process/vmnet"
"github.com/sirupsen/logrus"
)

func main() {
_, cmd := filepath.Split(os.Args[0])
switch cmd {
case "qemu-system-x86_64", "qemu-system-aarch64":
qemuWrapper(cmd)
default:
root.Execute()
}
}

func qemuWrapper(qemu string) {
if profile := os.Getenv(config.SubprocessProfileEnvVar); profile != "" {
config.SetProfile(profile)
}

gvproxyInfo := gvproxy.Info()
vmnetInfo := vmnet.Info()

// check if qemu is meant to run by lima
// decided by -pidfile flag
qemuRunning := false
for _, arg := range os.Args {
if arg == "-pidfile" {
qemuRunning = true
break
}
}

args := os.Args[1:] // forward all args
var extraFiles []*os.File

gvproxyEnabled, _ := strconv.ParseBool(os.Getenv(gvproxy.SubProcessEnvVar))
vmnetEnabled, _ := strconv.ParseBool(os.Getenv(vmnet.SubProcessEnvVar))

if qemuRunning && gvproxyEnabled {
// vmnet should come first as it would be added by Lima and would have the fd 3

// vmnet
if vmnetEnabled {
fd := os.NewFile(3, vmnetInfo.Socket.File())
extraFiles = append(extraFiles, fd)
}

// gvproxy
{
conn, err := net.Dial("unix", gvproxyInfo.Socket.File())
if err != nil {
logrus.Fatal(fmt.Errorf("error connecting to gvproxy socket: %w", err))
}
fd, err := conn.(*net.UnixConn).File()
if err != nil {
logrus.Fatal(fmt.Errorf("error retrieving fd for gvproxy socket: %w", err))
}
extraFiles = append(extraFiles, fd)
}

// gvproxy fd
fd := strconv.Itoa(2 + len(extraFiles))
args = append(args,
"-netdev", "socket,id=vlan,fd="+fd,
"-device", "virtio-net-pci,netdev=vlan,mac="+gvproxyInfo.MacAddress,
)
}

cmd := exec.Command(qemu, args...)

cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin

if len(extraFiles) > 0 {
cmd.ExtraFiles = append(cmd.ExtraFiles, extraFiles...)
}

err := cmd.Run()
if err != nil {
if err, ok := err.(*exec.ExitError); ok {
os.Exit(err.ExitCode())
}
os.Exit(1)
}

root.Execute()
}
9 changes: 2 additions & 7 deletions cmd/daemon/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import (
"context"
"time"

"github.com/abiosoft/colima/daemon/process"
"github.com/abiosoft/colima/daemon/process/gvproxy"
"github.com/abiosoft/colima/daemon/process/vmnet"

"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/daemon/process"
"github.com/abiosoft/colima/daemon/process/vmnet"
"github.com/spf13/cobra"
)

Expand All @@ -33,9 +31,6 @@ var startCmd = &cobra.Command{
if daemonArgs.vmnet {
processes = append(processes, vmnet.New())
}
if daemonArgs.gvproxy {
processes = append(processes, gvproxy.New())
}

return start(ctx, processes)
},
Expand Down
35 changes: 25 additions & 10 deletions cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/config/configmanager"
"github.com/abiosoft/colima/daemon/process/gvproxy"
"github.com/abiosoft/colima/embedded"
"github.com/abiosoft/colima/environment"
"github.com/abiosoft/colima/environment/container/docker"
Expand Down Expand Up @@ -94,8 +93,6 @@ const (
defaultMemory = 2
defaultDisk = 60
defaultKubernetesVersion = kubernetes.DefaultVersion
defaultMountType = "sshfs"
defaultNetworkDriver = gvproxy.Name
)

var defaultKubernetesDisable = []string{"traefik"}
Expand All @@ -114,8 +111,17 @@ var startCmdArgs struct {

func init() {
runtimes := strings.Join(environment.ContainerRuntimes(), ", ")
networkDrivers := strings.Join([]string{"slirp", gvproxy.Name}, ", ")
defaultArch := string(environment.HostArch().Value())
defaultArch := string(environment.HostArch())

defaultMountType := "9p"
defaultVMType := "qemu"
if util.MacOS13() {
defaultVMType = "vz"
defaultMountType = "virtiofs"
}

mounts := strings.Join([]string{defaultMountType, "sshfs"}, ", ")
types := strings.Join([]string{defaultVMType, "qemu"}, ", ")

root.Cmd().AddCommand(startCmd)
startCmd.Flags().StringVarP(&startCmdArgs.Runtime, "runtime", "r", docker.Name, "container runtime ("+runtimes+")")
Expand All @@ -128,17 +134,19 @@ func init() {

// network
if util.MacOS() {
startCmd.Flags().StringVar(&startCmdArgs.Network.Driver, "network-driver", defaultNetworkDriver, "network driver to use ("+networkDrivers+")")
startCmd.Flags().BoolVar(&startCmdArgs.Network.Address, "network-address", false, "assign reachable IP address to the VM")
}
if util.MacOS13() {
startCmd.Flags().StringVarP(&startCmdArgs.VMType, "vm-type", "t", defaultVMType, "virtual machine type ("+types+")")
}

// config
startCmd.Flags().BoolVarP(&startCmdArgs.Flags.Edit, "edit", "e", false, "edit the configuration file before starting")
startCmd.Flags().StringVar(&startCmdArgs.Flags.Editor, "editor", "", `editor to use for edit e.g. vim, nano, code (default "$EDITOR" env var)`)

// mounts
startCmd.Flags().StringSliceVarP(&startCmdArgs.Flags.Mounts, "mount", "V", nil, "directories to mount, suffix ':w' for writable")
startCmd.Flags().StringVar(&startCmdArgs.MountType, "mount-type", defaultMountType, "volume driver for the mount (sshfs, 9p)")
startCmd.Flags().StringVar(&startCmdArgs.MountType, "mount-type", defaultMountType, "volume driver for the mount ("+mounts+")")

// ssh agent
startCmd.Flags().BoolVarP(&startCmdArgs.ForwardAgent, "ssh-agent", "s", false, "forward SSH agent to the VM")
Expand Down Expand Up @@ -204,6 +212,11 @@ func prepareConfig(cmd *cobra.Command) {
startCmdArgs.Mounts = mountsFromFlag(startCmdArgs.Flags.Mounts)
startCmdArgs.ActivateRuntime = &startCmdArgs.Flags.ActivateRuntime

// convert mount type for qemu
if startCmdArgs.VMType != "vz" && startCmdArgs.MountType == "virtiofs" {
startCmdArgs.MountType = "9p"
}

// if there is no existing settings
if current.Empty() {
// attempt template
Expand Down Expand Up @@ -276,12 +289,14 @@ func prepareConfig(cmd *cobra.Command) {
}
}
if util.MacOS() {
if !cmd.Flag("network-driver").Changed {
startCmdArgs.Network.Driver = current.Network.Driver
}
if !cmd.Flag("network-address").Changed {
startCmdArgs.Network.Address = current.Network.Address
}
if util.MacOS13() {
if !cmd.Flag("vm-type").Changed {
startCmdArgs.VMType = current.VMType
}
}
}
}

Expand Down
11 changes: 10 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ type Config struct {
Network Network `yaml:"network,omitempty"`
Env map[string]string `yaml:"env,omitempty"` // environment variables

// VM VMType
VMType string `yaml:"vmType,omitempty"`

// volume mounts
Mounts []Mount `yaml:"mounts,omitempty"`
MountType string `yaml:"mountType,omitempty"`
Expand Down Expand Up @@ -114,7 +117,6 @@ type Kubernetes struct {
type Network struct {
Address bool `yaml:"address"`
DNS []net.IP `yaml:"dns"`
Driver string `yaml:"driver"`
}

// Mount is volume mount
Expand Down Expand Up @@ -155,3 +157,10 @@ func (c Config) Empty() bool { return c.Runtime == "" } // this may be better bu
func CtxKey() any {
return struct{ name string }{name: "colima_config"}
}

func (c Config) DriverLabel() string {
if util.MacOS13() && c.VMType == "vz" {
return "macOS Virtualization.Framework"
}
return "QEMU"
}
Loading

0 comments on commit 40bf7bf

Please sign in to comment.