work on stable version

This commit is contained in:
Ryan Ward 2025-03-28 11:09:50 -04:00
parent 70b35932cb
commit a0f6f3a6a0
8 changed files with 96 additions and 109 deletions

59
main.go
View File

@ -12,8 +12,6 @@ import (
"os"
"os/exec"
"path/filepath"
"runtime"
"syscall"
"github.com/google/uuid"
"github.com/melbahja/goph"
@ -34,8 +32,7 @@ type Credentials struct {
type Controller struct {
cancel context.CancelFunc
Stdout *bytes.Buffer
Stderr *bytes.Buffer
cmd *exec.Cmd
}
func (c *Controller) Stop() {
@ -63,41 +60,35 @@ func StartMachine(machine types.Machine) *Controller {
ctrl := &Controller{}
go func() {
command := machine.Expand()
ctx, cfunc := context.WithCancel(context.TODO())
ctrl.cancel = cfunc
var stdout bytes.Buffer
var stderr bytes.Buffer
var cmd *exec.Cmd
if runtime.GOOS == "windows" {
cmd = exec.Command("powershell.exe", command)
} else {
cmd = exec.Command("bash", "-c", command)
}
cmd.Stdout = &stdout
cmd.Stderr = &stderr
ctrl.Stderr = &stderr
ctrl.Stdout = &stdout
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd := exec.Command(fmt.Sprintf("qemu-system-%v", machine.Arch), machine.Expand()...)
fmt.Println(cmd.String())
cmd.Stdout = &stderr
cmd.Stderr = &stdout
ctrl.cmd = cmd
err := cmd.Start()
if err != nil {
panic(err)
fmt.Println("Error:", err)
}
fmt.Println("running...", cmd.Process.Pid)
//syscall.Kill(cmd.Process.Pid, syscall.SIGTERM)
go func() {
err := cmd.Wait()
if err != nil {
fmt.Println("Error:", err)
}
cfunc()
}()
for {
select {
case <-ctx.Done():
fmt.Println("Killing Process")
//err := KillProcess(string(machine.Arch))
//err := cmd.Process.Signal(syscall.SIGTERM)
err := cmd.Process.Kill()
if err != nil {
panic(err)
fmt.Println("Error:", err)
}
return
default:
}
}
}()
@ -144,28 +135,16 @@ func main() {
NoGraphic: types.Set,
HardDiskA: `./imgs/UbuntuTest.img`,
}
// ctrl := StartMachine(machine)
command := machine.Expand()
fmt.Println(command)
// this works, we need to format like this
cmd := exec.Command("qemu-system-x86_64", "-m", "size=4096", "-smp", "cpus=4", "-accel", "accel=whpx", "-boot", "order=c,menu=off", "-nic", "tap,ifname=qemu-tap", "-nographic", "-hda", "./imgs/UbuntuTest.img")
cmd.Start()
ctrl := StartMachine(machine)
fmt.Println("Press enter to stop machine")
reader := bufio.NewReader(os.Stdin)
_, _ = reader.ReadString('\n')
cmd.Process.Kill()
// ctrl.Stop()
ctrl.Stop()
fmt.Println("Press enter to exit")
_, _ = reader.ReadString('\n')
// if errout != "" {
// panic(fmt.Errorf("%v", errout))
// }
// if err != nil {
// fmt.Println(err)
// }
// Start new ssh connection with private key.
//client, err := goph.New("baseimguser", "127.0.0.1", goph.Password("food99"))

View File

@ -1,3 +0,0 @@
package machine
// qemu-system-x86_64.exe -m 4096 -accel whpx -boot d -smp 4 -net nic -net user,hostfwd=tcp::8888-:22 -hda .\imgs\ubuntu_server_test.img -nographic

View File

@ -1,4 +1,11 @@
package types
package accel
type (
VMExit string
Accelerator string
Thread string
KernelIrqchip string
)
const (
KVM Accelerator = "kvm"
@ -22,7 +29,7 @@ const (
)
type Accel struct {
Accelerator Accelerator `json:"accel,omitempty"`
Accelerator Accelerator `json:"accel,omitempty" omit:"tag"`
// enable Xen integrated Intel graphics passthrough, default=off
IGDPassthrough *bool `json:"igd-passthru,omitempty"`
// controls accelerated irqchip support (default=on

View File

@ -1,4 +1,4 @@
package types
package boot
// floppy (a), hard disk (c), CD-ROM (d), network (n)
type Drives string
@ -20,7 +20,7 @@ const (
type Boot struct {
// Order of boot
Order []Drives `json:"order,omitempty"`
Order []Drives `json:"order,omitempty" omit:"tag"`
Once []Drives `json:"once,omitempty"`
Menu *bool `json:"menu,omitempty"`
// The file's name that would be passed to bios as logo picture, if menu=on

View File

@ -6,6 +6,8 @@ import (
"strings"
"github.com/fatih/structs"
"github.com/rayaman/go-qemu/pkg/types/accel"
"github.com/rayaman/go-qemu/pkg/types/boot"
"github.com/rayaman/go-qemu/pkg/types/numa"
)
@ -30,14 +32,14 @@ type Machine struct {
// Amount of memory in MB
Memory Memory `json:"m,omitempty"`
// Number of CPU cores
Cores SMP `json:"smp,omitempty"`
Cpu CHIP `json:"cpu,omitempty"`
Accel Accel `json:"accel,omitempty"`
Boot Boot `json:"boot,omitempty"`
Numa numa.Numa `json:"numa,omitempty" omit:"true"`
MemoryPath string `json:"memory-path,omitempty"`
MemoryPrealloc Flag `json:"memory-prealloc,omitempty"`
Nic NIC `json:"nic,omitempty"`
Cores SMP `json:"smp,omitempty"`
Cpu CHIP `json:"cpu,omitempty"`
Accel accel.Accel `json:"accel,omitempty"`
Boot boot.Boot `json:"boot,omitempty"`
Numa numa.Numa `json:"numa,omitempty" omit:"true"`
MemoryPath string `json:"memory-path,omitempty"`
MemoryPrealloc Flag `json:"memory-prealloc,omitempty"`
Nic NIC `json:"nic,omitempty"`
// Graphics
NoGraphic Flag `json:"nographic,omitempty"`
@ -52,7 +54,16 @@ type Machine struct {
CDROM string `json:"cdrom,omitempty"`
}
func (m *Machine) Expand() string {
func remove(s []string, r string) []string {
for i, v := range s {
if v == r {
return append(s[:i], s[i+1:]...)
}
}
return s
}
func (m *Machine) Expand() []string {
fields := structs.Fields(m)
exp := []string{}
for _, field := range fields {
@ -61,29 +72,30 @@ func (m *Machine) Expand() string {
if tag != "" {
if field.Kind() == reflect.Struct || field.Kind() == reflect.Interface && !field.IsZero() {
if omit != "" {
exp = append(exp, Expand(field.Value()))
exp = append(exp, Expand(field.Value())...)
} else {
exp = append(exp, Expand(field.Value(), tag))
exp = append(exp, Expand(field.Value(), tag)...)
}
} else {
if !field.IsZero() {
if strings.Contains(fmt.Sprintf("%v", field.Value()), " ") {
exp = append(exp, fmt.Sprintf(`-%v "%v"`, tag, field.Value()))
if fmt.Sprintf("%v", field.Value()) == "flag-on" {
exp = append(exp, "-"+tag)
} else {
exp = append(exp, fmt.Sprintf("-%v %v", tag, field.Value()))
exp = append(exp, "-"+tag, fmt.Sprintf("%v", field.Value()))
}
}
}
}
}
return strings.ReplaceAll(strings.ReplaceAll(fmt.Sprintf("qemu-system-%v %v", m.Arch, strings.Join(exp, " ")), " flag-on", ""), " ", " ")
exp = remove(exp, "")
return exp
}
func Expand(obj any, tag ...string) string {
func Expand(obj any, tag ...string) []string {
opts := []string{}
fields := structs.Fields(obj)
useSpace := false
for _, field := range fields {
opt := strings.ReplaceAll(field.Tag("json"), ",omitempty", "")
opt = strings.ReplaceAll(opt, "omitempty", "")
@ -103,58 +115,50 @@ func Expand(obj any, tag ...string) string {
opts = append(opts, fmt.Sprintf("%v=%v-%v", opt, value.First, value.Last))
}
case []numa.Node:
useSpace = true
for _, node := range value {
opts = append(opts, "-numa "+opt+","+Expand(node))
opts = append(opts, "-numa", opt)
opts = append(opts, Expand(node)...)
}
case []numa.Dist:
useSpace = true
for _, dist := range value {
opts = append(opts, "-numa "+opt+","+Expand(dist))
opts = append(opts, "-numa", opt)
opts = append(opts, Expand(dist)...)
}
case []numa.CPU:
useSpace = true
for _, cpu := range value {
opts = append(opts, "-numa "+opt+","+Expand(cpu))
opts = append(opts, "-numa", opt)
opts = append(opts, Expand(cpu)...)
}
case []numa.HMATLB:
useSpace = true
for _, hmatlb := range value {
opts = append(opts, "-numa "+opt+","+Expand(hmatlb))
opts = append(opts, "-numa", opt)
opts = append(opts, Expand(hmatlb)...)
}
case []numa.HMATCache:
useSpace = true
for _, hmatcache := range value {
opts = append(opts, "-numa "+opt+","+Expand(hmatcache))
opts = append(opts, "-numa", opt)
opts = append(opts, Expand(hmatcache)...)
}
case Options:
opts = append(opts, value.ExpandOptions())
case []Drives:
opts = append(opts, fmt.Sprintf("%v=%v", opt, strings.Join(ConvertDrives(value), ",")))
opts = append(opts, value.ExpandOptions()...)
case []boot.Drives:
if omit == "tag" {
opts = append(opts, fmt.Sprintf("%v", strings.Join(boot.ConvertDrives(value), ",")))
} else {
opts = append(opts, fmt.Sprintf("%v=%v", opt, strings.Join(boot.ConvertDrives(value), ",")))
}
default:
if omit == "" {
if strings.Contains(fmt.Sprintf("%v", value), " ") {
opts = append(opts, fmt.Sprintf(`%v="%v"`, opt, value))
} else {
opts = append(opts, fmt.Sprintf("%v=%v", opt, value))
}
} else {
if strings.Contains(fmt.Sprintf("%v", value), " ") {
opts = append(opts, fmt.Sprintf(`"%v"`, value))
} else {
opts = append(opts, fmt.Sprintf("%v", value))
}
opts = append(opts, fmt.Sprintf("%v=%v", opt, value))
} else if omit == "tag" {
opts = append(opts, fmt.Sprintf("%v", value))
}
}
}
}
otag := ""
if len(tag) > 0 {
otag = "-" + tag[0] + " "
return []string{"-" + tag[0], strings.Join(opts, ",")}
} else {
return []string{strings.Join(opts, ",")}
}
if useSpace {
return otag + strings.Join(opts, " ")
}
return otag + strings.Join(opts, ",")
}

View File

@ -1,9 +1,13 @@
package types
import "strings"
type (
NICType string
)
// TODO: Implement other types user,socket,brtidge
const (
TAP NICType = "tap"
Bridge NICType = "bridge"
@ -16,22 +20,22 @@ type TapOptions struct {
IFName string `json:"ifname,omitempty"`
}
func (t *TapOptions) ExpandOptions() string {
return Expand(t)
func (t *TapOptions) ExpandOptions() []string {
return []string{"tap," + strings.Join(Expand(t), ",")}
}
type BridgeOptions struct {
}
func (b *BridgeOptions) ExpandOptions() string {
return ""
func (b *BridgeOptions) ExpandOptions() []string {
return []string{}
}
type UserOptions struct {
}
func (u *UserOptions) ExpandOptions() string {
return ""
func (u *UserOptions) ExpandOptions() []string {
return []string{}
}
type SocketOptions struct {
@ -44,12 +48,12 @@ type SocketOptions struct {
Connect string `json:"connect,omitempty"`
}
func (s *SocketOptions) ExpandOptions() string {
return Expand(s)
func (s *SocketOptions) ExpandOptions() []string {
return []string{}
}
type Options interface {
ExpandOptions() string
ExpandOptions() []string
}
type NIC struct {

View File

@ -16,7 +16,7 @@ Note: Different machines may have different subsets of the CPU topology
*/
type SMP struct {
// The number of initial CPUs
Cpus uint `json:"cpus,omitempty"`
Cpus uint `json:"cpus,omitempty" omit:"tag"`
// Maximum number of total CPUs, including offline CPUs for hotplug, etc
MaxCpus uint `json:"maxcpus,omitempty"`
// Number of drawers on the machine board

View File

@ -8,10 +8,6 @@ type (
CompressionType string
Format string
System string
Accelerator string
VMExit string
Thread string
KernelIrqchip string
Flag string
)