From 7384a56b07158d18ae14006250acfc70f8d7c1f7 Mon Sep 17 00:00:00 2001 From: Ryan Ward Date: Fri, 28 Mar 2025 12:03:19 -0400 Subject: [PATCH] resturctured code --- main.go | 45 ++++++---- pkg/image/image.go | 71 --------------- pkg/{ => v1}/image/cmd_create.go | 51 +---------- pkg/v1/image/cmd_load_image.go | 37 ++++++++ pkg/v1/image/cmd_save_image.go | 31 +++++++ pkg/{ => v1}/image/formats/luks.go | 0 pkg/{ => v1}/image/formats/qcow.go | 0 pkg/{ => v1}/image/formats/qcow2.go | 9 +- pkg/{ => v1}/image/formats/qed.go | 0 pkg/{ => v1}/image/formats/raw.go | 5 +- pkg/{ => v1}/image/formats/vdi.go | 0 pkg/{ => v1}/image/formats/vhdx.go | 0 pkg/{ => v1}/image/formats/vmdk.go | 0 pkg/{ => v1}/image/formats/vpc.go | 0 pkg/v1/image/types.go | 17 ++++ pkg/v1/image/utils.go | 50 +++++++++++ pkg/v1/system/machine.go | 90 +++++++++++++++++++ pkg/{ => v1}/system/system.go | 0 pkg/{ => v1}/types/accel/accel.go | 0 pkg/{types/types.go => v1/types/arch/arch.go} | 62 +------------ pkg/{ => v1}/types/boot/boot.go | 0 pkg/{types => v1/types/chip}/chip.go | 2 +- pkg/{types => v1/types/disk}/disk.go | 2 +- pkg/v1/types/image/image.go | 25 ++++++ pkg/{types => v1/types/memory}/memory.go | 2 +- pkg/{types => v1/types/nic}/nic.go | 15 +++- pkg/{ => v1}/types/numa/numa.go | 0 pkg/{types => v1/types/smp}/smp.go | 2 +- pkg/v1/types/types.go | 33 +++++++ .../machine.go => v1/types/utils/utils.go} | 86 +++--------------- 30 files changed, 351 insertions(+), 284 deletions(-) delete mode 100644 pkg/image/image.go rename pkg/{ => v1}/image/cmd_create.go (54%) create mode 100644 pkg/v1/image/cmd_load_image.go create mode 100644 pkg/v1/image/cmd_save_image.go rename pkg/{ => v1}/image/formats/luks.go (100%) rename pkg/{ => v1}/image/formats/qcow.go (100%) rename pkg/{ => v1}/image/formats/qcow2.go (95%) rename pkg/{ => v1}/image/formats/qed.go (100%) rename pkg/{ => v1}/image/formats/raw.go (74%) rename pkg/{ => v1}/image/formats/vdi.go (100%) rename pkg/{ => v1}/image/formats/vhdx.go (100%) rename pkg/{ => v1}/image/formats/vmdk.go (100%) rename pkg/{ => v1}/image/formats/vpc.go (100%) create mode 100644 pkg/v1/image/types.go create mode 100644 pkg/v1/image/utils.go create mode 100644 pkg/v1/system/machine.go rename pkg/{ => v1}/system/system.go (100%) rename pkg/{ => v1}/types/accel/accel.go (100%) rename pkg/{types/types.go => v1/types/arch/arch.go} (61%) rename pkg/{ => v1}/types/boot/boot.go (100%) rename pkg/{types => v1/types/chip}/chip.go (99%) rename pkg/{types => v1/types/disk}/disk.go (97%) create mode 100644 pkg/v1/types/image/image.go rename pkg/{types => v1/types/memory}/memory.go (95%) rename pkg/{types => v1/types/nic}/nic.go (84%) rename pkg/{ => v1}/types/numa/numa.go (100%) rename pkg/{types => v1/types/smp}/smp.go (99%) create mode 100644 pkg/v1/types/types.go rename pkg/{types/machine.go => v1/types/utils/utils.go} (52%) diff --git a/main.go b/main.go index bcbf2a5..1a0ea82 100644 --- a/main.go +++ b/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") diff --git a/pkg/image/image.go b/pkg/image/image.go deleted file mode 100644 index 984c3bf..0000000 --- a/pkg/image/image.go +++ /dev/null @@ -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 -} diff --git a/pkg/image/cmd_create.go b/pkg/v1/image/cmd_create.go similarity index 54% rename from pkg/image/cmd_create.go rename to pkg/v1/image/cmd_create.go index ec8d04c..2f6c93d 100644 --- a/pkg/image/cmd_create.go +++ b/pkg/v1/image/cmd_create.go @@ -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) diff --git a/pkg/v1/image/cmd_load_image.go b/pkg/v1/image/cmd_load_image.go new file mode 100644 index 0000000..cc71e5e --- /dev/null +++ b/pkg/v1/image/cmd_load_image.go @@ -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 +} diff --git a/pkg/v1/image/cmd_save_image.go b/pkg/v1/image/cmd_save_image.go new file mode 100644 index 0000000..91519f4 --- /dev/null +++ b/pkg/v1/image/cmd_save_image.go @@ -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 +} diff --git a/pkg/image/formats/luks.go b/pkg/v1/image/formats/luks.go similarity index 100% rename from pkg/image/formats/luks.go rename to pkg/v1/image/formats/luks.go diff --git a/pkg/image/formats/qcow.go b/pkg/v1/image/formats/qcow.go similarity index 100% rename from pkg/image/formats/qcow.go rename to pkg/v1/image/formats/qcow.go diff --git a/pkg/image/formats/qcow2.go b/pkg/v1/image/formats/qcow2.go similarity index 95% rename from pkg/image/formats/qcow2.go rename to pkg/v1/image/formats/qcow2.go index e781fa0..654bcbb 100644 --- a/pkg/image/formats/qcow2.go +++ b/pkg/v1/image/formats/qcow2.go @@ -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. diff --git a/pkg/image/formats/qed.go b/pkg/v1/image/formats/qed.go similarity index 100% rename from pkg/image/formats/qed.go rename to pkg/v1/image/formats/qed.go diff --git a/pkg/image/formats/raw.go b/pkg/v1/image/formats/raw.go similarity index 74% rename from pkg/image/formats/raw.go rename to pkg/v1/image/formats/raw.go index e2d6f64..0e494fa 100644 --- a/pkg/image/formats/raw.go +++ b/pkg/v1/image/formats/raw.go @@ -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"` } diff --git a/pkg/image/formats/vdi.go b/pkg/v1/image/formats/vdi.go similarity index 100% rename from pkg/image/formats/vdi.go rename to pkg/v1/image/formats/vdi.go diff --git a/pkg/image/formats/vhdx.go b/pkg/v1/image/formats/vhdx.go similarity index 100% rename from pkg/image/formats/vhdx.go rename to pkg/v1/image/formats/vhdx.go diff --git a/pkg/image/formats/vmdk.go b/pkg/v1/image/formats/vmdk.go similarity index 100% rename from pkg/image/formats/vmdk.go rename to pkg/v1/image/formats/vmdk.go diff --git a/pkg/image/formats/vpc.go b/pkg/v1/image/formats/vpc.go similarity index 100% rename from pkg/image/formats/vpc.go rename to pkg/v1/image/formats/vpc.go diff --git a/pkg/v1/image/types.go b/pkg/v1/image/types.go new file mode 100644 index 0000000..bb98d7c --- /dev/null +++ b/pkg/v1/image/types.go @@ -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 + } +) diff --git a/pkg/v1/image/utils.go b/pkg/v1/image/utils.go new file mode 100644 index 0000000..43f7d3a --- /dev/null +++ b/pkg/v1/image/utils.go @@ -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 +} diff --git a/pkg/v1/system/machine.go b/pkg/v1/system/machine.go new file mode 100644 index 0000000..cac6592 --- /dev/null +++ b/pkg/v1/system/machine.go @@ -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 parameter for item of type + 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 +} diff --git a/pkg/system/system.go b/pkg/v1/system/system.go similarity index 100% rename from pkg/system/system.go rename to pkg/v1/system/system.go diff --git a/pkg/types/accel/accel.go b/pkg/v1/types/accel/accel.go similarity index 100% rename from pkg/types/accel/accel.go rename to pkg/v1/types/accel/accel.go diff --git a/pkg/types/types.go b/pkg/v1/types/arch/arch.go similarity index 61% rename from pkg/types/types.go rename to pkg/v1/types/arch/arch.go index f4dbc00..22d9a85 100644 --- a/pkg/types/types.go +++ b/pkg/v1/types/arch/arch.go @@ -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") -} diff --git a/pkg/types/boot/boot.go b/pkg/v1/types/boot/boot.go similarity index 100% rename from pkg/types/boot/boot.go rename to pkg/v1/types/boot/boot.go diff --git a/pkg/types/chip.go b/pkg/v1/types/chip/chip.go similarity index 99% rename from pkg/types/chip.go rename to pkg/v1/types/chip/chip.go index 9a6623b..eb86c17 100644 --- a/pkg/types/chip.go +++ b/pkg/v1/types/chip/chip.go @@ -1,4 +1,4 @@ -package types +package chip type CHIP string diff --git a/pkg/types/disk.go b/pkg/v1/types/disk/disk.go similarity index 97% rename from pkg/types/disk.go rename to pkg/v1/types/disk/disk.go index 7d8dd6f..19dedba 100644 --- a/pkg/types/disk.go +++ b/pkg/v1/types/disk/disk.go @@ -1,4 +1,4 @@ -package types +package disk import ( "math/big" diff --git a/pkg/v1/types/image/image.go b/pkg/v1/types/image/image.go new file mode 100644 index 0000000..6a26ad4 --- /dev/null +++ b/pkg/v1/types/image/image.go @@ -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" +) diff --git a/pkg/types/memory.go b/pkg/v1/types/memory/memory.go similarity index 95% rename from pkg/types/memory.go rename to pkg/v1/types/memory/memory.go index afab088..fd9694a 100644 --- a/pkg/types/memory.go +++ b/pkg/v1/types/memory/memory.go @@ -1,4 +1,4 @@ -package types +package memory /* Configure guest RAM Note: Some architectures might enforce a specific granularity diff --git a/pkg/types/nic.go b/pkg/v1/types/nic/nic.go similarity index 84% rename from pkg/types/nic.go rename to pkg/v1/types/nic/nic.go index 3999ca4..8e5920f 100644 --- a/pkg/types/nic.go +++ b/pkg/v1/types/nic/nic.go @@ -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 { diff --git a/pkg/types/numa/numa.go b/pkg/v1/types/numa/numa.go similarity index 100% rename from pkg/types/numa/numa.go rename to pkg/v1/types/numa/numa.go diff --git a/pkg/types/smp.go b/pkg/v1/types/smp/smp.go similarity index 99% rename from pkg/types/smp.go rename to pkg/v1/types/smp/smp.go index 5c636d7..f20b05a 100644 --- a/pkg/types/smp.go +++ b/pkg/v1/types/smp/smp.go @@ -1,4 +1,4 @@ -package types +package smp /* Note: Different machines may have different subsets of the CPU topology diff --git a/pkg/v1/types/types.go b/pkg/v1/types/types.go new file mode 100644 index 0000000..4d828bb --- /dev/null +++ b/pkg/v1/types/types.go @@ -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") +} diff --git a/pkg/types/machine.go b/pkg/v1/types/utils/utils.go similarity index 52% rename from pkg/types/machine.go rename to pkg/v1/types/utils/utils.go index d94f20f..6f5119c 100644 --- a/pkg/types/machine.go +++ b/pkg/v1/types/utils/utils.go @@ -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 parameter for item of type - 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" {