mirror of https://github.com/linka-cloud/d2vm.git
124 lines
3.2 KiB
Go
124 lines
3.2 KiB
Go
package run
|
|
|
|
import (
|
|
"os"
|
|
"runtime"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/spf13/cobra"
|
|
|
|
"go.linka.cloud/d2vm/pkg/qemu"
|
|
)
|
|
|
|
const (
|
|
qemuNetworkingNone string = "none"
|
|
qemuNetworkingUser = "user"
|
|
qemuNetworkingTap = "tap"
|
|
qemuNetworkingBridge = "bridge"
|
|
qemuNetworkingDefault = qemuNetworkingUser
|
|
)
|
|
|
|
var (
|
|
defaultArch string
|
|
defaultAccel string
|
|
enableGUI bool
|
|
disks Disks
|
|
data string
|
|
accel string
|
|
arch string
|
|
cpus uint
|
|
mem uint
|
|
qemuCmd string
|
|
qemuDetached bool
|
|
networking string
|
|
publishFlags MultipleFlag
|
|
|
|
QemuCmd = &cobra.Command{
|
|
Use: "qemu [options] [image-path]",
|
|
Short: "Run the virtual machine image with qemu",
|
|
Args: cobra.ExactArgs(1),
|
|
Run: Qemu,
|
|
}
|
|
)
|
|
|
|
func init() {
|
|
switch runtime.GOARCH {
|
|
case "arm64":
|
|
defaultArch = "aarch64"
|
|
case "amd64":
|
|
defaultArch = "x86_64"
|
|
case "s390x":
|
|
defaultArch = "s390x"
|
|
}
|
|
switch {
|
|
case runtime.GOARCH == "s390x":
|
|
defaultAccel = "kvm"
|
|
case haveKVM():
|
|
defaultAccel = "kvm:tcg"
|
|
case runtime.GOOS == "darwin":
|
|
defaultAccel = "hvf:tcg"
|
|
}
|
|
flags := QemuCmd.Flags()
|
|
|
|
flags.BoolVar(&enableGUI, "gui", false, "Set qemu to use video output instead of stdio")
|
|
|
|
// Paths and settings for disks
|
|
flags.Var(&disks, "disk", "Disk config, may be repeated. [file=]path[,size=1G][,format=qcow2]")
|
|
|
|
// VM configuration
|
|
flags.StringVar(&accel, "accel", defaultAccel, "Choose acceleration mode. Use 'tcg' to disable it.")
|
|
flags.StringVar(&arch, "arch", defaultArch, "Type of architecture to use, e.g. x86_64, aarch64, s390x")
|
|
flags.UintVar(&cpus, "cpus", 1, "Number of CPUs")
|
|
flags.UintVar(&mem, "mem", 1024, "Amount of memory in MB")
|
|
|
|
// Backend configuration
|
|
flags.StringVar(&qemuCmd, "qemu", "", "Path to the qemu binary (otherwise look in $PATH)")
|
|
flags.BoolVar(&qemuDetached, "detached", false, "Set qemu container to run in the background")
|
|
|
|
// Networking
|
|
flags.StringVar(&networking, "networking", qemuNetworkingDefault, "Networking mode. Valid options are 'default', 'user', 'bridge[,name]', tap[,name] and 'none'. 'user' uses QEMUs userspace networking. 'bridge' connects to a preexisting bridge. 'tap' uses a prexisting tap device. 'none' disables networking.`")
|
|
|
|
flags.Var(&publishFlags, "publish", "Publish a vm's port(s) to the host (default [])")
|
|
}
|
|
|
|
func Qemu(cmd *cobra.Command, args []string) {
|
|
path := args[0]
|
|
|
|
if _, err := os.Stat(path); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
var publishedPorts []PublishedPort
|
|
for _, publish := range publishFlags {
|
|
p, err := NewPublishedPort(publish)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
publishedPorts = append(publishedPorts, p)
|
|
}
|
|
opts := []qemu.Option{
|
|
qemu.WithDisks(disks...),
|
|
qemu.WithAccel(accel),
|
|
qemu.WithArch(arch),
|
|
qemu.WithCPUs(cpus),
|
|
qemu.WithMemory(mem),
|
|
qemu.WithNetworking(networking),
|
|
qemu.WithStdin(os.Stdin),
|
|
qemu.WithStdout(os.Stdout),
|
|
qemu.WithStderr(os.Stderr),
|
|
}
|
|
if enableGUI {
|
|
opts = append(opts, qemu.WithGUI())
|
|
}
|
|
if qemuDetached {
|
|
opts = append(opts, qemu.WithDetached())
|
|
}
|
|
if err := qemu.Run(cmd.Context(), path, opts...); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func haveKVM() bool {
|
|
_, err := os.Stat("/dev/kvm")
|
|
return !os.IsNotExist(err)
|
|
}
|