work on stable version
This commit is contained in:
parent
70b35932cb
commit
a0f6f3a6a0
59
main.go
59
main.go
@ -12,8 +12,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/melbahja/goph"
|
"github.com/melbahja/goph"
|
||||||
@ -34,8 +32,7 @@ type Credentials struct {
|
|||||||
|
|
||||||
type Controller struct {
|
type Controller struct {
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
Stdout *bytes.Buffer
|
cmd *exec.Cmd
|
||||||
Stderr *bytes.Buffer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) Stop() {
|
func (c *Controller) Stop() {
|
||||||
@ -63,41 +60,35 @@ func StartMachine(machine types.Machine) *Controller {
|
|||||||
ctrl := &Controller{}
|
ctrl := &Controller{}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
command := machine.Expand()
|
|
||||||
ctx, cfunc := context.WithCancel(context.TODO())
|
ctx, cfunc := context.WithCancel(context.TODO())
|
||||||
ctrl.cancel = cfunc
|
ctrl.cancel = cfunc
|
||||||
var stdout bytes.Buffer
|
var stdout bytes.Buffer
|
||||||
var stderr bytes.Buffer
|
var stderr bytes.Buffer
|
||||||
var cmd *exec.Cmd
|
cmd := exec.Command(fmt.Sprintf("qemu-system-%v", machine.Arch), machine.Expand()...)
|
||||||
if runtime.GOOS == "windows" {
|
fmt.Println(cmd.String())
|
||||||
cmd = exec.Command("powershell.exe", command)
|
cmd.Stdout = &stderr
|
||||||
} else {
|
cmd.Stderr = &stdout
|
||||||
cmd = exec.Command("bash", "-c", command)
|
ctrl.cmd = cmd
|
||||||
}
|
|
||||||
cmd.Stdout = &stdout
|
|
||||||
cmd.Stderr = &stderr
|
|
||||||
ctrl.Stderr = &stderr
|
|
||||||
ctrl.Stdout = &stdout
|
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
fmt.Println("Error:", err)
|
||||||
}
|
}
|
||||||
fmt.Println("running...", cmd.Process.Pid)
|
go func() {
|
||||||
|
err := cmd.Wait()
|
||||||
//syscall.Kill(cmd.Process.Pid, syscall.SIGTERM)
|
if err != nil {
|
||||||
|
fmt.Println("Error:", err)
|
||||||
|
}
|
||||||
|
cfunc()
|
||||||
|
}()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
fmt.Println("Killing Process")
|
fmt.Println("Killing Process")
|
||||||
//err := KillProcess(string(machine.Arch))
|
|
||||||
//err := cmd.Process.Signal(syscall.SIGTERM)
|
|
||||||
err := cmd.Process.Kill()
|
err := cmd.Process.Kill()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
fmt.Println("Error:", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -144,28 +135,16 @@ func main() {
|
|||||||
NoGraphic: types.Set,
|
NoGraphic: types.Set,
|
||||||
HardDiskA: `./imgs/UbuntuTest.img`,
|
HardDiskA: `./imgs/UbuntuTest.img`,
|
||||||
}
|
}
|
||||||
// ctrl := StartMachine(machine)
|
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()
|
|
||||||
fmt.Println("Press enter to stop machine")
|
fmt.Println("Press enter to stop machine")
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
_, _ = reader.ReadString('\n')
|
_, _ = reader.ReadString('\n')
|
||||||
cmd.Process.Kill()
|
|
||||||
// ctrl.Stop()
|
ctrl.Stop()
|
||||||
fmt.Println("Press enter to exit")
|
fmt.Println("Press enter to exit")
|
||||||
_, _ = reader.ReadString('\n')
|
_, _ = reader.ReadString('\n')
|
||||||
|
|
||||||
// if errout != "" {
|
|
||||||
// panic(fmt.Errorf("%v", errout))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if err != nil {
|
|
||||||
// fmt.Println(err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Start new ssh connection with private key.
|
// Start new ssh connection with private key.
|
||||||
|
|
||||||
//client, err := goph.New("baseimguser", "127.0.0.1", goph.Password("food99"))
|
//client, err := goph.New("baseimguser", "127.0.0.1", goph.Password("food99"))
|
||||||
|
|||||||
@ -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
|
|
||||||
@ -1,4 +1,11 @@
|
|||||||
package types
|
package accel
|
||||||
|
|
||||||
|
type (
|
||||||
|
VMExit string
|
||||||
|
Accelerator string
|
||||||
|
Thread string
|
||||||
|
KernelIrqchip string
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
KVM Accelerator = "kvm"
|
KVM Accelerator = "kvm"
|
||||||
@ -22,7 +29,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Accel struct {
|
type Accel struct {
|
||||||
Accelerator Accelerator `json:"accel,omitempty"`
|
Accelerator Accelerator `json:"accel,omitempty" omit:"tag"`
|
||||||
// enable Xen integrated Intel graphics passthrough, default=off
|
// enable Xen integrated Intel graphics passthrough, default=off
|
||||||
IGDPassthrough *bool `json:"igd-passthru,omitempty"`
|
IGDPassthrough *bool `json:"igd-passthru,omitempty"`
|
||||||
// controls accelerated irqchip support (default=on
|
// controls accelerated irqchip support (default=on
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package types
|
package boot
|
||||||
|
|
||||||
// floppy (a), hard disk (c), CD-ROM (d), network (n)
|
// floppy (a), hard disk (c), CD-ROM (d), network (n)
|
||||||
type Drives string
|
type Drives string
|
||||||
@ -20,7 +20,7 @@ const (
|
|||||||
|
|
||||||
type Boot struct {
|
type Boot struct {
|
||||||
// Order of boot
|
// Order of boot
|
||||||
Order []Drives `json:"order,omitempty"`
|
Order []Drives `json:"order,omitempty" omit:"tag"`
|
||||||
Once []Drives `json:"once,omitempty"`
|
Once []Drives `json:"once,omitempty"`
|
||||||
Menu *bool `json:"menu,omitempty"`
|
Menu *bool `json:"menu,omitempty"`
|
||||||
// The file's name that would be passed to bios as logo picture, if menu=on
|
// The file's name that would be passed to bios as logo picture, if menu=on
|
||||||
@ -6,6 +6,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fatih/structs"
|
"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"
|
"github.com/rayaman/go-qemu/pkg/types/numa"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,14 +32,14 @@ type Machine struct {
|
|||||||
// Amount of memory in MB
|
// Amount of memory in MB
|
||||||
Memory Memory `json:"m,omitempty"`
|
Memory Memory `json:"m,omitempty"`
|
||||||
// Number of CPU cores
|
// Number of CPU cores
|
||||||
Cores SMP `json:"smp,omitempty"`
|
Cores SMP `json:"smp,omitempty"`
|
||||||
Cpu CHIP `json:"cpu,omitempty"`
|
Cpu CHIP `json:"cpu,omitempty"`
|
||||||
Accel Accel `json:"accel,omitempty"`
|
Accel accel.Accel `json:"accel,omitempty"`
|
||||||
Boot Boot `json:"boot,omitempty"`
|
Boot boot.Boot `json:"boot,omitempty"`
|
||||||
Numa numa.Numa `json:"numa,omitempty" omit:"true"`
|
Numa numa.Numa `json:"numa,omitempty" omit:"true"`
|
||||||
MemoryPath string `json:"memory-path,omitempty"`
|
MemoryPath string `json:"memory-path,omitempty"`
|
||||||
MemoryPrealloc Flag `json:"memory-prealloc,omitempty"`
|
MemoryPrealloc Flag `json:"memory-prealloc,omitempty"`
|
||||||
Nic NIC `json:"nic,omitempty"`
|
Nic NIC `json:"nic,omitempty"`
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
NoGraphic Flag `json:"nographic,omitempty"`
|
NoGraphic Flag `json:"nographic,omitempty"`
|
||||||
@ -52,7 +54,16 @@ type Machine struct {
|
|||||||
CDROM string `json:"cdrom,omitempty"`
|
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)
|
fields := structs.Fields(m)
|
||||||
exp := []string{}
|
exp := []string{}
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
@ -61,29 +72,30 @@ func (m *Machine) Expand() string {
|
|||||||
if tag != "" {
|
if tag != "" {
|
||||||
if field.Kind() == reflect.Struct || field.Kind() == reflect.Interface && !field.IsZero() {
|
if field.Kind() == reflect.Struct || field.Kind() == reflect.Interface && !field.IsZero() {
|
||||||
if omit != "" {
|
if omit != "" {
|
||||||
exp = append(exp, Expand(field.Value()))
|
exp = append(exp, Expand(field.Value())...)
|
||||||
} else {
|
} else {
|
||||||
exp = append(exp, Expand(field.Value(), tag))
|
exp = append(exp, Expand(field.Value(), tag)...)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !field.IsZero() {
|
if !field.IsZero() {
|
||||||
if strings.Contains(fmt.Sprintf("%v", field.Value()), " ") {
|
if fmt.Sprintf("%v", field.Value()) == "flag-on" {
|
||||||
exp = append(exp, fmt.Sprintf(`-%v "%v"`, tag, field.Value()))
|
exp = append(exp, "-"+tag)
|
||||||
} else {
|
} 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{}
|
opts := []string{}
|
||||||
fields := structs.Fields(obj)
|
fields := structs.Fields(obj)
|
||||||
useSpace := false
|
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
opt := strings.ReplaceAll(field.Tag("json"), ",omitempty", "")
|
opt := strings.ReplaceAll(field.Tag("json"), ",omitempty", "")
|
||||||
opt = strings.ReplaceAll(opt, "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))
|
opts = append(opts, fmt.Sprintf("%v=%v-%v", opt, value.First, value.Last))
|
||||||
}
|
}
|
||||||
case []numa.Node:
|
case []numa.Node:
|
||||||
useSpace = true
|
|
||||||
for _, node := range value {
|
for _, node := range value {
|
||||||
opts = append(opts, "-numa "+opt+","+Expand(node))
|
opts = append(opts, "-numa", opt)
|
||||||
|
opts = append(opts, Expand(node)...)
|
||||||
}
|
}
|
||||||
case []numa.Dist:
|
case []numa.Dist:
|
||||||
useSpace = true
|
|
||||||
for _, dist := range value {
|
for _, dist := range value {
|
||||||
opts = append(opts, "-numa "+opt+","+Expand(dist))
|
opts = append(opts, "-numa", opt)
|
||||||
|
opts = append(opts, Expand(dist)...)
|
||||||
}
|
}
|
||||||
case []numa.CPU:
|
case []numa.CPU:
|
||||||
useSpace = true
|
|
||||||
for _, cpu := range value {
|
for _, cpu := range value {
|
||||||
opts = append(opts, "-numa "+opt+","+Expand(cpu))
|
opts = append(opts, "-numa", opt)
|
||||||
|
opts = append(opts, Expand(cpu)...)
|
||||||
}
|
}
|
||||||
case []numa.HMATLB:
|
case []numa.HMATLB:
|
||||||
useSpace = true
|
|
||||||
for _, hmatlb := range value {
|
for _, hmatlb := range value {
|
||||||
opts = append(opts, "-numa "+opt+","+Expand(hmatlb))
|
opts = append(opts, "-numa", opt)
|
||||||
|
opts = append(opts, Expand(hmatlb)...)
|
||||||
}
|
}
|
||||||
case []numa.HMATCache:
|
case []numa.HMATCache:
|
||||||
useSpace = true
|
|
||||||
for _, hmatcache := range value {
|
for _, hmatcache := range value {
|
||||||
opts = append(opts, "-numa "+opt+","+Expand(hmatcache))
|
opts = append(opts, "-numa", opt)
|
||||||
|
opts = append(opts, Expand(hmatcache)...)
|
||||||
}
|
}
|
||||||
case Options:
|
case Options:
|
||||||
opts = append(opts, value.ExpandOptions())
|
opts = append(opts, value.ExpandOptions()...)
|
||||||
case []Drives:
|
case []boot.Drives:
|
||||||
opts = append(opts, fmt.Sprintf("%v=%v", opt, strings.Join(ConvertDrives(value), ",")))
|
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:
|
default:
|
||||||
if omit == "" {
|
if omit == "" {
|
||||||
if strings.Contains(fmt.Sprintf("%v", value), " ") {
|
opts = append(opts, fmt.Sprintf("%v=%v", opt, value))
|
||||||
opts = append(opts, fmt.Sprintf(`%v="%v"`, opt, value))
|
} else if omit == "tag" {
|
||||||
} else {
|
opts = append(opts, fmt.Sprintf("%v", value))
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
otag := ""
|
|
||||||
if len(tag) > 0 {
|
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, ",")
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
type (
|
type (
|
||||||
NICType string
|
NICType string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: Implement other types user,socket,brtidge
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TAP NICType = "tap"
|
TAP NICType = "tap"
|
||||||
Bridge NICType = "bridge"
|
Bridge NICType = "bridge"
|
||||||
@ -16,22 +20,22 @@ type TapOptions struct {
|
|||||||
IFName string `json:"ifname,omitempty"`
|
IFName string `json:"ifname,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TapOptions) ExpandOptions() string {
|
func (t *TapOptions) ExpandOptions() []string {
|
||||||
return Expand(t)
|
return []string{"tap," + strings.Join(Expand(t), ",")}
|
||||||
}
|
}
|
||||||
|
|
||||||
type BridgeOptions struct {
|
type BridgeOptions struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BridgeOptions) ExpandOptions() string {
|
func (b *BridgeOptions) ExpandOptions() []string {
|
||||||
return ""
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserOptions struct {
|
type UserOptions struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserOptions) ExpandOptions() string {
|
func (u *UserOptions) ExpandOptions() []string {
|
||||||
return ""
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SocketOptions struct {
|
type SocketOptions struct {
|
||||||
@ -44,12 +48,12 @@ type SocketOptions struct {
|
|||||||
Connect string `json:"connect,omitempty"`
|
Connect string `json:"connect,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SocketOptions) ExpandOptions() string {
|
func (s *SocketOptions) ExpandOptions() []string {
|
||||||
return Expand(s)
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Options interface {
|
type Options interface {
|
||||||
ExpandOptions() string
|
ExpandOptions() []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type NIC struct {
|
type NIC struct {
|
||||||
|
|||||||
@ -16,7 +16,7 @@ Note: Different machines may have different subsets of the CPU topology
|
|||||||
*/
|
*/
|
||||||
type SMP struct {
|
type SMP struct {
|
||||||
// The number of initial CPUs
|
// 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
|
// Maximum number of total CPUs, including offline CPUs for hotplug, etc
|
||||||
MaxCpus uint `json:"maxcpus,omitempty"`
|
MaxCpus uint `json:"maxcpus,omitempty"`
|
||||||
// Number of drawers on the machine board
|
// Number of drawers on the machine board
|
||||||
|
|||||||
@ -8,10 +8,6 @@ type (
|
|||||||
CompressionType string
|
CompressionType string
|
||||||
Format string
|
Format string
|
||||||
System string
|
System string
|
||||||
Accelerator string
|
|
||||||
VMExit string
|
|
||||||
Thread string
|
|
||||||
KernelIrqchip string
|
|
||||||
Flag string
|
Flag string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user