resturctured code
This commit is contained in:
parent
a0f6f3a6a0
commit
7384a56b07
45
main.go
45
main.go
@ -15,9 +15,17 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/melbahja/goph"
|
||||
"github.com/rayaman/go-qemu/pkg/image"
|
||||
"github.com/rayaman/go-qemu/pkg/image/formats"
|
||||
"github.com/rayaman/go-qemu/pkg/types"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/image"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/image/formats"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/system"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/accel"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/arch"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/boot"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/disk"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/memory"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/nic"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/smp"
|
||||
"github.com/shirou/gopsutil/v3/process"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
@ -33,12 +41,17 @@ type Credentials struct {
|
||||
type Controller struct {
|
||||
cancel context.CancelFunc
|
||||
cmd *exec.Cmd
|
||||
err []error
|
||||
}
|
||||
|
||||
func (c *Controller) Stop() {
|
||||
c.cancel()
|
||||
}
|
||||
|
||||
func (c *Controller) Errors() []error {
|
||||
return c.err
|
||||
}
|
||||
|
||||
func KillProcess(name string) error {
|
||||
processes, err := process.Processes()
|
||||
if err != nil {
|
||||
@ -56,7 +69,7 @@ func KillProcess(name string) error {
|
||||
return fmt.Errorf("process not found")
|
||||
}
|
||||
|
||||
func StartMachine(machine types.Machine) *Controller {
|
||||
func StartMachine(machine system.Machine) *Controller {
|
||||
ctrl := &Controller{}
|
||||
|
||||
go func() {
|
||||
@ -111,24 +124,24 @@ func main() {
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
machine := types.Machine{
|
||||
Arch: types.X86_64,
|
||||
Cores: types.SMP{
|
||||
machine := system.Machine{
|
||||
Arch: arch.X86_64,
|
||||
Cores: smp.SMP{
|
||||
Cpus: 4,
|
||||
},
|
||||
Boot: types.Boot{
|
||||
Order: []types.Drives{types.HARDDISK},
|
||||
Boot: boot.Boot{
|
||||
Order: []boot.Drives{boot.HARDDISK},
|
||||
Menu: types.Off,
|
||||
},
|
||||
Memory: types.Memory{
|
||||
Memory: memory.Memory{
|
||||
Size: 4096,
|
||||
},
|
||||
Accel: types.Accel{
|
||||
Accelerator: types.WHPX,
|
||||
Accel: accel.Accel{
|
||||
Accelerator: accel.WHPX,
|
||||
},
|
||||
Nic: types.NIC{
|
||||
Type: types.TAP,
|
||||
Options: &types.TapOptions{
|
||||
Nic: nic.NIC{
|
||||
Type: nic.TAP,
|
||||
Options: &nic.TapOptions{
|
||||
IFName: "qemu-tap",
|
||||
},
|
||||
},
|
||||
@ -181,7 +194,7 @@ func main() {
|
||||
// SetUpMachine(types.GetSize(types.GB, 64))
|
||||
}
|
||||
|
||||
func SetUpMachine(size types.Size) (*Credentials, error) {
|
||||
func SetUpMachine(size disk.Size) (*Credentials, error) {
|
||||
machine_id := uuid.New().String()
|
||||
private_path := filepath.Join("keys", machine_id)
|
||||
public_path := filepath.Join("keys", machine_id+".pub")
|
||||
|
||||
@ -1,71 +0,0 @@
|
||||
package image
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/rayaman/go-qemu/pkg/types"
|
||||
)
|
||||
|
||||
// Reperesents a qemu image
|
||||
type Image interface {
|
||||
//GetType() types.Format
|
||||
}
|
||||
|
||||
type holder struct {
|
||||
Format string
|
||||
Image any
|
||||
}
|
||||
|
||||
// Loades a saved Image into memory
|
||||
func LoadImage(path string) (Image, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var h = &holder{}
|
||||
|
||||
err = json.Unmarshal(data, h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err = json.Marshal(h.Image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t := reflect.New(reflect.TypeOf(types.GetTypes()[h.Format])).Interface()
|
||||
err = json.Unmarshal(data, t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// Saves an image to disk
|
||||
func SaveImage(path string, img Image) error {
|
||||
|
||||
data, err := json.MarshalIndent(holder{
|
||||
Format: strings.ReplaceAll(strings.ToLower(reflect.TypeOf(img).String()), "*formats.", ""),
|
||||
Image: img,
|
||||
}, "", "\t")
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file, err := os.Create(path)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = file.Write(data)
|
||||
|
||||
return err
|
||||
}
|
||||
@ -8,58 +8,13 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/abdfnx/gosh"
|
||||
"github.com/rayaman/go-qemu/pkg/types"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/disk"
|
||||
)
|
||||
|
||||
func getOptions(m map[string]string) string {
|
||||
str := []string{}
|
||||
for k, v := range m {
|
||||
if len(v) > 0 {
|
||||
str = append(str, fmt.Sprintf("%v=%v", k, v))
|
||||
}
|
||||
}
|
||||
n_str := strings.Join(str, ",")
|
||||
if len(n_str) > 0 {
|
||||
return "-o \"" + strings.Join(str, ",") + "\" "
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getData(m map[string]string, key string) (string, bool) {
|
||||
if d, ok := m[key]; ok {
|
||||
delete(m, key)
|
||||
if len(d) == 0 {
|
||||
return "", false
|
||||
}
|
||||
return d, true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func getMap(q any) map[string]string {
|
||||
m := map[string]string{}
|
||||
v := reflect.ValueOf(q).Elem()
|
||||
for j := 0; j < v.NumField(); j++ { // Go through all fields of struct
|
||||
if !v.Field(j).IsZero() {
|
||||
index := strings.ReplaceAll(v.Type().Field(j).Tag.Get("json"), ",omitempty", "")
|
||||
if v.Field(j).Type() == reflect.TypeOf(true) {
|
||||
m[index] = types.SW[v.Field(j).Bool()]
|
||||
} else {
|
||||
m[index] = v.Field(j).String()
|
||||
}
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
IsBaseImage bool `json:"is_base_image"`
|
||||
}
|
||||
|
||||
// create [--object OBJECTDEF] [-q] [-f FMT] [-b BACKING_FILE [-F BACKING_FMT]] [-u] [-o OPTIONS] FILENAME [SIZE]
|
||||
|
||||
// Creates an image based of the supplied image
|
||||
func Create(i Image, size types.Size, opts ...Options) error {
|
||||
// Creates an image based of the supplied image structure
|
||||
func Create(i Image, size disk.Size, opts ...Options) error {
|
||||
|
||||
data := getMap(i)
|
||||
|
||||
37
pkg/v1/image/cmd_load_image.go
Normal file
37
pkg/v1/image/cmd_load_image.go
Normal file
@ -0,0 +1,37 @@
|
||||
package image
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types"
|
||||
)
|
||||
|
||||
// Loads a saved image structure into memory
|
||||
func LoadImage(path string) (Image, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var h = &holder{}
|
||||
|
||||
err = json.Unmarshal(data, h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err = json.Marshal(h.Image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t := reflect.New(reflect.TypeOf(types.GetTypes()[h.Format])).Interface()
|
||||
err = json.Unmarshal(data, t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
31
pkg/v1/image/cmd_save_image.go
Normal file
31
pkg/v1/image/cmd_save_image.go
Normal file
@ -0,0 +1,31 @@
|
||||
package image
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Saves an image structure to disk
|
||||
func SaveImage(path string, img Image) error {
|
||||
|
||||
data, err := json.MarshalIndent(holder{
|
||||
Format: strings.ReplaceAll(strings.ToLower(reflect.TypeOf(img).String()), "*formats.", ""),
|
||||
Image: img,
|
||||
}, "", "\t")
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file, err := os.Create(path)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = file.Write(data)
|
||||
|
||||
return err
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
package formats
|
||||
|
||||
import (
|
||||
"github.com/rayaman/go-qemu/pkg/types"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/image"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -12,13 +13,13 @@ type QCOW2 struct {
|
||||
// Name of the image
|
||||
ImageName string `json:"image_name"`
|
||||
// Determines the qcow2 version to use. compat=0.10 uses the traditional image format that can be read by any QEMU since 0.10. compat=1.1 enables image format extensions that only QEMU 1.1 and newer understand (this is the default). Amongst others, this includes zero clusters, which allow efficient copy-on-read for sparse images
|
||||
Compat types.Compat `json:"compat,omitempty"`
|
||||
Compat image.Compat `json:"compat,omitempty"`
|
||||
// File name of a base image
|
||||
BackingFile string `json:"backing_file,omitempty"`
|
||||
// Image format of the base image
|
||||
BackingFmt string `json:"backing_fmt,omitempty"`
|
||||
// This option configures which compression algorithm will be used for compressed clusters on the image. Note that setting this option doesn’t yet cause the image to actually receive compressed writes. It is most commonly used with the -c option of qemu-img convert, but can also be used with the compress filter driver or backup block jobs with compression enabled.
|
||||
CompressionType types.CompressionType `json:"compression_type,omitempty"`
|
||||
CompressionType image.CompressionType `json:"compression_type,omitempty"`
|
||||
/*
|
||||
If this option is set to true, the image is encrypted with 128-bit AES-CBC.
|
||||
|
||||
@ -38,7 +39,7 @@ type QCOW2 struct {
|
||||
// Changes the qcow2 cluster size (must be between 512 and 2M). Smaller cluster sizes can improve the image file size whereas larger cluster sizes generally provide better performance.
|
||||
ClusterSize string `json:"cluster_size,omitempty"`
|
||||
// Preallocation mode (allowed values: off, metadata, falloc, full). An image with preallocated metadata is initially larger but can improve performance when the image needs to grow. falloc and full preallocations are like the same options of raw format, but sets up metadata also.
|
||||
Preallocation types.Preallocation `json:"preallocation,omitempty"`
|
||||
Preallocation image.Preallocation `json:"preallocation,omitempty"`
|
||||
/*
|
||||
If this option is set to true, reference count updates are postponed with the goal of avoiding metadata I/O and improving performance. This is particularly interesting with cache=writethrough which doesn’t batch metadata updates. The tradeoff is that after a host crash, the reference count tables must be rebuilt, i.e. on the next open an (automatic) qemu-img check -r all is required, which may take some time.
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
package formats
|
||||
|
||||
import (
|
||||
"github.com/rayaman/go-qemu/pkg/types"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/image"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -12,5 +13,5 @@ type Raw struct {
|
||||
// Name of the image
|
||||
ImageName string `json:"image_name"`
|
||||
// Preallocation mode (allowed values: off, falloc, full). falloc mode preallocates space for image by calling posix_fallocate(). full mode preallocates space for image by writing data to underlying storage. This data may or may not be zero, depending on the storage location.
|
||||
Preallocation types.Preallocation `json:"preallocation"`
|
||||
Preallocation image.Preallocation `json:"preallocation"`
|
||||
}
|
||||
17
pkg/v1/image/types.go
Normal file
17
pkg/v1/image/types.go
Normal file
@ -0,0 +1,17 @@
|
||||
package image
|
||||
|
||||
type (
|
||||
Options struct {
|
||||
IsBaseImage bool `json:"is_base_image"`
|
||||
}
|
||||
|
||||
// Reperesents a qemu image
|
||||
Image interface {
|
||||
//GetType() types.Format
|
||||
}
|
||||
|
||||
holder struct {
|
||||
Format string
|
||||
Image any
|
||||
}
|
||||
)
|
||||
50
pkg/v1/image/utils.go
Normal file
50
pkg/v1/image/utils.go
Normal file
@ -0,0 +1,50 @@
|
||||
package image
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/utils"
|
||||
)
|
||||
|
||||
func getOptions(m map[string]string) string {
|
||||
str := []string{}
|
||||
for k, v := range m {
|
||||
if len(v) > 0 {
|
||||
str = append(str, fmt.Sprintf("%v=%v", k, v))
|
||||
}
|
||||
}
|
||||
n_str := strings.Join(str, ",")
|
||||
if len(n_str) > 0 {
|
||||
return "-o \"" + strings.Join(str, ",") + "\" "
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getData(m map[string]string, key string) (string, bool) {
|
||||
if d, ok := m[key]; ok {
|
||||
delete(m, key)
|
||||
if len(d) == 0 {
|
||||
return "", false
|
||||
}
|
||||
return d, true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func getMap(q any) map[string]string {
|
||||
m := map[string]string{}
|
||||
v := reflect.ValueOf(q).Elem()
|
||||
for j := 0; j < v.NumField(); j++ { // Go through all fields of struct
|
||||
if !v.Field(j).IsZero() {
|
||||
index := strings.ReplaceAll(v.Type().Field(j).Tag.Get("json"), ",omitempty", "")
|
||||
if v.Field(j).Type() == reflect.TypeOf(true) {
|
||||
m[index] = utils.SW[v.Field(j).Bool()]
|
||||
} else {
|
||||
m[index] = v.Field(j).String()
|
||||
}
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
90
pkg/v1/system/machine.go
Normal file
90
pkg/v1/system/machine.go
Normal file
@ -0,0 +1,90 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/accel"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/arch"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/boot"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/chip"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/memory"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/nic"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/numa"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/smp"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/utils"
|
||||
)
|
||||
|
||||
/*
|
||||
TODO:
|
||||
-add-fd fd=fd,set=set[,opaque=opaque]
|
||||
|
||||
Add 'fd' to fd 'set'
|
||||
|
||||
-set group.id.arg=value
|
||||
|
||||
set <arg> parameter for item <id> of type <group>
|
||||
i.e. -set drive.$id.file=/path/to/image
|
||||
|
||||
-global driver.property=value
|
||||
-global driver=driver,property=property,value=value
|
||||
|
||||
set a global default for a driver property
|
||||
*/
|
||||
type Machine struct {
|
||||
Arch arch.System // The binary we use
|
||||
// Amount of memory in MB
|
||||
Memory memory.Memory `json:"m,omitempty"`
|
||||
// Number of CPU cores
|
||||
Cores smp.SMP `json:"smp,omitempty"`
|
||||
Cpu chip.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 types.Flag `json:"memory-prealloc,omitempty"`
|
||||
Nic nic.NIC `json:"nic,omitempty"`
|
||||
|
||||
// Graphics
|
||||
NoGraphic types.Flag `json:"nographic,omitempty"`
|
||||
|
||||
// Block devices
|
||||
HardDiskA string `json:"hda,omitempty"`
|
||||
HardDiskB string `json:"hdb,omitempty"`
|
||||
HardDiskC string `json:"hdc,omitempty"`
|
||||
HardDiskD string `json:"hdd,omitempty"`
|
||||
FloppyA string `json:"fda,omitempty"`
|
||||
FloppyB string `json:"fdb,omitempty"`
|
||||
CDROM string `json:"cdrom,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Machine) Expand() []string {
|
||||
fields := structs.Fields(m)
|
||||
exp := []string{}
|
||||
for _, field := range fields {
|
||||
tag := strings.ReplaceAll(field.Tag("json"), ",omitempty", "")
|
||||
omit := field.Tag("omit")
|
||||
if tag != "" {
|
||||
if field.Kind() == reflect.Struct || field.Kind() == reflect.Interface && !field.IsZero() {
|
||||
if omit != "" {
|
||||
exp = append(exp, utils.Expand(field.Value())...)
|
||||
} else {
|
||||
exp = append(exp, utils.Expand(field.Value(), tag)...)
|
||||
}
|
||||
} else {
|
||||
if !field.IsZero() {
|
||||
if fmt.Sprintf("%v", field.Value()) == "flag-on" {
|
||||
exp = append(exp, "-"+tag)
|
||||
} else {
|
||||
exp = append(exp, "-"+tag, fmt.Sprintf("%v", field.Value()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exp = utils.Remove(exp, "")
|
||||
return exp
|
||||
}
|
||||
@ -1,52 +1,8 @@
|
||||
package types
|
||||
package arch
|
||||
|
||||
import "fmt"
|
||||
|
||||
type (
|
||||
Preallocation string
|
||||
Compat string
|
||||
CompressionType string
|
||||
Format string
|
||||
System string
|
||||
Flag string
|
||||
)
|
||||
|
||||
// converts bool to on/off format
|
||||
var SW = map[bool]string{
|
||||
true: "on",
|
||||
false: "off",
|
||||
}
|
||||
var (
|
||||
On *bool = func(b bool) *bool {
|
||||
return &b
|
||||
}(true)
|
||||
Off *bool = func(b bool) *bool {
|
||||
return &b
|
||||
}(false)
|
||||
)
|
||||
|
||||
type Param interface {
|
||||
Expand() string
|
||||
}
|
||||
|
||||
var register = map[string]any{}
|
||||
type System string
|
||||
|
||||
var (
|
||||
// No pre-allocation
|
||||
OFF Preallocation = "off"
|
||||
// Allocates qcow2 metadata, and it's still a sparse image.
|
||||
METADATA Preallocation = "metadata"
|
||||
// Uses posix_fallocate() to "allocate blocks and marking them as uninitialized", and is relatively faster than writing out zeroes to a file:
|
||||
FALLOC Preallocation = "falloc"
|
||||
// Allocates zeroes and makes a non-sparse image.
|
||||
FULL Preallocation = "full"
|
||||
|
||||
Compat_0_10 Compat = "0.10"
|
||||
Compat_1_1 Compat = "1.1"
|
||||
|
||||
Zlib CompressionType = "zlib"
|
||||
Zstd CompressionType = "zstd"
|
||||
|
||||
AARCH64 System = "aarch64"
|
||||
AARCH64W System = "aarch64w"
|
||||
ALPHA System = "alpha"
|
||||
@ -105,18 +61,4 @@ var (
|
||||
XTENSAEB System = "xtensaeb"
|
||||
XTENSAEBW System = "xtensaebw"
|
||||
XTENSAW System = "xtensaw"
|
||||
|
||||
Set Flag = "flag-on"
|
||||
)
|
||||
|
||||
func GetTypes() map[string]any {
|
||||
return register
|
||||
}
|
||||
|
||||
func RegisterType(t string, i any) error {
|
||||
if _, ok := register[t]; !ok {
|
||||
register[t] = i
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("type already registered")
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package types
|
||||
package chip
|
||||
|
||||
type CHIP string
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package types
|
||||
package disk
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
25
pkg/v1/types/image/image.go
Normal file
25
pkg/v1/types/image/image.go
Normal file
@ -0,0 +1,25 @@
|
||||
package image
|
||||
|
||||
type (
|
||||
Preallocation string
|
||||
Compat string
|
||||
CompressionType string
|
||||
Format string
|
||||
)
|
||||
|
||||
var (
|
||||
// No pre-allocation
|
||||
OFF Preallocation = "off"
|
||||
// Allocates qcow2 metadata, and it's still a sparse image.
|
||||
METADATA Preallocation = "metadata"
|
||||
// Uses posix_fallocate() to "allocate blocks and marking them as uninitialized", and is relatively faster than writing out zeroes to a file:
|
||||
FALLOC Preallocation = "falloc"
|
||||
// Allocates zeroes and makes a non-sparse image.
|
||||
FULL Preallocation = "full"
|
||||
|
||||
Compat_0_10 Compat = "0.10"
|
||||
Compat_1_1 Compat = "1.1"
|
||||
|
||||
Zlib CompressionType = "zlib"
|
||||
Zstd CompressionType = "zstd"
|
||||
)
|
||||
@ -1,4 +1,4 @@
|
||||
package types
|
||||
package memory
|
||||
|
||||
/* Configure guest RAM
|
||||
Note: Some architectures might enforce a specific granularity
|
||||
@ -1,6 +1,8 @@
|
||||
package types
|
||||
package nic
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type (
|
||||
NICType string
|
||||
@ -21,7 +23,14 @@ type TapOptions struct {
|
||||
}
|
||||
|
||||
func (t *TapOptions) ExpandOptions() []string {
|
||||
return []string{"tap," + strings.Join(Expand(t), ",")}
|
||||
opts := []string{}
|
||||
if t.ID != "" {
|
||||
opts = append(opts, "id="+t.ID)
|
||||
}
|
||||
if t.IFName != "" {
|
||||
opts = append(opts, "ifname="+t.IFName)
|
||||
}
|
||||
return []string{"tap," + strings.Join(opts, ",")}
|
||||
}
|
||||
|
||||
type BridgeOptions struct {
|
||||
@ -1,4 +1,4 @@
|
||||
package types
|
||||
package smp
|
||||
|
||||
/*
|
||||
Note: Different machines may have different subsets of the CPU topology
|
||||
33
pkg/v1/types/types.go
Normal file
33
pkg/v1/types/types.go
Normal file
@ -0,0 +1,33 @@
|
||||
package types
|
||||
|
||||
import "fmt"
|
||||
|
||||
type (
|
||||
Flag string
|
||||
)
|
||||
|
||||
var (
|
||||
register = map[string]any{}
|
||||
|
||||
On *bool = func(b bool) *bool {
|
||||
return &b
|
||||
}(true)
|
||||
|
||||
Off *bool = func(b bool) *bool {
|
||||
return &b
|
||||
}(false)
|
||||
|
||||
Set Flag = "flag-on"
|
||||
)
|
||||
|
||||
func GetTypes() map[string]any {
|
||||
return register
|
||||
}
|
||||
|
||||
func RegisterType(t string, i any) error {
|
||||
if _, ok := register[t]; !ok {
|
||||
register[t] = i
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("type already registered")
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package types
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -6,55 +6,18 @@ 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"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/boot"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/nic"
|
||||
"github.com/rayaman/go-qemu/pkg/v1/types/numa"
|
||||
)
|
||||
|
||||
/*
|
||||
TODO:
|
||||
-add-fd fd=fd,set=set[,opaque=opaque]
|
||||
|
||||
Add 'fd' to fd 'set'
|
||||
|
||||
-set group.id.arg=value
|
||||
|
||||
set <arg> parameter for item <id> of type <group>
|
||||
i.e. -set drive.$id.file=/path/to/image
|
||||
|
||||
-global driver.property=value
|
||||
-global driver=driver,property=property,value=value
|
||||
|
||||
set a global default for a driver property
|
||||
*/
|
||||
type Machine struct {
|
||||
Arch System // The binary we use
|
||||
// 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.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"`
|
||||
|
||||
// Block devices
|
||||
HardDiskA string `json:"hda,omitempty"`
|
||||
HardDiskB string `json:"hdb,omitempty"`
|
||||
HardDiskC string `json:"hdc,omitempty"`
|
||||
HardDiskD string `json:"hdd,omitempty"`
|
||||
FloppyA string `json:"fda,omitempty"`
|
||||
FloppyB string `json:"fdb,omitempty"`
|
||||
CDROM string `json:"cdrom,omitempty"`
|
||||
// converts bool to on/off format
|
||||
var SW = map[bool]string{
|
||||
true: "on",
|
||||
false: "off",
|
||||
}
|
||||
|
||||
func remove(s []string, r string) []string {
|
||||
func Remove(s []string, r string) []string {
|
||||
for i, v := range s {
|
||||
if v == r {
|
||||
return append(s[:i], s[i+1:]...)
|
||||
@ -63,35 +26,6 @@ func remove(s []string, r string) []string {
|
||||
return s
|
||||
}
|
||||
|
||||
func (m *Machine) Expand() []string {
|
||||
fields := structs.Fields(m)
|
||||
exp := []string{}
|
||||
for _, field := range fields {
|
||||
tag := strings.ReplaceAll(field.Tag("json"), ",omitempty", "")
|
||||
omit := field.Tag("omit")
|
||||
if tag != "" {
|
||||
if field.Kind() == reflect.Struct || field.Kind() == reflect.Interface && !field.IsZero() {
|
||||
if omit != "" {
|
||||
exp = append(exp, Expand(field.Value())...)
|
||||
} else {
|
||||
exp = append(exp, Expand(field.Value(), tag)...)
|
||||
}
|
||||
} else {
|
||||
if !field.IsZero() {
|
||||
if fmt.Sprintf("%v", field.Value()) == "flag-on" {
|
||||
exp = append(exp, "-"+tag)
|
||||
} else {
|
||||
exp = append(exp, "-"+tag, fmt.Sprintf("%v", field.Value()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exp = remove(exp, "")
|
||||
return exp
|
||||
}
|
||||
|
||||
func Expand(obj any, tag ...string) []string {
|
||||
opts := []string{}
|
||||
fields := structs.Fields(obj)
|
||||
@ -139,7 +73,7 @@ func Expand(obj any, tag ...string) []string {
|
||||
opts = append(opts, "-numa", opt)
|
||||
opts = append(opts, Expand(hmatcache)...)
|
||||
}
|
||||
case Options:
|
||||
case nic.Options:
|
||||
opts = append(opts, value.ExpandOptions()...)
|
||||
case []boot.Drives:
|
||||
if omit == "tag" {
|
||||
Loading…
x
Reference in New Issue
Block a user